乐趣区

关于javascript:拾遗记4this指向

JavaScript 中 this 的指向取决于 function 被谁调用,而不取决于其定义。

示例一

function fn() {console.log(this)
}
fn()

上例中,fn 是被全局对象调用,所以 this 指向全局对象。

示例二

const obj = {foo: function () {console.log(this)
    }
}
let fn = obj.foo
fn()
obj.foo()

上例中,fn 办法指向 obj.foo,因为 fn 办法被全局对象调用,因而 this 指向全局对象。而间接调用obj.foo(),此时 foo 办法被 obj 调用,因而 this 指向 obj。

示例三

function Foo() {console.log(this)
}
const f = new Foo()

上例中,Function Foo 被当作构造函数进行了实力化,此时 this 指向实力化对象 f。
ES2015 中的 class 关键字是一种语法糖,其本质还是申明一个构造函数,因而其外部 this 指向可参考构造函数。

示例四

function foo() {return () => {console.log(this)
    }
}
foo()()

箭头函数尽管也是一种函数,然而其不扭转外部 this 指向,也就是说在查找箭头函数外部 this 指向时,查找的仍然是包裹它的 function 的调用者。在上例中,foo 函数返回的函数是被全局对象调用,因而 this 指向全局对象。

基于下面的四个例子,能够总结出在 JavaScript 中查找 this 的步骤为:

  • 沿着作用域链由外向外查找查找最近的 function(箭头函数不是 function),看这个 function 最终被谁调用。
  1. 被全局对象调用(作为函数调用),如foo(), this 指向全局对象。
  2. 被其余对象调用(作为办法调用),如foo.bar(),this 指向最终调用这个办法的对象。
  3. 被当作结构函数调用,如new Person,this 指向新生成的实力化对象。
  4. 非凡调用,如fn.call, fn.apply, fn.bind,此时 this 指向调用时传入的参数。
  • 如果找不到 function,this 就指向全局对象。

this 指向的全局对象是什么?

在下面提到很屡次 this 指向全局对象,那这个全局对象到底是什么?

浏览器环境下

  • 非严格模式下,全局对象为 window。
  • 严格模式下,全局对象为 undefined。

node 环境下

如果在命令行中通过 node *.js 执行时,分为上面两种状况。

  • 如果 this 没有在任何函数作用域中
if (true) {console.log(this)
}
console.log(this)
// true
console.log(this === module.exports)

在上例中,this 指向 {}。
因为 nodejs 为保障文件的模块作用域,在执行文件代码时,会为所有的文件代码增加一个包裹函数,下面的执行相似于:

// exports 指向 module.exports
function wrapped(exports) {if (true) {console.log(this)
    }
    console.log(this)
}
wrapped()

因而 this 会指向{}。

  • 如果 this 处在函数作用域中,this 指向调用者。
function fn() {console.log(this)
}
fn()

在上例中,fn 是全局对象调用,而 node 环境中,全局对象是 Global,因而 this 指向 Global。

退出移动版