最近又遇到了JavaScript中的call()方法和apply()方法,而在某些时候这两个方法还确实是十分重要的,那么就让我总结这两个方法的使用和区别吧。
1. 每个函数都包含两个非继承而来的方法:call()方法和apply()方法。
2. 相同点:这两个方法的作用是一样的。
都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向。
call()方法使用示例:
//例1
<script>
window.color = 'red';
document.color = 'yellow';
var s1 = {color: 'blue' };
function changeColor(){
console.log(this.color);
}
changeColor(); //red
changeColor.call(); //red (默认传递参数)
changeColor.call(window); //red
changeColor.call(document); //yellow
changeColor.call(this); //red
changeColor.call(s1); //blue
</script>
//例2
var Pet = {
words : '...',
speak : function (say) {
console.log(say + ''+ this.words)
}
}
Pet.speak('Speak'); // 结果:Speak...
var Dog = {
words:'Wang'
}
//将this的指向改变成了Dog
Pet.speak.call(Dog, 'Speak'); //结果: SpeakWang
apply()方法使用示例:
//例1
<script>
window.number = 'one';
document.number = 'two';
var s1 = {number: 'three' };
function changeColor(){
console.log(this.number);
}
changeColor.apply(); //one (默认传参)
changeColor.apply(window); //one
changeColor.apply(document); //two
changeColor.apply(this); //one
changeColor.apply(s1); //three
</script>
//例2
function Pet(words){
this.words = words;
this.speak = function () {
console.log( this.words)
}
}
function Dog(words){
//Pet.call(this, words); //结果: Wang
Pet.apply(this, arguments); //结果: Wang
}
var dog = new Dog('Wang');
dog.speak();
- 不同点:接收参数的方式不同。
apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
语法:apply([thisObj [,argArray] ]);,调用一个对象的一个方法,2另一个对象替换当前对象。
说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个
TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。
call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
语法:call([thisObject[,arg1 [,arg2 [,…,argn]]]]);,应用某一对象的一个方法,用另一个对象替换当前对象。
说明: call方法可以用来代替另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上下文改变为thisObj指定的新对象,如果没有提供thisObj参数,那么Global对象被用于thisObj。
使用示例1:
function add(c,d){
return this.a + this.b + c + d;
}
var s = {a:1, b:2};
console.log(add.call(s,3,4)); // 1+2+3+4 = 10
console.log(add.apply(s,[5,6])); // 1+2+5+6 = 14
使用示例2:
<script>
window.firstName = "Cynthia";
window.lastName = "_xie";
var myObject = {firstName:'my', lastName:'Object'};
function getName(){
console.log(this.firstName + this.lastName);
}
function getMessage(sex,age){
console.log(this.firstName + this.lastName + " 性别: " + sex + " age: " + age );
}
getName.call(window); // Cynthia_xie
getName.call(myObject); // myObject
getName.apply(window); // Cynthia_xie
getName.apply(myObject);// myObject
getMessage.call(window,"女",21); //Cynthia_xie 性别: 女 age: 21
getMessage.apply(window,["女",21]); // Cynthia_xie 性别: 女 age: 21
getMessage.call(myObject,"未知",22); //myObject 性别: 未知 age: 22
getMessage.apply(myObject,["未知",22]); // myObject 性别: 未知 age: 22
</script>
-----------------------------------------------------------------------------手动分割线----------------------------------------------------------------------------
一 使用:
function log (...args) {
console.log(...args)
}
function log () {
console.log.apply(console, arguments)
}
log(1, 2, 3)
log.bind()
-
call()
-
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
-
调用call的对象必须是个函数function
-
call的第一个参数将会是function改变上下文后指向的对象,如果不传,将会默认是全局对象window
-
第二个参数开始可以接收任意个参数,这些参数将会作为function的参数传入function
-
-
apply()
-
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
-
与call方法的使用基本一致,但是只接收两个参数,其中第二个参数必须是一个数组或者类数组,这也是这两个方法很重要的一个区别
-
二 异同
-
相同点
- 都能够改变方法的执行上下文(执行环境),将一个对象的方法交给另一个对象来执行,并且是立即执行
-
不同点
-
call方法:从第二个参数开始可以接收任意个参数,每个参数会映射到相应位置的function的参数上,可以通过参数名调用,但是如果将所有的参数作为数组传入,它们会作为一个整体映射到function对应的第一个参数上,之后参数都为空
-
apply方法:最多只有两个参数,第二个参数接收数组或者类数组,但是都会被转换成类数组传入function中,并且会被映射到function对应的参数上
-
更简单地说,apply和call功能一样,只是传入的参数列表形式不同:
如 function.call(function1,var1,var2,var3)对应的apply写法为:function.apply(function1,[var1,var2,var3])
-
三 两个方法该如何选择?
-
根据你要传入的参数来做选择,不需要传参或者只有1个参数的时候,用call,当要传入多个对象时,用apply。
-
如果需要传入的参数已经是一个数组或者类数组了,就用apply,如果还是单独的需要逐个传入的,可以考虑使用call(如果你不嫌麻烦的话 )
题目点评
本题属于比较一般性的问题,稍有接触的同学都是能够掌握的,先说清楚他们的相同点,方法的作用的,在把它们的差异讲清楚。
如果题目问到异同点如何回答?
相同点:两个方法产生的作用是完全一样的,都用来改变当前函数调用的对象。
不同点:调用的参数不同,比较精辟的总结:
foo.call(this,arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)
具体的使用
1.call的使用
语法
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
参数
thisObj 可选项。将被用作当前对象的对象。
arg1,arg2, , argN 可选项。将被传递方法参数序列。
说明
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
示例
<input id="myText">
<script>
function Obj()
{
this.value="对象!";
}
var value="global 变量";
function Fun1(a,b){
alert(this.value);
}
window.Fun1(); //global 变量
Fun1.call(window,1,2); //global 变量
Fun1.call(document.getElementById('myText')); //input text
Fun1.call(new Obj()); //对象!
</script>
2.apply()
apply与call的功能几乎一样,第一个参数意义都一样,只是第二个参数有点不同apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,call从第二个参数开始,依次传值给调用函数的参数
3.代码比较
function print(a, b, c, d){
alert(a + b + c + d);
}
function example(a, b , c , d){
//用call方式借用print,参数显式打散传递
print.call(this, a, b, c, d);
//用apply方式借用print, 参数作为一个数组传递,
//这里直接用JavaScript方法内本身有的arguments数组
print.apply(this, arguments);
//或者封装成数组
print.apply(this, [a, b, c, d]);
}
//下面将显示“我爱学习””
example("我" , "爱" , "学", "习");
bind() 方法和前两者不同在于: bind() 方法会返回执行上下文被改变的函数而不会立即执行,而前两者是直接执行该函数。他的参数和call()相同。
bind 除了返回是函数以外,它 的参数和 call 一样。
当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。
当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。
一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
//在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它
var fn = {
bar : 1,
eventBind: function(){
var _this = this;
$('.someClass').on('click',function(event) {
console.log(_this.bar); //1
});
}
}
//当然使用 bind() 可以更加优雅的解决这个问题:
var fn = {
bar : 1,
eventBind: function(){
$('.someClass').on('click',function(event) {
/* Act on the event */
console.log(this.bar); //1
}.bind(this));
}
}
//创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 fn , 而不是像我们调用 bar() 时的全局作用域。
var bar = function(){
console.log(this.a);
}
var fn = {
a:3
}
bar(); // undefined
var func = bar.bind(fn);
func(); // 3
这三个方法的作用都是改变函数的执行上下文!