【手把手带你拿下作用域/原型/闭包相关知识点】

84 阅读2分钟

作用域/作用域链

作用域:顾名思义,就是当前创建变量产生的范围。浏览器引擎能够在当前作用域或嵌套作用域中根据变量名查找到相应的变量。

作用域链:当寻找一个变量的时候,如果在当前作用域没有找到,那么js会向上级作用域一层层的进行查找,这个过程就是作用域链。

作用域分为:
1.全局作用域 挂载在window对象下的,可以在任何地方都能访问到
2.函数作用域 函数内部才能访问 函数执行完 局部变量也会被销毁
3.块级作用域(ES6let const 可以产生该作用域) 由{}包裹的

原型/原型链

原型 简而言之 可以理解为对象的父级 每个js对象中都包含一个_proto_指向对象的原型(父辈)

原型链 是由原型对象组成的 当我们需要在对象中查找一个属性时,如果在当前对象中不存在,就会沿着原型链一层一层往上找,最终到最顶级原型对象Object.prototype

     一些公式。。。
-   `实例.__proto__ === 原型`
-   `原型.constructor === 构造函数`
-   `构造函数.prototype === 原型`
    获取原型的方法
-   `w.proto`
-   `w.constructor.prototype`
-   `Object.getPrototypeOf(w)`

闭包

闭包:当前环境中存在父级作用域的引用 / 常见: 一个函数包裹另一个函数

1.闭包保留了变量对象的引用 即使函数执行完 变量对象仍然会保存在内存中 
2.在函数外部能够访问到函数内部的变量 

高频面试题
for(var i = 1; i <= 5; i ++){
  setTimeout(function() {
    console.log(i)
  }, 0)
}
该输出为6 6 6 6 6 (56) 为什么?

1.js是单线程事件循环机制 同步任务结束之后才会去执行宏任务 
所以这里循环结束之后才会执行setTimeout的回调,setTimeout是宏任务。 

2.setTimeout也是一种闭包,找到它的父级作用域就是window,所以在执行setTimeout之前,
循环结束后在window上的变量i已经变成了6

这里如何输出1 2 3 4 5 呢?
1.利用let 
for(let i = 1; i <= 5; i++){
  setTimeout(function() {
    console.log(i);
  },0)
}
2.立即执行函数IIFE
for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}
3.利用setTimeout的第三个参数
for(var i=1;i<=5;i++){
  setTimeout(function(j) {
    console.log(j)
  }, 0, i)
}