JavaScript难点系列(二):this

来源:互联网 发布:中金智德 知乎 编辑:程序博客网 时间:2024/05/29 19:06

深入了解js这门语言后,才发现它有着诸多众所周知的难点(例如:闭包、原型链、内存空间等)。有的是因为js的设计缺陷导致的,而有的则是js的优点。不管如何,总需要去学会它们,在学习过程中我觉得只看别人的文章并不能做到深刻理解,所以我决定写这一系列的文章来记录我所学习到的知识点,也方便自己以后回顾,如有写错的地方欢迎指正。
废话不多说,马上进入正题!

一、默认绑定

在看过很多种的this解读思路后,我觉得《你不知道的JavaScript(上卷)》中对this的讲解比较有操作性,即有个很明确的标准让你去判断。

默认绑定指的是在没有new绑定和显示绑定(后面会提到)的前提下解析器会运行的绑定逻辑,它的思路是:this是由调用者提供的,每个函数的this取决于函数的调用位置(也就是调用方法)。

具体的判断标准是:如果函数被一个对象所拥有,那么该函数在调用时内部的this指向该对象。如果函数是独立调用(直接不带任何修饰的函数引用进行调用),那么函数内部的this指向undefined(严格模式下)。

// 独立调用function foo() {    console.log(this.a)}var a = 2foo()  // undefined

独立调用中有些情况属于比较隐蔽且容易让人混淆的:

// 隐式丢失(也是属于独立调用的情况)function foo() {    console.log(this.a)}var obj = {    a: 2,    foo: foo}var bar = obj.foo  // bar引用的是foo函数本身,即相当于bar=foovar a = "global"bar()  // undefined // 这里和上面的foo()独立调用同理
// 回调中的独立调用var a = 20;function foo () {  console.log(this.a)}var obj = {  a: 2,  foo: foo}function doFoo (fn) {  fn() // 相当于在此处直接调用foo()}doFoo(obj.foo)
// 被某个对象拥有function foo() {    console.log(this.a)}var obj = {    a: 2,    foo: foo}obj.foo();  // 2
// 如果被多个对象调用,this绑定到离函数调用最近的对象function foo() {    console.log(this.a)}var obj2 = {    a: 42,    foo: foo}var obj1 = {    a: 2,    obj2: obj2}obj1.obj2.foo()  // 42// 离foo()最近的是obj2,所以this绑定到obj2

二、显式绑定

显式绑定是指使用函数的call()、apply()和bind()方法强制地让函数的this绑定到我们想要的对象。显式绑定的优先级比默认绑定优先级高,即如果有显式绑定出现,默认绑定的规则失效。

// call()和apply()方法的第一个参数是一样的,都是this的绑定对象。function foo() {    console.log(this.a)}var obj = {    a: 42}foo.call(obj)  // 42foo.apply(obj)  // 42
// bind()方法会返回一个新函数,新函数内部的this绑定到bind()方法的第一个参数var obj = {    a: 2,    foo: function() { return this.a }}var bar = obj.foobar()  // undefinedvar new_bar = bar.bind(obj)new_bar()  // 2

三、new绑定

new绑定是优先级最高的。使用new来调用函数时,会创建一个全新的对象,并把函数的this绑定到新对象上。

function foo(a) {    this.a = a}var bar = new foo(2)console.log(bar.a)  // 2

四、ES6箭头函数

ES6的最好用的新特性之一就是箭头函数了。箭头函数中的this和我们上述说的规则都没有关系,它是根据箭头函数的外层作用域来决定this(JS中只有函数作用域和全局作用域)

function foo() {    setTimeout(() => {        // 这里的this继承自外层作用域的this,即foo的this        console.log(this.a)      }, 100)}var obj = {    a: 2}foo.call(obj)  // 2

五、总结

以上三种绑定规则的优先级是:new绑定 > 显式绑定 > 默认绑定。所以我们在判断this时,只要按照优先级来一步一步判断就没有问题了。

原创粉丝点击