# 函数进阶-执行上下文
# 函数绑定
当将对象方法作为回调进行传递,例如传递给 setTimeout,这儿会存在一个常见的问题:“丢失 this”。
# 绑定上下文
函数对象提供了一个内建方法 bind,它可以绑定 this。
基本的语法是:
// 稍后将会有更复杂的语法
let boundFunc = func.bind(context);
let user = {
firstName: "John"
};
function func(phrase) {
alert(phrase + ", " + this.firstName);
}
// 将 this 绑定到 user
let funcUser = func.bind(user);
funcUser("Hello"); // Hello, John(参数 "Hello" 被传递,并且 this=user)
便捷方法:bindAll
如果一个对象有很多方法,并且我们都打算将它们都传递出去,那么我们可以在一个循环中完成所有方法的绑定:
for (let key in user) {
if (typeof user[key] == "function") {
user[key] = user[key].bind(user);
}
}
# 绑定参数
我们不仅可以绑定 this,还可以绑定参数(arguments)。虽然很少这么做,但有时它可以派上用场。
bind 的完整语法如下:
let bound = func.bind(context, [arg1], [arg2], ...);
# 箭头函数
让我们深入研究一下箭头函数。
箭头函数不仅仅是编写简洁代码的“捷径”。它还具有非常特殊且有用的特性。
JavaScript 充满了我们需要编写在其他地方执行的小函数的情况。
# 箭头函数没有 “this”
我们常说的一句话就是箭头函数没有 “this”
,在箭头函数中访问 this,会从箭头函数的声明上下文中获取。
let group = {
title: "Our Group",
students: ["John", "Pete", "Alice"],
showList() {
this.students.forEach((student) => alert(this.title + ": " + student));
}
};
group.showList();
这里 forEach 中使用了箭头函数,所以其中的 this.title 其实和外部方法 showList 的完全一样。那就是:group.title。
如果我们使用正常的函数,则会出现错误,报错是因为 forEach 运行它里面的这个函数,但是这个函数的 this 为默认值 this=undefined
。
不能对箭头函数进行 new 操作
不具有 this 自然也就意味着另一个限制:箭头函数不能用作构造器(constructor)。不能用 new 调用它们。
箭头函数 VS bind
.bind(this)
创建了一个该函数的“绑定版本”- 箭头函数 => 没有创建任何绑定。箭头函数只是没有 this。this 的查找与常规变量的搜索方式完全相同:在外部词法环境中查找。
# 箭头函数没有 “arguments”
箭头函数也没有 arguments 变量。
当我们需要使用当前的 this 和 arguments 转发一个调用时,这对装饰器(decorators)来说非常有用。
function defer(f, ms) {
return function () {
setTimeout(() => f.apply(this, arguments), ms);
};
}
不用箭头函数的话,可以这么写:
function defer(f, ms) {
return function (...args) {
let ctx = this;
setTimeout(function () {
return f.apply(ctx, args);
}, ms);
};
}
在这里,我们必须创建额外的变量 args 和 ctx,以便 setTimeout 内部的函数可以获取它们。
# 总结
箭头函数:
- 没有 this
- 没有 arguments
- 不能使用
new
进行调用,也没有super