持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
函数内部有三个重要的特殊属性:arguments、this和new.target.
1、arguments
arguments是一个类数组对象,里面的值是调用函数时传递的参数。这个属性只有使用function关键字定义的才有,也就是使用箭头函数创建的没有。
arguments对象有一个属性叫callee,它是一个指向arguments对象所在函数的指针。它通常用来让函数逻辑与函数名解耦
2、new.target
我们知道对象可以使用new关键字创建,也就是使用构造函数方式创建,也就是任何一个函数都可以实例化一个新对象。但是在使用继承的时候,有时候我们不想让父类可以被实例化(抽象基类),我们只能实例化子类,这时候,我们就可以使用new.target
function Father() {
if (new.target === Father) {
throw new Error('cant use Father to create object')
}
}
new Father()
// Error: cant use Father to create object
3、this
下面就是this的关键字this了。this在标准函数和箭头函数中有不同的行为。
在标准函数中,this引用的是把函数当成方法调用的上下文对象,这时候通常称其为this值。
var name = 'window';
let o = {
name: 'ly'
}
function sayName() {
console.log(this.name);
}
sayName(); // window
o.sayName = sayName;
o.sayName(); //ly
我们知道var在全局声明的变量,会自动添加到全局对象window上,而在全局上下文中调用sayName(),这时候会输出window,因为this指向的是window,而this.name就相当于window.name。而在把sayName赋值给o对象后再调用o.sayName(),this也就指向了o,而this.name也就相当于o.name.
在箭头函数中,this引用的是定义箭头函数的上下文。
var name = 'window';
let o = {
name: 'ly'
}
sayName = () => {
console.log(this.name);
}
sayName(); // window
o.sayName = sayName;
o.sayName(); //window
这是因为sayName()在全局上下文中定义的,所以sayName的this就指向了window.哪怕将它赋值给o对象this的值也不会改变。
注意:函数名只不过是保存指针的变量,sayName()函数和o.sayName()是同一个函数,只不过执行的上下文不同。
4、call、apply和bind
call、apply个bind都是会改变函数内部this的值。
apply接收两个参数:函数内this的值和参数数组。第二个参数是Array的实例,也可以是arguments对象。
function sum(a, b) {
return a + b;
}
function callSum1(a, b) {
return sum.apply(this, arguments)
}
function callSum2(a, b) {
return sum.apply(this, [a, b])
}
console.log(callSum1(1, 2)); // 3
console.log(callSum2(1, 2)); // 3
call的使用方法和apply基本一样,唯一的区别就是传参是形式不同,call的第一个参数和apply一样,而剩下的参数就是要传给被调用函数的参数。
function sum(a, b) {
return a + b;
}
function callSum(a, b) {
return sum.call(this, a, b)
}
console.log(callSum(10, 10)); // 20
bind方法与call和bind的方式略有不同,我们通过上面的例子发现call和apply是立即执行函数,而bind则不是立即执行函数,而是返回一个新函数。
function sum(a, b) {
return a + b;
}
function callSum(a, b) {
return sum.bind(this, a, b)
}
let result = callSum(10, 10);
console.log(result()); // 20
console.log(callSum(10, 10)); // [Function: bound sum]
但是call、apply和bind真正厉害的地方其实是改变this值和实现继承。
function add(c, d) {
return this.a + this.b + c + d;
}
var s = { a: 1, b: 2 };
var ss = { a: 10, b: 20 };
let result = add.bind(ss, 3, 4)
console.log(add.call(s, 3, 4)); // 1+2+3+4 = 10
console.log(add.apply(s, [5, 6])); // 1+2+5+6 = 14
console.log(result()); //10+20+3+4 = 37
我们可以看出,call、apply和bind都改变了函数add中的this的值。