1.call apply bind区别
共同点:都可以修改this,第一个参数都是
修改的this
不同点
- 传参方式不同:
- call是
逐一传参
,apply是数组/伪数组
传参;call,apply是一次性传入,bind分为多次传入(参数1,参数2…) - 函数名.call(修改的this,参数1,参数2…)
- 函数名.apply(修改的this,数组/伪数组)
- 传入
第一个参数
为null,undefined,this指向window
- 执行机制不同:
- call和apply会
立即执行函数
,临时
改变this一次;bind不会立即执行,bind会得到一个永久
改变this指向的新函数
2.typeof和instanceof区别
- 使用 typeof 可以检测数据类型是基本数据类型还是引用数据类型,typeof null 返回的一个 object,是 js 中的 bug,他不是一个引用数据类型.现在 null 被认为是对象的占位符 技术上来说他仍然是个原始值 被 ECMAScript 沿用
- instanceof 是检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
typeof
与instanceof
都是判断数据类型的方法,区别如下:
typeof
会返回一个变量的基本类型,instanceof
返回的是一个布尔值instanceof
可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型- 而
typeof
也存在弊端,它虽然可以判断基础数据类型(null
除外),但是引用数据类型中,除了function
类型以外,其他的也无法判断
可以看到,上述两种方法都有弊端,并不能满足所有场景的需求
如果需要通用检测数据类型,可以采用Object.prototype.toString
,调用该方法,统一返回格式“[object Xxx]”
的字符串
3.事件委托
事件委托
就是给父元素注册事件,利用事件冒泡的原理委托子元素处理,冒泡到父元素身上触发父元素事件
优点
:减少注册事件,提高程序的性能
4.new关键字做了哪些事情?
- 创建新对象
- 构造函数this指向新对象
- 执行构造函数代码,修改this,添加新的属性
- 返回新对象
5.防抖和节流的异同点
-
相同点:都是减少事件触发的次数,从而提高网页的性能
-
不同点:场景不同
- 防抖:减少用户主动触发的事件(输入框输入,鼠标移入事件)
- 节流:事件本身高频触发(滚动事件,鼠标移动事件)
函数防抖:单位时间内,频繁触发事件,以最后一次为准(京东搜索框)
函数节流:单位时间内,频繁触发事件,只会执行一次(滚动事件)
6.ES6 里 let 和 var 的区别
var
使用var声明的变量存在变量提升
在函数中使用var声明变量的时候,该变量是局部
的
在函数内不
使用var,该变量是全局
的
1.块级作用域
var
不存在块级作用域
let
const
不存在变量提升,存在块级作用域
2.重复声明
var
允许重复声明变量
let
和const
在同一作用域不允许重复声明变量
3.修改声明的变量
var
和let
可以
const
声明一个只读的常量。一旦声明,常量的值就不能改变
4.使用
能用const
的情况尽量使用const
,其他情况下大多数使用let
,避免使用var
7. ===
和==
的区别
==:比较两边的值是否相等
===:比较等号两边的值和数据类型是否相等
相等操作符(==)会做类型转换,再进行值的比较,全等运算符不会做类型转换
null
和 undefined
比较,相等操作符(==)为true
,全等为false
8. null 和 undefined 的区别
null:空对象
undefined:未定义
null经过数字转换是0
undefined经过数字转换是Nan
9.原型链
作用域就是起作用的一个区域
作用域链:遵守一个就近原则,当使用一个变量的时候,会在当前作用域下寻找这个变量,如果没有找到,就去它上层作用域查找,直到找到这个变量或查
找到全局作用域,如果全局找不到这个变量的话,会报错.
10.闭包
闭包就是内层函数访问外层函数的变量就会形成闭包
作用:扩展变量的作用范围,封闭数据,防止变量污染
缺点:容易造成内存泄漏,占据内存
解决方案:在用完这个变量之后,给这个变量赋值为 null,利用 js 垃圾回收机制自动回收
内存泄漏一般是指变量的内存没有及时的回收,导致内存资源浪费。一般有三种情况出现内存泄露比较多。(1)常见的声明了一个全局变量,但是又没有用上,那么就有点浪费内存了,(2)定时器没清除 (3)循环引用:A 对象里面有一个属性指向 B 对象,B 对象有一个属性指向 A 对象。互相引用
解决内存泄露:我们编译器有一个自动的内存清理。常见的主要是引用记数 和 标记清除。 谷歌浏览器主要是用标记清除,大概流程是给每一个变量添加一个标记,通过内部算法计算引用情况,当不使用的时候就会自动清除。如果遇到定时器的话,我一般会在页面关闭的时候手动清除。如果遇到循环引用,我一般会手动把变量赋值为 null 来清除
11.浅拷贝与深拷贝
浅拷贝:拷贝基本数据类型
为他的值
,拷贝引用数据
类型为地址
,生成新的数据,修改新的数据会影响原数据,实际开发常用的方法有:object.assgin,扩展运算符等等
深拷贝:在内存中开辟一个新的栈空间
保存新的数据,修改新数据不会影响到原数据,开发中常用的方法有:loadsh 中的_.cloneDeep()方法,JSON.stringify()
12.for in与for of区别
- 功能不同:forin 是遍历数组下标,forof 是遍历数组元素
- 原型属性不同:forin 会遍历原型的元素 ,forof 不会遍历原型的元素
- 数据类型不同:forin 可以遍历 object 类型,forof 不可以遍历 object 类型
13.对原型的理解
在js中,原型是一个对象,通过原型可以实现对象的属性继承,函数对象都包含了Prototype内部属性,这个属性对应的是函数对象的构造函数,作为内部属性,prototype是不能被直接访问到的.为了方便查看一个对象的原型,火狐和谷歌内核的js引擎提供了一个叫proto的非标准的访问器.
14.原型链
当访问对象的某个属性时,会在当前对象属性进行查找,如果查找不到,就回去该对象的__proto__原型上查找(构造函数的prototype属性查找),如果还没有查找到,就会查找他的object对象原型上查找,一层层向上查找形成原型链.
作用:面向对象继承
对象访问原则:就近原则
15.this指向
- 以函数形式调用时,this---->window
- 以方法形式调用时,this---->调用方法的对象(例:obj.say())
- 在构造函数内,this 指向实例化对象
- 箭头函数内,没有 this 指向,它会去他的上一层寻找 this 指向
- 定时器中this—>window
- 使用call,apply调用时,this指向那个对象
16.谈谈对Promise的理解?
promise是ES6新增的一个构造函数,promise主要是用来解决开发中的回调地狱问题
。
它的工作流程是
:当我们创建promise
的时候,它就会立即执行里面的异步代码,此时它的状态是进行中
,然后剩下两种状态是由异步本身决定的,分别对应的是异步操作的成功和失败,当成功或失败之后,promise的状态就会发生改变,从进行中到成功或者从进行中到失败,这时候就会分别调用它的resolve()和reject()方法来处理异步的结果,resolve()
就会执行promise实例的then
方法,reject
就会执行promise实例的catch()
方法,这就是整个流程。
promise本身并没有改变异步的顺序, 而是通过操作异步结果的顺序从而
间接
控制异步的顺序
17.promise是怎么解决回调地狱问题的?
promise是通过在上一个promise实例的then方法里面返回下一个promise实例,形成then的链式调用来解决异步回调地狱问题的。
18.异步函数是怎么用的?
用async关键字来修饰function函数,修饰的作用是为了在函数内部使用await关键字,然后用await来调用一个函数,那么await得到的结果就是就是这个函数then里面的res。
19.事件循环
事件循环
(Event Loop)是js编译器解析与执行
代码的一种规则.
js代码分为两大类:
(1)同步
(2)异步分为两种:
- 异步宏:script标签 、事件处理函数、定时器回调、ajax回调
- 异步微:promise.then()、await/async
-
事件循环规则:
(1)先
解析
默认script标签,进入第一个
宏任务(默认宏)(2)
判断
代码是同步还是异步(3)如果是同步,立即
执行
(4)如果是异步:微任务放入微队列,宏任务放入宏队列
(5)当前同步执行完毕之后,开始执行异步队列
(6)
先清空微任务
队列,之后再解析宏任务
队列,此时完成一次事件循环(7)按照以上步骤
反复解析执行
每一个宏任务(事件循环就是按照相同的规则反复循环解析执行代码)