执行上下文以及作用域链
执行上下文
邓哥会跑步,这叫函数定义,表达的是邓哥可以做这件事
邓哥现在去跑步,这叫函数调用,表达的是邓哥现在就去做这件事
做一件事需要一些准备工作,比如邓哥跑步需要准备:
- 蓝猫运动服
- 奥特曼运动鞋
- 海绵宝宝同款毛巾
- 北冰洋汽水
之所以要准备这些东西,是因为他在做这件事的过程中,可能会用到它们
在函数调用时也是一样,在函数真正开始运行之前,浏览器需要开辟一块内存空间,在这块内存中放置一些关键“物品”,函数运行过程中可以随时使用这些“物品”
这个“物品”,就是执行上下文(Execution Context,简称EC)

在执行上下文中,我们目前仅需关心其中一件“物品”——AO(Activation Object),称之为活动对象
在调用函数时,会先往AO里面放一些东西,放完后再执行函数

AO具体的创建顺序为:
确定参数
同时确定arguments
提取函数声明
若遇到同名问题,覆盖
提取变量声明
值为undefined。若遇到同名问题,忽略。
可以将全局的代码看做是一次特殊的函数调用,它产生的执行上下文称之为全局上下文
全局上下文在最开始就会被创建
作用域链
作用域链,其实就是EC形成的链条。当函数定义时,这个链条就会产生
运行函数时,若需要的东西不在当前的EC中,则从函数绑定的作用域链中依次寻找

要特别注意的是:
- 查找作用域链是,由近到远查询,找到了就停止查找
- 作用域链在函数定义时产生
作用域链和闭包有什么关系?
闭包不是一个技术,而是一种现象,是指在定义函数时,周围环境中的信息可以在函数中使用。作用域链是实现闭包的手段。
原型链
什么是原型
function User(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
this.fullName = firstName + ' ' + lastName;
}
User.prototype.sayHi = function(){
console.log('你好,我是' + this.fullName);
}
User.prototype.sayHiEN = function(){
console.log('hello, my name is ' + this.fullName);
}
var u1 = new User('邓', '旭明');
u1.sayHi(); // 你好,我是邓旭明
var u2 = new User('莫', '妮卡');
u2.sayHiEN(); // hello, my name is 莫妮卡上面这段代码发生了什么?prototype是什么东西?new User又是什么东西?为什么u1 u2可以调用sayHi和sayHiEN方法?
一图胜千言

从上图中可以看出:
- 每个函数都有一个原型对象
- 原型对象上的成员被所有实例共享
什么是原型链
所有的对象都是通过new 函数的方式创建的
var u1 = new User('邓', '旭明'); // 对象 u1 通过 new User 创建
var u2 = { // 对象 u2 通过 new Object 创建
firstName: '莫',
lastName: '妮卡'
}
// 等效于
var u2 = new Object();
u2.firstName = '莫';
u2.lastName = '妮卡';上面的代码形成的原型图如下

原型对象本身也是一个对象,默认情况下,是通过new Object创建的,因此,上面的两幅原型图是可以发生关联的

Object.prototype.__proto__比较特殊,它固定指向null
可以看出,u1的隐式原型形成了一个链条,称之为原型链
当读取对象成员时,会先看对象自身是否有该成员,如果没有,就依次在其原型链上查找
完整的链条

instanceof
a instanceof b,b必须是一个函数,检查a的原型链上是否存在b的原型
this指向
函数中的this只能在函数调用时才能确定!只能,只能,只能,重要的事说三遍

注意点:
- 使用bind时,得到的新函数无法通过其他方式再次修改this,但
new则例外。 - 如果函数是非严格模式,使用
call apply bind时,传入null或undefined,相当于传入全局对象
小知识
我们在代码中使用的this,其实就是执行上下文中的this
由于执行上下文只能在函数调用时创建,所以,this只能在函数调用时确定
箭头函数
箭头函数是ES6提供的一种简洁的函数定义语法,所有可以使用函数表达式的地方都可以使用箭头函数。
var sum = function(a, b){
return a + b;
}
// 箭头函数格式
var sum = (a, b) => {
return a + b;
}箭头函数有着一个重要的特征:箭头函数中没有this和arguments,是真的没有!
所以,箭头函数中使用的this,是作用域链上的this
