前端面试--JS

前端面试–JS

Q:JS数据类型
JS简单数据类型:String、Number、Boolean、Null、undefined、Symbol。复杂数据类型Object、Array、Function。

Q:null和undefined的区别
(1)null是一个表示”无”的对象,转我数值是为0,undefined是一个表示”无”的原始值,转为数值时为NaN。当声明的变量还未被初始化时,能量的默认值为undefined
(2)Null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象
(3)Undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。典型用法是:
a、变量被声明了,但没有赋值时,就等于undefined
b、调用函数时,应该提供的参数没有提供,该参数等于undefined
c、对象没有赋值属性,该属性的值为undefined
d、函数没有返回值时,默认返回undefined
(4)null表示”没有对象”,即该处不应该有值。典型用法是:
 a、作为函数的参数,表示该函数的参数不是对象
 b、作为对象原型链的终点

Q:拖拽涉及的事件
拖拽事件

Q:垃圾回收
什么是垃圾回收
JS垃圾回收机制的目的是为了防止内存泄漏,内存泄漏是指有一些已经不被需要的变量但仍然存在在内存中,这样便会造成内存泄漏。垃圾回收机制就是为了回收这些不被需要的变量,并且释放掉他们所指向的内存。
JS垃圾回收的方法
①标记清除
这是最常见的回收方法,也是大部分浏览器使用的回收方法。
当变量进入执行环境是,就会被标记上“进入环境”,从逻辑上讲,被标记上“进入环境”的变量所指向的内存是永远不会被回收的。当某个变量离开执行环境时,就会被标上“离开环境”。被标记为“离开环境”的变量则是可以回收的。
②引用计数
这是一种不太常见的回收方式。引用计数法就是同级引用类型声明后被引用的次数,当次数为0时,该变量就会被回收。
有可能造成内存泄漏的案例
①全局变量造成的内存泄漏
②未销毁的定时器和回调函数造成的内存泄漏
③DOM引用造成的内存泄漏
https://www.cnblogs.com/pingzi-wq/p/11531185.html

Q:原型链
因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。

Q:JS定时器
setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。
setTimeout() :在指定的毫秒数后调用函数或计算表达式。

Q:数组和对象内置方法
数组内置方法
constructor 所建立对象的函数参考
prototype 能够为对象加入的属性和方法
Array.concat( ) 连接数组
Array.join( ) 将数组元素连接起来以构建一个字符串
Array.length 数组的大小
Array.pop( ) 删除并返回数组的最后一个元素
Array.push( ) 给数组添加元素
Array.reverse( ) 颠倒数组中元素的顺序
Array.shift( ) 将元素移出数组
Array.slice( ) 返回数组的一部分
Array.sort( ) 对数组元素进行排序
Array.splice( ) 插入、删除或替换数组的元素
Array.toLocaleString( ) 把数组转换成局部字符串
Array.toString( ) 将数组转换成一个字符串
Array.unshift( ) 在数组头部插入一个元素
对象内置方法
属性
constructor
prototype
实例方法
1、toString()返回当前对象的字符串形式,返回值为String类型。
2、toLocaleString()返回当前对象的"本地化"字符串形式,以便于当前环境的用户辨识和使用,返回值为String类型。
3、valueOf()返回指定对象的原始值。
静态方法
1.Object.assign(target, …sources)
功能:把一个或多个源对象的可枚举、自有属性值复制到目标对象中,返回值为目标对象。
2、Object.create(proto [,propertiesObject])
功能:创建一个对象,其原型为prototype,同时可添加多个属性。
3、Object.defineProperty(obj, prop, descriptor)
功能:在一个对象上定义一个新属性或修改一个现有属性,并返回该对象。
4、Object.defineProperties(obj, props)
功能:在一个对象上定义一个或多个新属性或修改现有属性,并返回该对象。
8、Object.getOwnPropertyNames(obj)
功能:获取目标对象上的全部自有属性名(包括不可枚举属性)组成的数组。
9.Object.getPrototypeOf(obj)
功能:获取指定对象的原型,即目标对象的prototype属性的值。
11、Object.keys(obj)
功能:获取目标对象上所有可枚举属性组成的数组。

Q:for in和for of的区别
a. for in 便历出来的是属性
b. for of 遍历的是value
c. 手动给对象添加属性后, for in 是可以将新添加的属性遍历出来 但是for of 不行
d. for in 的属性是使用[] 不可以使用 “.” eg: data[‘index’] instead of data.index

Q:继承的方式
1.原型链继承
2.借用构造函数(经典继承) 复制父类构造函数内的属性
call继承是在子类中把父类当做普通的函数去执行,让父类的this指向子类的实例,相当于给子类设置了很多私有的属性和方法。
3.组合继承
组合原型链继承和借用构造函数继承
背后的思路是:使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。
4.寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。
可以理解为在原型式继承的基础上新增一些函数或属性。
5.寄生组合式继承
子类构造函数复制父类的自身属性和方法,子类原型只接收父类的原型属性和方法。
https://www.jianshu.com/p/85899e287694

Q:数据类型检测
第一种:typeof可以检测一些基本的数据类型
第二种:valueof可以看到数据最本质内容(原始值)
第三种:instanceof检测当前实例是否隶属于某各类
双目运算符 a instanceof b 判断a的构造器是否为b,返回值是布尔值
第四种:isArray判断是否为数组,isNaN()判断是否为NaN
第五种:Object.prototype.toString
语法 Object.prototype.toString.call([value])
获取Object.prototype上的toString方法,让方法的this变为需要检测的数据类型值,并在Number、String、Array、Function…这些类的原型上都有一个toString方法:这个方法就是把本身的值转换为字符串

Q:怎么改变this指向
call、apply、bind
共同点:call和apply第一个参数都为改变this的指针,若为null/undefined,默认指向window
不同点:①call、apply可以自动执行,bind需手动调用
②call、bind都有无数个参数,apply只有两个参数,而且第二个参数为数组

Q:判断this指向
按照this指针的优先级,列出下面常会遇到的四种情况,从上到下依次是优先级从高到低(后面会详细比较优先级)。
1.函数是和new一起被调用的吗(new绑定)?如果是,this就是新构建的对象。
var bar = new foo()
2.函数是用call或apply被调用(明确绑定),甚至是隐藏在bind 硬绑定 之中吗?如果是,this就是明确指定的对象。
var bar = foo.call( obj2 )
3.函数是用环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,this就是那个环境对象。
var bar = obj1.foo()
4.否则,使用默认的this(默认绑定)。如果在strict mode下,就是undefined,否则是global对象。 var bar = foo()

Q:设计模式
(不全)
js设计模式有:单例,工厂,观察者等。
单例模式:保证一个类只有一个实例。实现方法:判断实际是否存在,不存在,创建实际,存在直接返回。
观察者模式:当改变一个对象会同时改变其他对象时,应该使用观察者模式。观察者模式主要作用是解耦。
工厂模式:通过对产品类的抽象使其创建业务主要负责用于创建多类产品实例。

Q:new实现
new的实现原理
• 以构造器的prototype属性为原型,创建新对象;
• 将this(也就是上一句中的新对象)和调用参数传给构造器,执行;
• 如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象。
通过new创建对象经历4个步骤
1、创建一个新对象;[var o = {};]
2、将构造函数的作用域赋给新对象(因此this指向了这个新对象);[Person.apply(o)] [Person原来的this指向的是window]
3、执行构造函数中的代码(为这个新对象添加属性);
4、返回新对象。
https://blog.csdn.net/weixin_47047317/article/details/107567674

Q:防抖、节流
防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
防抖和节流都是为了限制事件的执行次数,防止出现事件的响应速度跟不上触发的速度,导致出现卡顿延迟的现象。

Q:哪些操作会造成内存泄漏
1.意外的全局变量
2.被遗忘的计时器或回调函数
3.脱离 DOM 的引用
4.闭包
第一种情况是我们由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
第二种情况是我们设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留
在内存中,而无法被回收。
第三种情况是我们获取一个 DOM 元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回收。
第四种情况是不合理的使用闭包,从而导致某些变量一直被留在内存当中。

Q:event loop
事件循环机制
JavaScript是一门单线程非阻塞的脚本语言,单线程意味着,JavaScript代码在执行的任何时候,都只有一个主线程来处理所有的任务。而非阻塞则是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如I/O事件)的时候,主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。
在异步函数中,可以细分为两种任务,宏任务与微任务。
宏任务有以下几种:
①I/O
②setTimeout
③setInterval
④setImmediate
⑤requestAnimationFrame
微任务有以下几种:
①process.nextTick
②MutationObserver
③Promise.then catch finally
js执行顺序: 同步函数 -> 微任务 -> 宏任务

async function async1() {
console.log(‘async1 start’);
await async2();
console.log(‘async1 end’);
}
async function async2() {
console.log(‘async2’);
}
console.log(‘script start’);
setTimeout(function() {
console.log(‘setTimeout’);
}, 0)
async1();
new Promise(function(resolve) {
console.log(‘promise1’);
resolve();
}).then(function() {
console.log(‘promise2’);
});
console.log(‘script end’);
/*输出结果:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/

Q:promise
(还需了解使用与实现、并行执行与顺序执行)
原理
在Promise的内部,有一个状态管理器的存在,有三种状态:pending、fulfilled、rejected。
(1) promise 对象初始化状态为 pending。
(2) 当调用resolve(成功),会由pending => fulfilled。
(3) 当调用reject(失败),会由pending => rejected

Q:闭包
闭包概念
能够读取其他函数内部变量的函数。或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。
闭包用途
1、读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。
3、方便调用上下文的局部变量。利于代码封装。
原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后被自动清除。
https://www.cnblogs.com/Renyi-Fan/p/11590231.html

Q:垃圾回收和内存泄露
垃圾回收
Javascript具有周期性的自动垃圾收集机制,执行环境会负责管理代码运行过程中使用的内存。
1.标记清除(mark-and-sweep)。常用的垃圾收集方式。当变量进入环境,就将这个变量标记为“进入环境”。离开环境就标记“离开环境”。
工作流程:
1)垃圾收集器在运行时给内存中的所有变量加上标记。
2)去掉环境中的变量和被环境中的变量引用的变量标记。
3)后来再加上的变量会被视为准备删除的变量。
4)销毁带标记的值并回收他们所占用的空间。
2.引用计数:
不太常用的垃圾收集策略(reference counting)。意为:跟踪记录每个值被引用的次数。
工作流程:
1)声明一个变量并将一个引用类型值赋给该变量,则这个值的引用次数为1。
2)同一个值若再次赋给另一个变量,则改值引用次数加1。
3)包含对这个值引用的变量又取得了另一个值,引用次数减1。
4)当引用次数变为0,则无法在访问这个值,就可以将其占用的内存回收回来。
5)垃圾回收器下次再运行时,释放引用次数为零的值被占用的内存。
内存泄露
对内存使用不当的话会造成内存泄露。以下这几种情况会造成内存的泄漏:
1.意外的全局变量引起的内存泄漏。
原因:全局变量,不会被回收。
解决:使用严格模式避免。
2.闭包引起的内存泄漏
原因:闭包可以维持函数内局部变量,使其得不到释放。
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
3.没有清理的DOM元素引用
原因:虽然别的地方删除了,但是对象中还存在对dom的引用
解决:手动删除。
4.被遗忘的定时器或者回调
原因:定时器中有dom的引用,即使dom删除了,但是定时器还在,所以内存中还是有这个dom。
解决:手动删除定时器和dom。
5.子元素存在引用引起的内存泄漏
原因:div中的ul li 得到这个div,会间接引用某个得到的li,那么此时因为div间接引用li,即使li被清空,也还是在内存中,并且只要li不被删除,他的父元素都不会被删除。
解决:手动删除清空。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值