函数this

136 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

大家都知道函数的this是动态的, 未到执行之时,不知道他是谁。 刺激不刺激,今天我们就一起来了解函数的this。

动态的this

浏览器下执行下面的代码:

var name = "window"
function logName(){
    console.log(this.name, this)
}

function logName2(){
    "use strict"
     console.log("this:", this)
}

var person = {
    name: "person",
    logName
}

logName();
// window Window {window: Window, self: Window, document: document, name: 'window', location: Location, …}

logName2()
// this: undefined

person.logName();
// person {name: 'person', logName: ƒ}

可以看出, logName直接执行和作为一个属性执行,this的输出是完全不一样的。

顺便,我们通过logName2也验证了,严格模式下, this为undefined

改变this的方式

一起看看常见的改变函数this的方法方式。

call

function logName(){
    console.log(this.name, this)
}
logName.call({name: "haha"})
// haha {name: 'haha'}

apply

function logName(){
    console.log(this.name, this)
}
logName.apply({name: "haha"})
// haha {name: 'haha'}

bind

bind额外说一下,返回的是一个函数。

function logName(){
    console.log(this.name, this)
}
logName.bind({name: "haha"})()
// // haha {name: 'haha'}

new

function logName(){
    console.log(this.name, this)
}
logName.prototype.name = "哎哟";

new logName();
// 哎哟 logName {}

函数作为构造函数的时候, this 是logName的实例。

作为属性

这是函数的一个基本特征,也是改变this的一种方式吧。

function logName(){
    console.log(this.name, this)
}
var person = {
    name: "person",
    logName
}
// person {name: 'person', logName: ƒ}

锁定this的方式

有改变就有锁定, this, 你往哪里跑!

bind

function logName(){
    console.log(this.name, this)
}
var person = {
    name: "person",
}

logName.bind(person).call({name: "o"})
// person {name: 'person'}

可以看到,用bind绑定this之后,再想用 call去改变this,是不行的。

logName.bind(person).bind({name: "o"})
// person {name: 'person'}

同样的,多次bind,第一次生效!

箭头函数

var name = "window";
var person = {
    name: "person",
    logName: () => {
        console.log(this.name, this)
    }
}
person.logName();
// window Window {window: Window, self: Window, document: document, name: 'window', location: Location, …}

可以看到结果是name属性的值是window,因为箭头函数把this绑定到当时所处的上下文。

:: 函数绑定符

函数绑定符。

({name:"123"})::logName()
// 等同于 logName.bind({name:"123"})
// 123

更多信息可以参见 proposal-bind-operator

小结

  • 动态的this
    执行的时候,才确定
  • 有好几种方式可以改变this
    call, apply, bind和new都可以
  • 也有好几种方式绑定this
    bind,箭头函数,::绑定符

今天你收获了吗?