JavaScript中的this

引子

本文是看完《你不知道的js》这本书中关于this的介绍后写的,相当于是读书笔记,把书中的重点总结了出来。如果你看完本文还有什么不懂的话,可以直接看《你不知道的js》这本书,写的灰常好。

概要

  • 函数被new调用,this是新构建的对象;
  • 函数被硬绑定(call、apply、bind)后调用,this是指定绑定的对象;
  • 函数被持有自己的环境对象调用,this是该环境对象;
  • 函数直接被调用,this是全局对象windowstrict mode下是undefined

如果上面说的四种情况你都懂的话,本文就不太适合你了;

this是什么

this是函数执行时建立的一个绑定,指向什么是由函数执行时确定的;
所以判断this指向什么,要先看函数在哪执行,然后再判断this的指向。

判断this指向的四种规则

  • 默认绑定

函数被直接执行,this默认绑定的是window对象,严格模式下是undefined。例如:

function foo() {
  console.log(this) // window
}
foo() // 函数在直接执行,this 指向 window
  • 隐式绑定

隐式绑定需要考虑函数执行时是否有拥有者对象,this一般指向该对象。例如:

let obj = {
  foo: function () {
    console.log(this) // obj
  }
}
obj.foo() // 函数执行时有个拥有者对象 obj,所以 this 指向 obj

需要注意的是,隐式绑定会丢失它的绑定。一般会退回到默认绑定。例如:

let obj = {
  foo: function () {
    console.log(this)
  }
};
let baz = obj.foo
baz() // window,函数执行时才绑定 this,相当于直接执行,this 绑定到 window 上
obj.foo() // obj,隐式绑定,this 指向 obj

当我们传递回调函数时,隐式绑定也会丢失它的绑定。比如:

let obj = {
  foo: function () {
    console.log(this)
  }
};
function doFoo(fn) {
  fn()
}
doFoo(obj.foo) // window
// 参数传递相当于一种赋值,
// 这里是 obj.foo 赋值给 fn,fn 函数执行时,this 绑定到 window
obj.foo() // obj , 隐式绑定,this 指向 obj
  • 明确绑定

有隐式绑定就有明确绑定,它是使用call、apply、bind这些方法强行改变this的指向。比如:

function foo() {
    console.log( this.a )
}

let obj = {
    a: 2
};

foo.call( obj ); // 2, 通过 call 方法强行让 this 指向 obj
  • new 绑定

通过new生成的对象,this指向的是新生成的对象。例如:

function foo(a) {
    this.a = a
}
let bar = new foo( 2 )
console.log( bar.a ) // 2, 
// new 构建的对象,this 指向新构建出来的对象,
// 至于为什么会这样,跟 new 干了啥有关;

一些特例

  • 间接引用

看个栗子:

function foo() {
  console.log( this )
}
let o = { foo: foo }
let p = { }

o.foo() // o
(p.foo = o.foo)() // window

赋值表达式p.foo = o.foo的结果是指向函数的引用,在执行时相当于foo()this指向window

  • 箭头函数

从上面我们可以看出,this是函数执行时,才绑定的。但是箭头函数不同,箭头函数的this是编写时,被绑定到调用者的外层;比如:

function foo() {
  let fn = () => {
    console.log( this )
  }
  return fn()
}
foo() // window
posted @ 2019-03-17 18:01  yangrenmu  阅读(148)  评论(0编辑  收藏  举报