一天一个知识点 - 浅谈 JavaScript this 问题

243 阅读2分钟

前言

前些日子,在掘金上看到一片热门文章《在酷家乐做面试官的日子》。该文作者以面试官的角度,详细阐述了作为一名 web 应聘者应该具有哪些技能,才会更让人青睐。

在对比自身的过程中,发现有一些问题,或许了解,但不全面,这也是本系列文章诞生的缘由。

this 的定义

在 ECMAScript 这样定义的 this

The this keyword evaluates to the value of the ThisBinding of the current execution context

记住一个原则就好:

this 指向调用它的对象(谁污染,谁治理)。

this 的指向

使用 new 操作符


/*
 * 谁调用 func,this 就是谁
 * 当前运行时,是 obj 实例化了 func,所以 this 指向 obj
 */
function func(){
    console.log(this.obj)
}

var obj = { obj: 'obj', func1 : new func()}

console.log(obj.msg) => hello world 

使用 call、apply、bind

call、apply 和 bind 都会改变函数运行时的上下文。

在示例代码中,this 都指向第一个参数(调用者)


/*
 * TODO:
 * call、apply、bind 后期会有系列文章说明
 */

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

var obj1 = { msg : '1', obj: 'obj1' }
var obj2 = { msg : '2', obj: 'obj1' }
var obj3 = { msg : '3', obj: 'obj1' }

// 直接调用时,调用者是 window,this 指向 window。
func() => Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

// 使用 call、apply 用于改变函数运行时的上下文
// 调用者是当前对象,指向当前对象
func.call(obj1) => {msg: "1", obj: "obj1"}
func.apply(obj2) => {msg: "2", obj: "obj1"}

// bind 和 call、apply 有细微不同, bind 的返回值是函数
func.bind(obj3)() => {msg: "3", obj: "obj1"}

ES6 的箭头函数

ES6 的箭头改变了常规函数的 this 运行时指向。

箭头函数的this,总是指向定义时所在的对象,而不是运行时所在的对象。

让我们改写上个示例的代码,使用箭头函数替换普通的函数声明:


/*
 * 因为箭头函数的 this 总是指向定义时所在的对象,所以在这个示例中,this 都指向 Window 对象
 */
var func = () => {
    console.log(this)
}

var obj1 = { msg : '1', obj: 'obj1' }
var obj2 = { msg : '2', obj: 'obj1' }
var obj3 = { msg : '3', obj: 'obj1' }

func() => Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
func.call(obj1) => Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
func.apply(obj2) => Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
func.bind(obj3)() => Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

总结

  • 非箭头函数,this 总是指向调用他的对象
  • 箭头函数,this 总是指向定义的对象

参考

系列文章