call,apply,bind的区别

一、this的理解

在call,apply,bind的应用中,都会出现this,因此我们需要先来了解一下this的具体分类和意思。

JavaScript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

(一)This的指向(四种):

1、作为对象的方法调用:此时this指向该对象

 
 
var obj1 = {
	name : 'a',
	getName : function () {
		console.log(this === obj1);   //true
		return this.name;   //'a'
	}
}

obj1.getName();

2、最为普通函数调用:此时this指向全局对象(在浏览器中,全局对象为window)

 
 
window.name = 'windowName';
var getName = function () {
	console.log('this = ' + this);   ///this = [object Window]
	return this.name;   //"windowName"
}
getName();

3、构造器调用:此时this指向返回的对象

 
 
var Animal = function (name) {
	this.name = name;
}

var cat = new Animal('cat');
console.log(cat.name);  //'cat'

4、Function.prototype.call或Function.prototype.apply调用:此时this指向传入的第一个参数对象

 
 
var obj1 = {
	name : 'a',
	getName : function () {
		console.log(this === obj1);   //false
		return this.name;   //'b'
	}
};

var obj2 = {
	name : 'b'
};

obj1.getName.call(obj2);

(二)丢失的this

var obj1 = {
	name : 'a',
	getName : function () {
		return this.name;  
	}
};

var getName2 = obj1.getName;
getName2();    // 'windowName',此时的this指向window,由于之前已经设置window.name= 'windowName'

要想实现预期效果,需要对this进行修正

方法一:

 
 
var obj1 = {
	name : 'a',
	getName : function (self) {
		return self.name;  
	}
};

var getName2 = obj1.getName;
getName2(obj1);  // 'a'

方法二:

 
 
var obj1 = {
	name : 'a',
	getName : function () {
		return this.name;   
	}
};

obj1.getName = (function (func) {
	return function () {
		return func.apply(obj1);
	}
})(obj1.getName);

var getName2 = obj1.getName;
getName2();   //'a'

二、call、apply、bind

call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。

(一)call的应用

 
 
Function.call(this.obj,arg1,args,……)

Call中的第一个参数是对象,参数的传入需要一个个列举,返回的是调用函数的返回值。

例如,为了让字符串有pop的方法,字符串可以调用数组的slice方法,这样就返回一个数组,因为slice的返回值就是数组。

 
 
Array.prototype.slice.call('123456');//返回值[1,2,3,4,5,6]

(二)apply的应用

 
 
Function.apply(this.obj,[arg1,arg2,……])

Apply的第一个参数是对象,第二个参数则是数组,返回的是调用函数的返回值。

 
 
function add (a,b) {
	return a+b;
}
var obj1 = {
	name:'haha'
};
add.apply(obj1,[4,5]);

(三)bind的应用

Bind则是函数绑定到一个对象,返回一个新函数,通过可选的指定参数,作为指定对象的方法调用该方法。

 
 
Function.bind(this.obj,arg1,arg2,……);//返回一个函数

利用call和apply实现bind方法:

 
 
Function.prototype.bind = function() {
	var self = this,                       //保存原来的函数function
		content = [].shift.call(arguments),//bind中传入的函数,提取出第一个this参数
		args = [].slice.call(arguments);   //保存bind中的其他参数
	return function () {	               //返回一个函数
		return self.apply(content, [].concat.call(args,[].slice.call(arguments)));                      //返回执行原来function的结果。Arguments为新函数的传参。
	}
}
var func2 = function (a,b,c,d) {
	console.log(this.name);
	console.log(a,b,c,d);
}
var obj1 = {
	name: 'zsx'
};
var func1 = func2.bind(obj1, 1, 2);
func1(3,4);   //'zsx', 1,2,3,4

三、具体使用场景区分

如果只是简单的调用对象本身没有的方法,则使用call或者apply。当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。

如果需要一个本身对象没有,且之后还经常使用的,那就使用bind,在其他函数的基础上,绑定一个新函数,之后传入相应的参数即可多次使用。

注意:

当使用call或者apply时,如果我们传入的第一个参数是null,函数体内的this会指向默认的宿主对象,在浏览器中就是window;但如果是在严格模式下,函数体内的this还是为null。

参考:
call,apply && bind,currying

如何理解和熟练运用js中的call和apply

《JavaScript设计模式与开发实践》--曾探

图片引用,侵权立删

猜你喜欢

转载自blog.csdn.net/zhongshanxian/article/details/80859217