前端基础知识:this 指向问题,和 bind、call、apply之区分
this
就是一个指针,指向我们调用函数的对象。
执行上下文: 是语言规范中的一个概念,用通俗的话讲,大致等同于函数的执行“环境”。具体的有:变量作用域(和 作用域链条,闭包里面来自外部作用域的变量),函数参数,以及 this
对象的值。
找出
this
的指向
this
的值并不是由函数定义放在哪个对象里面决定,而是函数执行时由谁来唤起决定。
var name = "Jay Global";
var person = {
name: 'Jay Person',
details: {
name: 'Jay Details',
print: function() {
return this.name;
}
},
print: function() {
return this.name;
}
};
console.log(person.details.print()); // 【details对象调用的print】Jay Details
console.log(person.print()); // 【person对象调用的print】Jay Person
var name1 = person.print;
var name2 = person.details;
console.log(name1()); // 【name1前面没有调用对象,所以是window】Jay Global
console.log(name2.print()) // 【name2对象调用的print】Jay Details
this和箭头函数
箭头函数按词法作用域来绑定它的上下文,所以 this
实际上会引用到原来的上下文。
箭头函数保持它当前执行上下文的词法作用域不变,而普通函数则不会。换句话说,箭头函数从包含它的词法作用域中继承到了 this
的值。
匿名函数,它不会作为某个对象的方法被调用, 因此,this
关键词指向了全局 window
对象。
var object = {
data: [1,2,3],
dataDouble: [1,2,3],
double: function() {
console.log(this); // object
return this.data.map(function(item) { // this是当前object,object调用的double
console.log(this); // 传给map()的那个匿名函数没有被任一对象调用,所以是window
return item * 2;
});
},
doubleArrow: function() {
console.log(this); // object
return this.dataDouble.map(item => { // this是当前object,object调用的doubleArrow
console.log(this); // doubleArrow是object调用的,这就是上下文,所以是window
return item * 2;
});
}
};
object.double();
object.doubleArrow();
明确设置执行上下文
在 JavaScript 中通过使用内置的特性开发者就可以直接操作执行上下文了。这些特性包括:
- bind():不需要执行函数就可以将
this
的值准确设置到你选择的一个对象上。通过逗号隔开传递多个参数。 设置好this
关键词后不会立刻执行函数。 - apply():将
this
的值准确设置到你选择的一个对象上。apply(thisObj, argArray)
接收两个参数,thisObj是函数运行的作用域(this),argArray是参数数组,数组的每一项是你希望传递给函数的参数。如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。最后,会立刻执行函数。 - call():将
this
的值准确设置到你选择的一个对象上。然后像bind
一样通过逗号分隔传递多个参数给函数。语法:call(thisObj,arg1,arg2,..., argn);
,如果没有提供thisObj参数,那么Global对象被用于thisObj。最后,会立刻执行函数。
this 和 bind
var bobObj = {
name: "Bob"
};
function print() {
return this.name;
}
var printNameBob = print.bind(bobObj);
console.log(printNameBob()); // Bob
this 和 call
function add(a, b) {
return a + b;
}
function sum() {
return Array.prototype.reduce.call(arguments, add);
}
console.log(sum(1,2,3,4)); // 10
this 和 apply
apply 就是接受数组版本的call。
Math.min(1,2,3,4); // 返回 1
Math.min([1,2,3,4]); // 返回 NaN。只接受数字
Math.min.apply(null, [1,2,3,4]); // 返回 1
function Person(name, age){
this.name = name;
this.age = age;
}
function Student(name, age, grade) {
Person.apply(this, arguments); //Person.call(this, name, age);
this.grade = grade;
}
var student = new Student("sansan", 21, "一年级");
console.log("student:", student); // {name: 'sansan'; age: '21', grade: '一年级'}
如果你的参数本来就存在一个数组中,那自然就用 apply,如果参数比较散乱相互之间没什么关联,就用 call。
THE END