(译文)掌握JavaScript基础--理解this关键字的新思路

时间:2022-07-27 16:43:02

普通函数

下面这种就是普通函数

function add(x, y) {
return x + y;
}

每个普通函数被调用的时候,都相当于有一个this参数传进来。

内部函数this不会是外部函数传入的this,相当于和外部的this隔离开了。

function outer() {
function inner() {
console.log(this); // window
}
console.log(this); // 'outer'
inner();
}
outer.call('outer');

相当于:

function outer(_this) {
function inner(_this) {
console.log(_this); // undefined
}
console.log(_this); // 'outer'
inner(undefined);
}
outer('outer');

箭头函数

const add = (x, y) => {
return x + y;
};

如果你用箭头函数,内部函数的this和外部是一致的:

function outer() {
const inner = () => {
console.log(this); // 'outer'
};
console.log(this); // 'outer'
inner();
}
outer.call('outer');

箭头函数的this不会被call方法影响,它总是和箭头函数所在的位置有关:

它所在的位置(也就是作用域)的this指向谁,箭头函数里面的this就指向谁。

function ordinary() {
const arrow = () => this;
console.log(arrow.call('goodbye')); // 'hello'
}
ordinary.call('hello');

普通函数作为方法

如果一个函数赋值给了属性,就变成了方法:

const obj = {
prop: function () {}
};

调用方法的方式是:

obj.prop(x, y)

相当于:

obj.prop.call(obj, x, y)

陷阱

1 回调函数里面用this

回调里面执行(A),你发现logStatus访问不了。这个是因为this被阻隔了。

performCleanup() {
cleanupAsync()
.then(function () {
this.logStatus('Done'); // (A)
});
}

你应该采用箭头函数:

performCleanup() {
cleanupAsync()
.then(() => {
this.logStatus('Done');
});
}

2 map方法里面用this

同理,this也是访问不了company和name的

prefixNames(names) {
return names.map(function (name) {
return this.company + ': ' + name; // (A)
});
}

采用箭头函数:

// Inside a class or an object literal:
prefixNames(names) {
return names.map(
name => this.company + ': ' + name);
}

3 用函数作为回调

class UiComponent {
constructor(name) {
this.name = name;
const button = document.getElementById('myButton');
button.addEventListener('click', this.handleClick); // (A)
}
handleClick() {
console.log('Clicked '+this.name); // (B)
}
}

改为:

class UiComponent {
constructor(name) {
this.name = name;
const button = document.getElementById('myButton');
button.addEventListener(
'click', this.handleClick.bind(this)); // (A)
}
handleClick() {
console.log('Clicked '+this.name);
}
}

bind函数能让普通的函数调用无法修改this:

function returnThis() {
return this;
}
const bound = returnThis.bind('hello');
bound(); // 'hello'
bound.call(undefined); // 'hello'

保持正确的做法

1 用ESlint的rules: no-invalid-this

避免普通函数内部有this,一般在方法内使用this或者箭头函数内使用

2 不要把this当做参数

因为这样你就不能用箭头函数了

beforeEach(function () {
this.addMatchers({ // access API object
toBeInRange: function (start, end) {
···
}
});
});

可以很容易被改写:

beforeEach(api => {
api.addMatchers({
toBeInRange(start, end) {
···
}
});
});

原文链接:http://2ality.com/2017/12/alternate-this.html

作者知乎/公众号:前端疯 (一群热爱前端的一线程序员维护,想要用前端改变世界。)

(译文)掌握JavaScript基础--理解this关键字的新思路