我们都知道call、apply、bind()都是用来改变this指向的,这个概念 我看了好多遍每次看完总是似懂非懂,下面做个记录,首先我们在MDN上重新了解这几个概念:
apply()
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
语法介绍:
func.apply(thisArg, [argments])
thisArg: this要指向的对象,想指定的上下文
arguments: 想要传递的参数(数据或类数组对象)
call()
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
语法介绍:
func.call(thisArg, arg1, arg2 …)
thiArg: this要指向的对象,想指定的上下文
arg1, arg2 …: 指定的参数列表
我们可以看到:
call和apply的作用是相同的,他们都是用来改变函数上下文,并且第一个参数 都是要指定的上下文,区别就是call()方法接受的是一个参数列表,apply()接受的是一个参数数组
var female = {
name: '女生',
age: 18,
likeWear: function() {
console.log(this.name)
console.log(arguments)
}
}
var male = {
name: '男生',
age: '20'
}
female.likeWear.apply(male, ['polo','球鞋'])
female.likeWear.call(male, 'polo','球鞋')
male 拥有了likeWear()方法并立即执行了返回了 name 以及传入的参数
我们看一下mdn上的例子
var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
console.log(max);
// expected output: 7
var min = Math.min.apply(null, numbers);
console.log(min);
// expected output: 2
第一个参数为 null或者undefined时,会自动替换为指向全局对象,在html中为window对象,在window对象上调用 math.max方法,输出数组中的最大值
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.log(array); // ["a", "b", 0, 1, 2]
array.push.apply(array,elements) 可以将elements作为一个参数合集 (不是一个参数)依次添加近array中
var animals = [
{ species: 'Lion', name: 'King' },
{ species: 'Whale', name: 'Fail' }
];
for (var i = 0; i < animals.length; i++) {
(function(i) {
this.print = function() {
console.log('#' + i + ' ' + this.species
+ ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}
call() 允许为不同的对象分配和调用属于一个对象的函数/方法。
上述代码中 animals[i] 调用 分配并调用了这个匿名函数 并把 i作为参数穿了进去 当i=0时
对象 {species: ‘Lion’, name: 'King} 分配了
我的理解是
obj = {
species: 'line',
name: 'King',
print: function() {
console.log('#0' +t his.species
+ ': ' + this.name )
}
}
运用call()立即执行方法print
在下面的例子中,当调用 greet 方法的时候,该方法的this值会绑定到 obj 对象。
function greet() {
var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
console.log(reply);
}
var obj = {
animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj); //
bind()
bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。
语法介绍:
function.bind(thisArg[,arg1[,arg2[, …]]]) 生成一个新的方法
thisArg: 调用绑定函数时作为this参数传递给目标函数的值, 1.如果使用new运算符构造绑定函数,则忽略该值。当使用2.bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。3.如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg。
arg1, arg2, …
当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
console(unboundGetX())时 unboundGetX在全局变量window上 window上没有x属性 所以返回undefined ,console.log(boundGetX())时,this指向 module module.x = 42, 返回42
1. bind() 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 this 值
2 bind()的另一个最简单的用法是使一个函数拥有预设的初始参数。(传参)
function list() {
return Array.prototype.slice.call(arguments);
}
function addArguments(arg1, arg2) {
return arg1 + arg2
}
var list1 = list(1, 2, 3); // [1, 2, 3]
var result1 = addArguments(1, 2); // 3
// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);
// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37); //执行作用域的this将被视为新函数的thisArg。
var list2 = leadingThirtysevenList();
// [37]
var list4 = addThirtySeven()
// NAN
var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]
var result2 = addThirtySeven(5);
// 37 + 5 = 42
var result3 = addThirtySeven(5, 10);
// 37 + 5 = 42 ,第二个参数被忽略
优先使用bind时传入的参数进行计算,参数不够的情况下返回NAN, 参数太多会忽略多余参数
在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window (或global)对象。当类的方法中需要 this 指向类的实例时,你可能需要显式地把 this 绑定到回调函数,就不会丢失该实例的引用。
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
console.log(this) // LateBloomer {petalCount: 12}
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};
var flower = new LateBloomer();
flower.bloom(); // 一秒钟后, 调用'declare'方法
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare, 1000);
};
LateBloomer.prototype.declare = function() {
console.log(this) // window 对象
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');//I am a beautiful flower with undefined petals!
};
var flower = new LateBloomer();
flower.bloom(); // 一秒钟后, 调用'declare'方法