-
Notifications
You must be signed in to change notification settings - Fork 6
[Issues#3]关于js中的apply()和call()两个方法
ckinmind edited this page Nov 7, 2016
·
1 revision
[知乎: 如何理解和熟练运用js中的call及apply?](https://www.zhihu.com/question/20289071) js笔记——call,apply,bind使用笔记
语法:call(thisObj, arg1, arg2, ...)
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj
语法:apply([thisObj,[arg1,arg2,....])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果第二个参数不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数
-
两者作用一致,都是把
obj
(即this)绑定到thisObj
,这时候thisObj
具备了obj
的属性和方法。或者说thisObj
『继承』了obj
的属性和方法。绑定后会立即执行函数 -
简单说就是用对象的实例去替换原来的this,这样的话就可以用其他对象里的方法了
-
唯一区别是apply接受的是数组参数,call接受的是连续参数
-
当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来便利所有的参数
-
call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念
function add(a, b){console.dir(this);}
function sub(a, b){console.dir(this);}
add(1,2);
"Window"
sub(1,2);
"Window"
add.call(sub, 1, 2);
"sub(a, b)"
sub.apply(add, [1, 2]);
"add(a, b)"
console.dir()
直接将该DOM结点以DOM树的结构进行输出,可以详细查对象的方法发展等
function add(j, k){
return j+k;
}
function sub(j, k){
return j-k;
}
我们在控制台运行:
add(5,3); //8
add.call(sub, 5, 3); //8
add.apply(sub, [5, 3]); //8
sub(5, 3); //2
sub.call(add, 5, 3); //2
sub.apply(add, [5, 3]); //2
结合3.1理解
var a = {0:1, 1:"yjc", length: 2};
a.slice(0,1); //TypeError: a.slice is not a function
Array.prototype.slice.call(a,0,1);//[1]
Array.prototype.slice.apply(a,[0,1]);//[1]
- slice()方法可从已有的数组中返回选定的元素,第一个参数是起始位置,第二个参数是结束为止
- 对象a类似array,但不具备array的slice等方法。使用call绑定,这时候就可以调用slice方法
var Parent = function(){
this.name = "yjc";
this.age = 22;
}
var child = {};
console.log(child);//Object {} ,空对象
Parent.call(child);
console.log(child); //Object {name: "yjc", age: 22}
通过call和apply,我们可以实现对象继承
obj.bind(thisObj, arg1, arg2, ...);
把obj绑定到thisObj,这时候thisObj具备了obj的属性和方法。与call和apply不同的是,bind绑定后不会立即执行
同样是add()和sub():
add.bind(sub, 5, 3); //不再返回8
add.bind(sub, 5, 3)(); //8
如果bind的第一个参数是null或者undefined,等于将this绑定到全局对象
function changeStyle(attr, value){
this.style[attr] = value;
}
var box = document.getElementById('box');
window.changeStyle.call(box, "height", "200px");
call中的第一个参数用于指定将要调用此函数的对象,在这里,changeStyle函数将被box对象调用,this指向了box对象,如果不用call的话,程序报错,因为window对象中没有style属性
apply的用法:
window.changeStyle.apply(box, ['height', '200px']);
如果call或apply的第一参数是null的话, this指向window
举个更常规的例子吧,比如人类,当被问到:你爸爸叫什么名字的时候,每个人都会调用一个返回父亲名字的方法
function fatherName(){
return this.father.name;
}
你直接调用它会出事,因为这时候的this指代window,系统抛出异常说: Cannot read property 'name' of undefined
但这不代表fatherName这个函数没有存在的意义,要看是谁来调用它。比如有一个人:
var people = {
father: {
name: 'ck'
},
'getMyFatherName': fatherName
};
people.getMyFatherName(); //ck
还有另一个人:
var people2 = {
father: {
name: 'ck2'
},
'getMyFatherName': fatherName
};
people2.getMyFatherName(); //ck2
其实,中国还有很多人,写那……么多fatherName: fatherName 好烦呐
其实你可以这样:
var people = {
father: {
name: 'ck'
}
};
var people2 = {
father: {
name: 'ck2'
}
};
[people,people2].map(function(who){
return fatherName.call(who);
}); //["guodegang", "stone"]
map方法对数组的所有成员依次调用一个函数,根据函数结果返回一个新数组 方法接受一个函数作为参数。该函数调用时,map方法会将其传入三个参数,分别是当前成员、当前位置和数组本身