本来是想在这里写写call 和apply的用法,但是我刚在网上看到一篇讨论,感觉比较讲得彻底,拿过来吧 ,自己又懒了一把,
<script type="text/javascript"> </script> <script class="blogstory"> </script>
function foo(x) {
this.x = x;
var y = "Just a y";
}
function bar(foo) {
return function() {
var temp = {};
foo.apply(temp, arguments);
alert("In bar now");
alert("temp.foo:" + temp.foo + "/n" +
"temp.x:" + temp.x + "/n" +
"temp.y:" + temp.y);//注意看这一行的执行结果
}
}
var func = bar(foo);
func("In foo now");
试验结果表明:apply以后,temp对象就继承了foo类的公有变量了。也就是说,这一句 foo.apply(temp, arguments);实际上就是把foo()函数当成temp对象的构造函数来调用了。一旦构造完毕,temp对象就具有了成员this.x。
这样,我有了两种理解方案:
①按照传统的面向对象的语言来理解:一般来说,构造函数是不能被外界(不包括派生类)访问的。因此,这句话“调用apply时,是把foo函数变成temp对象的方法,然后调用”是正确的,而“可是temp.foo竟然没有定义”则是理所当然的事情了。
②按照JavaScript语言自身的对象机制来理解:在JavaScript中,(构造 )函数就是国王、一等公民,它就是类就是它。对象则是(构造)函数的实例。因此,通过对象来访问构造函数,显然是行不通的。
其实,说构造未必准确(但我们可以利用构造函数来理解这个处理过程),我认为应该说成克隆,也就是说系统把foo类拥有的所有公有变量复制给了temp对象(这里是指Object,Function,Array和包装型对象“四类”对象)。
蓝色的文字表明,如果temp不是一个对象型(指以上提到的四类对象)变量的话,克隆过程就不会发生,如下所示:
foo.apply(0, arguments);
foo.apply(null, arguments);
foo.apply(undefined, arguments);
foo.apply(true, arguments);
foo.apply("hello,world", arguments);
foo.apply({}, arguments);
那么foo.apply()实际上就和普通的方法调用没有什么区别了,只是有了它,我们可以利用传递arguments参数的便利。
所以,apply(和call)的应用场合就浮现出来了:
①我们需要把一个类的公有变量复制给另一个对象。
②我们要快速而“智能”的传参,而不是手动去书写arguments[0],arguments[1]...
问一个函数与函数之间传参数的问题,我觉得我这种方法太麻烦,不知道大家还有没有更好的方法.
如果按传统的方式来,得这样写:
function user( ) {
test(arguments[0], arguments[1]);
}
function test(id,name) {
alert(id +"-----------"+name);
}
user("dfdfd","kkkkk");
这样写的缺点很明显,万一参数一变,程序就挂了。
而利用apply,程序就变聪明多了:
function user( ) {
test.apply(0, arguments);
}
function test(id,name) {
alert(id +"-----------"+name);
}
user("dfdfd","kkkkk");
apply(...)和call(...)确实很实用,比如实现一个类创建模式
<script type="text/javascript">
<!--
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
};
var vehicle = Class.create();
vehicle.prototype = {
initialize: function(type){
this.type=type;
},
showSelf: function(){
alert("this vehicle is "+ this.type);
}
};
var moto=new vehicle("Moto");
moto.showSelf();
//-->
</script>
一个跨框架调用的例子
在View框架中有三个测试button,点击分别对应三种调用方式,第一种是通过最原始的obj.fn()来调用Controller框架中的fn函数,第二种是比较原始的eval拼装arguments跨框架字符串,第三种是改写的apply方法应用~
/**
* index.htm
*/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd ">
<html xmlns="http://www.w3.org/1999/xhtml ">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>测试跨框架调用-apply()应用</title>
</head>
<frameset rows="*,80" frameborder="1" border="1" framespacing="1">
<frame src="view.htm" name="main_frame" id="main_frame" />
<frame src="controller.htm" name="js_frame" id="js_frame" />
</frameset>
<noframes>
<body> UnSupport Frame Structure! </body>
</noframes>
</html>
/**
* view.htm
*/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
<html xmlns="http://www.w3.org/1999/xhtml ">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>:::View:::</title>
<script type="text/javascript">
<!--
// Cross Frames Function
var fFunc = function(){
try{
var iLen = arguments.length;
if(iLen == 0) return;
else{
var sFuncStr = "top.frames['js_frame'].";
sFuncStr += arguments[0] + "(";
for(var i=1; i<iLen; i++){
sFuncStr += "'" + arguments[i] + "',";
}
sFuncStr = sFuncStr.substring(0, sFuncStr.length-1);
sFuncStr += ");";
eval(sFuncStr);
}
}
catch(ex){
window.alert("Error: " + ex.description);
}
};
// Cross Frames Function Apply
var fGoto = function(){
try{
var sFuncStr = "top.frames['js_frame'].";
var arr = [];
for(var i=0; i<arguments.length; i++){
arr[i] = arguments[i];
}
arr = arr.slice(1);
var func = eval(sFuncStr + arguments[0]);
func.apply(window, arr);
}
catch(ex){
window.alert("Error: " + ex.description);
}
};
//-->
</script>
</head>
<body>
<input type="button" value="测试1--使用js_frame" οnclick='top.frames["js_frame"].fTest("content-1A", "content-1B")' />
<input type="button" value="测试2--使用fFunc" οnclick='fFunc("fTest", "content-2A", "content-2B")' />
<input type="button" value="测试3--使用apply" οnclick='fGoto("fTest", "content-3A", "content-3B")' />
</body>
</html>
/**
* controller.htm
*/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
<html xmlns="http://www.w3.org/1999/xhtml ">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>:::Controller:::</title>
<script type="text/javascript">
<!--
function fTest(sStr1, sStr2){
window.confirm(sStr1);
window.alert(sStr2);
}
//-->
</script>
</head>
<body>
<p>:::JS Frame:::</p>
</body>
</html>
提一点建议。。。利用apply的那一个函数可以优化如下:
// Cross Frames Function Apply
var fGoto = function(){
try{
var arr = [];
for(var i=0; i<arguments.length; i++){
arr[i] = arguments[i];
}
arr = arr.slice(1);
parent.frames['js_frame'][arguments[0]].apply(0, arr);
}
catch(ex){
window.alert("Error: " + ex.description);
}
};