this 的两个误解
- this 指向函数自身?
1 |
|
- this 指向函数的作用域?
1 |
|
this 是在运行时绑定的,并不是在编写时绑定的,它的上下文取决于函数调用时的各种条件,this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息,this 就是这个记录的一个属性,会在函数执行的过程中用到。
this 的绑定规则
默认绑定
无法应用其他规则时的默认规则
1 |
|
上面的例子中,this 指向的是全局对象,而 a 是声明在全局作用域中的变量,于是 this.a 即打印了变量 a 的值。当 foo()运行在严格模式下时,默认绑定不能绑定全局对象,打印结果会是 undefined
隐式绑定
调用位置是否有上下文对象,或者是否被某个对象'拥有'或者'包含'。
1 |
|
上例中调用位置使用 obj 上下文来引用函数,可以看成函数被调用时它就属于了 obj 对象。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。
隐式丢失
1 |
|
同样,在将函数作为参数传递时也会发生赋值,只不过这是一种隐式赋值。
1 |
|
显示绑定
不在对象内部包含函数引用,而是在某个对象上强制调用函数,函数的 call()和 apply()方法,bind()方法
call()和 apply()的第一个参数是用来绑定 this 的,可以直接指定 this 的绑定对象。如果传入的是一个非对象类型,比如字符串或者数字,会被转化成它的对象形式(new String()、new Number())。
1 |
|
apply()和 call()作用完全一样,只是接受参数的方式不一样
1 |
|
硬绑定
1 |
|
在上面的例子里,无论如何调用 bar 函数,它都会永远会返回 foo 被绑定后的结果,这种显示的强制绑定为硬绑定。
bind()函数就是为了方便硬绑定而出现的函数
1 |
|
bind()会返回一个硬编码的新函数--它会把你指定的参数设置为 this 的上下文并调用原始函数
API 调用的'上下文'
第三方库的一些函数,JavaScript 语言和宿主环境中许多新的内置函数都提供一个可选的参数,通常被称为上下文(context),其作用和 bind()一样,确保调用函数使用指定的 this
1 |
|
forEach 的第二个参数,绑定回调时函数的 this 值
- new 绑定
JavaScript 里的构造函数:
构造函数只是一些使用 new 操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上,它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已,这种函数调用被称为构造函数调用。
实际上并不存在所谓的‘构造函数’,只有对于函数的‘构造调用’
使用 new 来调用函数会自动执行下面的操作:
- 创建一个全新的对象
- 这个新对象会被执行[Prototype]连接
- 这个新对象会绑定到函数调用的 this
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象
1 |
|