call,apply和bind有什么区别?

4 call、apply、bind

了解了函数 this 的指向之后,我们知道在一些情况下我们为了使用某种特定环境的 this 引用,需要采用一些特殊手段来处理,例如我们经常在定时器外部备份 this 引用,然后在定时器函数内部使用外部 this 的引用。
然而实际上 JavaScript 内部已经专门为我们提供了一些函数方法,用来帮我们更优雅的处理函数内部 this 指向问题。call、apply、bind 三个函数方法。call()、apply()、bind()这三个方法都是是用来改变this的指向的。

4.1 call,apply

call() 方法调用一个函数, 其具有一个指定的 this 值和分别地提供的参数(参数的列表)。
apply() 方法调用一个函数, 其具有一个指定的 this 值,以及作为一个数组(或类似数组的对象)提供的参数。

注意:call() 和 apply() 方法类似,只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。

call语法:

fun.call(thisArg[, arg1[, arg2[, ...]]])

在 fun 函数运行时指定的 this 值
如果指定了 null 或者 undefined 则内部 this 指向 window

apply语法:

fun.apply(thisArg, [argsArray])

apply() 与 call() 相似,不同之处在于提供参数的方式。
apply() 使用参数数组而不是一组参数列表。例如:

fun.apply(this, ['eat', 'bananas'])

4.1.1 新的函数调用方式apply和call方法

function f1(x, y) {
    
    
	console.log("结果是:" + (x + y) + this);
	return "666";
}
f1(10, 20); // 函数的调用
 
console.log("========");

// apply和call方法也是函数的调用的方式
// 此时的f1实际上是当成对象来使用的,对象可以调用方法
// apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是默认的window

f1.apply(null, [10, 20]);
f1.call(null, 10, 20);

// apply和call都可以让函数或者方法来调用,传入参数和函数自己调用的写法不一样,但是效果是一样的

var result1 = f1.apply(null, [10, 20]);
var result2 = f1.call(null, 10, 20);
console.log(result1);
console.log(result2);

4.1.2 apply和call可以改变this的指向

/*通过apply和call改变this的指向*/
function Person(name, sex) {
    
    
	this.name = name;
	this.sex = sex;
}
//通过原型添加方法
Person.prototype.sayHi = function(x, y) {
    
    
	console.log("您好啊:" + this.name);
	return x + y;
};
var per = new Person("小三", "男");
var r1 = per.sayHi(10, 20);
 
console.log("==============");
 
function Student(name, age) {
    
    
	this.name = name;
	this.age = age;
}
var stu = new Student("小舞", 18);
var r2 = per.sayHi.apply(stu, [10, 20]);
var r3 = per.sayHi.call(stu, 10, 20);
 
console.log(r1);
console.log(r2);
console.log(r3);

4.2 call,apply使用

apply和call都可以改变this的指向。调用函数的时候,改变this的指向:

// 函数的调用,改变this的指向
function f1(x, y) {
    
    
	console.log((x + y) + ":===>" + this);
	return "函数的返回值";
}
//apply和call调用
var r1 = f1.apply(null, [1, 2]); // 此时f1中的this是window
console.log(r1);
var r2 = f1.call(null, 1, 2); // 此时f1中的this是window
console.log(r2);
console.log("=============>");
//改变this的指向
var obj = {
    
    
	sex: "男"
};
// 本来f1函数是window对象的,但是传入obj之后,f1的this此时就是obj对象
var r3 = f1.apply(obj, [1, 2]); //此时f1中的this是obj
console.log(r3);
var r4 = f1.call(obj, 1, 2); //此时f1中的this是obj
console.log(r4);

调用方法的时候,改变this的指向:

//方法改变this的指向
function Person(age) {
    
    
	this.age = age;
}
Person.prototype.sayHi = function(x, y) {
    
    
	console.log((x + y) + ":====>" + this.age); //当前实例对象
};
 
function Student(age) {
    
    
	this.age = age;
}
var per = new Person(10); // Person实例对象
var stu = new Student(100); // Student实例对象
// sayHi方法是per实例对象的
per.sayHi(10, 20);
per.sayHi.apply(stu, [10, 20]);
per.sayHi.call(stu, 10, 20);

总结

apply的使用语法:
1 函数名字.apply(对象,[参数1,参数2,…]);
2 方法名字.apply(对象,[参数1,参数2,…]);
call的使用语法
1 函数名字.call(对象,参数1,参数2,…);
2 方法名字.call(对象,参数1,参数2,…);
它们的作用都是改变this的指向,不同的地方是参数传递的方式不一样。

如果想使用别的对象的方法,并且希望这个方法是当前对象的,就可以使用apply或者是call方法改变this的指向。

4.3 bind

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也可以接受预设的参数提供给原函数。一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
bind方法是复制的意思,本质是复制一个新函数,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去。apply和call是调用的时候改变this指向,bind方法,是复制一份的时候,改变了this的指向。

语法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

参数:

thisArg

当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效。
arg1, arg2, …

当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
返回值:

返回由指定的this值和初始化参数改造的原函数的拷贝。

示例1:

function Person(name) {
    
    
	this.name = name;
}
Person.prototype.play = function() {
    
    
	console.log(this + "====>" + this.name);
};
 
function Student(name) {
    
    
	this.name = name;
}
var per = new Person("人");
var stu = new Student("学生");
per.play();
// 复制了一个新的play方法
var ff = per.play.bind(stu);
ff();

示例2:

//通过对象,调用方法,产生随机数
function ShowRandom() {
    
    
	//1-10的随机数
	this.number = parseInt(Math.random() * 10 + 1);
}
//添加原型方法
ShowRandom.prototype.show = function() {
    
    
	//改变了定时器中的this的指向了
	window.setTimeout(function() {
    
    
		//本来应该是window, 现在是实例对象了
		//显示随机数
		console.log(this.number);
	}.bind(this), 1000);
};
//实例对象
var sr = new ShowRandom();
//调用方法,输出随机数字
sr.show();

4.4 总结

call 和 apply 特性一样

都是用来调用函数,而且是立即调用
但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向
call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window

bind
可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数
它和 call、apply 最大的区别是:bind 不会调用
bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递
在 bind 的同时,以参数列表的形式进行传递
在调用的时候,以参数列表的形式进行传递
那到底以 bind 的时候传递的参数为准呢?还是以调用的时候传递的参数为准呢?
两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部。

猜你喜欢

转载自blog.csdn.net/qq_42526440/article/details/113983799
今日推荐