作用域链与原型链
作用域链
每一个代码在调用时,都会产生一个执行上下文。
执行上下文的具体内容:
每一个函数(例如f)执行上下文由两部分组成:
1. f内部定义的变量,arguments,内部定义的函数
2. 函数f的父级函数的执行上下文
父级函数:在定义f时,把直接f包起来的那个函数。如果f外层没有函数,则父级函数就理解为全局代码。
我们把执行的代码分为两类:一类是全局代码,一类是函数代码。
全局代码只会有一个,而函数代码可以有很多个。执行一个函数代码就会产生一个函数执行上下文;执行全局代码就会产生一个全局执行上下文
全局执行上下文只有一个,函数执行上下文会有多个。每一次执行函数,就会产生一个函数执行上下文。例如,一个函数f,被调用了10次,就会产生10个执行上下文。
执行上下文的作用:函数(代码)在执行的过程中,需要的一切数据都由执行上下文来提供。数据包含:变量,函数。
在查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链就叫做作用域链。
原型链
- 每个函数,都会有很多属性(因为函数也是对象,而对象是属性的集合),其中一定有一个prototype属性。这个属性的值是一个对象。prototype是key,它的value是对象,这个对象叫原型对象,它指向的是函数内部可被继承的一块隐藏空间,任何通过这个函数创建的实例都可访问到这块空间。我们学到的许多方法都是存在于这块空间里的。
函数的prototype属性是一个对象,这个对象中有很多方法(根据函数的不同,可能方法也不同),但是一定有一个方法:constructor。这个constructor指向这个函数本身。也就是说:
(f是一个函数)
console.log(f.prototype.constructor == f) // true
-
每一个对象,都有一个__proto__属性。它对应的值也是一个对象。对于函数而言,每一个函数都会有一个prototype和一个__ proto__ 属性。对象的 __proto__属性指向创建这个对象的函数的prototype。
let obj = {name:"wangcai"} // 通过Object创建 console.log(obj.__proto__ == Object.prototype) // true
为了方便理解这三个属性,可以参考下图

访问一个对象的属性时,会先在这个对象自己的属性中去找,如果找不到,则沿着__proto__这个属性去原型中找,如果__proto__这个对象中还是没有找到,就在__proto__对象的__proto__属性中去找,依次下去,这就是原型链。