apply:劫持另外一个对象的方法,继承另外一个对象的属性.
Function.apply(obj,args)方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
call:和apply的意思一样,只不过是参数列表不一样.
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
<script type="text/javascript">
/**
this:指向当前对象的引用
Computer类中的call和apply的使用,就是一个computer对象分别劫持了Cpu和Mainbord对象
*/
function Computer(name,memory,store){
this.name=name;
//Use call
/**
Cpu.call(this,memory);
Mainbord.call(this,store);
*/
//Use apply
Cpu.call(this,new Array(memory.toString()));
Mainbord.call(this,new Array(store.toString()));
}
function Cpu(memory){
this.memory=memory;
}
function Mainbord(store){
this.store=store;
}
(function (){
var com=new Computer("moline",2 ,500);
console.log(com.name+"\nMemory:"+com.memory+"\nStore:"+com.store);
})();
</script>
个人理解:
每一个声明function的函数(类)的原型链都是一个Empty的函数(类),Empty的原型链是一个Object,
由此形成一条继承链:UserFunction---->Empty---->Object.所以所有的函数都可以使用Empty和Object中的公共属性和方法。apply和call方法就属于Empty函数 。
eg:Computer:
每一个用户定义的函数都可以使用apply和call将当前函数的this给替换掉,this将不再指向当前函数的引用位置,而去指向一个要劫持对象的引用位置,即this指向栈的内存地址发生了改变。
this指向位置的几种情况:
一、在JavaScript中所有的全局函数this默认指向window对象,
二、当我们创建一个对象的时候:
var com=new Computer("moline",2 ,500);
函数的this将指向我们所创建的对象(com)。
三、当我们调用apply和call时,this将指向apply或call中的第一个参数的位置。(可以认为这两个方法利用第一个参数后面的参数创建了一个当前函数的实例,并将该实例的属性和方法逐一添加到第一个参数中)
综上所述,可以得出上面的例子中:
1、com指向Computer中的this,在Computer函数中this又分别传给了Cpu和Mainbord的apply,因此com将获得Cpu和Mainbord中的属性和方法。
2、Computer实现了多继承,父类分别是Cpu和Mainbord
apply和call的区别:
可以认为apply是call的一个拓展,即apply不在像call方法那样接受很多个参数,而是只接受两个参数:
第一个:要劫持的对象
第二个:参数组成的数组对象
apply将接受的数组按照从前向后的顺序将数组分解成N个对象,再调用call方法,第一个参数不变,然后把N个对象放到call后面的参数中。
假象代码:
function apply(obj,arr){
var str="call(obj";
for(var i=0;i<arr.length;i++){
str+=","+arr[i];
}
str+=");";
eval(str); //str最终样例 str="call(obj,arr[0],arr[1],arr[2]......);";
}
根据上述代码可以得出:
一、apply简化了call方法的调用
二、apply对call接受的参数顺序进行了限制(必须按照数组的0~i传递)
根据这两点我们可以明白什么情况使用call,什么情况使用apply。能用apply就用apply,如果参数顺序限制apply不能达到效果,再使用call
apply隐藏功能:
通过假象代码我们可以容易理解apply和call的区别,但实际情况并不是这么实现的,实际apply运行比假象代码中的apply运行要快3~5倍左右。这种快速就是apply隐藏的功能。
运用:
<script type="text/javascript">
var arr = new Array("1", "2", "3", "4");
function filter1(array) {
console.log(array.toString());
var temp=array[2];
var arr2=array.remove(temp);
arr2.push(temp);
filter2.apply(null, arr2);//利用apply的快速切割数组优势传递参数
}
console.log(a,b,c,d);
}
(function() {
filter1(arr);
var com = new Computer("moline", 2, 500);
console.log(com.name + "\nMemory:" + com.memory + "\nStore:" + com.store);
})();
</script>
代码解析:现有一个数组arr,要传递给filter2,由于filter2接受参数类型限制,需要通过filter1处理:
1、将数组的第三个值移动到最后
2、将修改后的数组变成参数列表的形式传递给filter2
同理,以下公共方法利用apply优势,将得到更好的效果:
Array.prototype.push.apply
Math.max