javascript的call 和apply的用法

  本来是想在这里写写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);
 }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值