zoukankan      html  css  js  c++  java
  • JS-call和apply(一)

    作者:zccst

    2014-6-10
    昨天对Array.prototype.slice.call(arguments);还是不太理解,不知道为什么slice调用时,可以将arguments切为数组。

    今天理解call(this, args);中的this是一个对象。而不是一个函数function(){}。
    Js代码  收藏代码
    1. var test1 = {  
    2.     age : 10,  
    3.     sum : function(){  
    4.         return this.age;  
    5.     }  
    6. }  
    7. console.log(Array.prototype.slice.call(test1));//打印[]  
    8.   
    9.   
    10. function test2(){  
    11.     this.age = 10;  
    12.     this.sum =function(){  
    13.         return this.age;  
    14.     }  
    15. }  
    16. console.log(Array.prototype.slice.call(test2));//打印[]  
    17.   
    18.   
    19. var test3 = {  
    20.     0 : 10,  
    21.     1 : function(){  
    22.         return this[0];  
    23.     },  
    24.     length:2  
    25. }  
    26. console.log(Array.prototype.slice.call(test3));//将类数组对象转换成真正的数组  
    27.   
    28.   
    29. /**/  
    30. function Product(name, price) {  
    31.   this.name = name;  
    32.   this.price = price;  
    33.   
    34.   if (price < 0)  
    35.     throw RangeError('Cannot create product "' + name + '" with a negative price');  
    36.   return this;  
    37. }  
    38.   
    39. function Food(name, price) {  
    40.   console.log(this);//打印?  
    41.   Product.call(this, name, price);  
    42.   this.category = 'food';  
    43. }  
    44. Food.prototype = Object.create(Product.prototype);  
    45.   
    46. function Toy(name, price) {  
    47.   console.log(this);//打印?  
    48.   Product.call(this, name, price);  
    49.   this.category = 'toy';  
    50. }  
    51. Toy.prototype = Object.create(Product.prototype);  
    52.   
    53. var cheese = new Food('feta', 5);  
    54. var fun = new Toy('robot', 40);  
    55. //console.log(cheese);  
    56. //console.log(fun);  





    2014-6-9
    重新看以前call的文章,觉得call应该就是指定某一个函数在某一个作用域中执行。
    比如:Array.prototype.slice.call(arguments);
    jquery的proxy的实现
    Js代码  收藏代码
    1. proxy: function( fn, context ) {  
    2.         var tmp, args, proxy;  
    3.   
    4.         if ( typeof context === "string" ) {  
    5.             tmp = fn[ context ];  
    6.             context = fn;  
    7.             fn = tmp;  
    8.         }  
    9.   
    10.         // Quick check to determine if target is callable, in the spec  
    11.         // this throws a TypeError, but we will just return undefined.  
    12.         if ( !jQuery.isFunction( fn ) ) {  
    13.             return undefined;  
    14.         }  
    15.   
    16.         // Simulated bind  
    17.         args = core_slice.call( arguments, 2 );  
    18.         proxy = function() {  
    19.             return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );  
    20.         };  
    21.   
    22.         // Set the guid of unique handler to the same of original handler, so it can be removed  
    23.         proxy.guid = fn.guid = fn.guid || jQuery.guid++;  
    24.   
    25.         return proxy;  
    26.     }  







    2013-8-21
    call和apply,它们的作用都是将函数绑定到另外一个对象上去运行
    两者的格式和参数定义:
    call( thisArg [,arg1,arg2,… ] );       // 参数列表,arg1,arg2,...
    apply(thisArg [,argArray] );                 // 参数数组,argArray
    上面两个函数内部的this指针,都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的

    一、call 的简单用法
    首先,我们先看个简单的例子(call):
    Html代码  收藏代码
    1. <!doctype html>  
    2. <html>  
    3.     <head>  
    4.         <title> call-apply </title>  
    5.     </head>  
    6.   
    7.     <body>  
    8.         <input type="text" id="idTxt" value="input text">  
    9.           
    10.         <script type="text/javascript">  
    11.             var value = "global var";  
    12.               
    13.             function mFunc()  
    14.             {  
    15.                 this.value = "member var";  
    16.             }  
    17.               
    18.             function gFunc()  
    19.             {  
    20.                 alert(this.value);  
    21.             }         
    22.                                                       
    23.             window.gFunc();                                 // show gFunc, global var  
    24.             gFunc.call(window);                             // show gFunc, global var  
    25.             gFunc.call(new mFunc());                        // show mFunc, member var  
    26.             gFunc.call(document.getElementById('idTxt'));   // show element, input text  
    27.         </script>  
    28.           
    29.         <script language="javascript">  
    30.             var func = new function()  
    31.             {  
    32.                 this.a = "func";  
    33.             }  
    34.               
    35.             var func2 = function(x)  
    36.             {  
    37.                 var a = "func2";  
    38.                 alert(this.a);                
    39.                 alert(x);  
    40.             }  
    41.               
    42.             func2.call(func, "func2");                      // show func and func2  
    43.         </script>  
    44.     </body>  
    45. </html>  

    然后,运行结果如下:
    global var
    global var
    member var
    input text
    func
    func2
    测试环境:Google Chrome 10.0.648.45
    最后,分析结果
    1、全局对象window调用函数gFunc,this指向window对象,因此this.value为global var
    2、函数gFunc调用call方法,this默认指向第一个参数window对象,因此this.value也为global var
    3、函数gFunc调用call方法,this默认指向第一个参数new mFunc(),即mFunc的对象,因此this.value为mFunc的成员变量member var
    4、函数gFunc调用call方法,this默认指向第一个参数input text控件,即id=‘idTxt’的控件,因此this.value为input控件的value值input text
    5、函数func2调用call方法,this默认指向第一个参数func函数对象,因此this.value为this.a,即func
    6、函数func2调用call方法,第二个参数属于函数对象func2的参数,因此alert(x)为第二个参数func2

    二、call 继承用法与改进
    js使用call模拟继承
    测试代码:
    Html代码  收藏代码
    1. <!doctype html>  
    2. <html>  
    3.     <head>  
    4.         <title> call - apply for inherit </title>  
    5.     </head>  
    6.       
    7.     <body>  
    8.         <script type="text/javascript">  
    9.             function baseA()        // base Class A  
    10.             {  
    11.                 this.member = "baseA member";  
    12.                 this.showSelfA = function()  
    13.                 {  
    14.                     window.alert(this.member);  
    15.                 }  
    16.             }  
    17.               
    18.             function baseB()        // base Class B  
    19.             {  
    20.                 this.member = "baseB member";  
    21.                 this.showSelfB = function()  
    22.                 {  
    23.                     window.alert(this.member);  
    24.                 }  
    25.             }  
    26.               
    27.             function extendAB()     // Inherit Class from A and B  
    28.             {  
    29.                 baseA.call(this);   // call for A  
    30.                 baseB.call(this);   // call for B  
    31.             }  
    32.               
    33.             window.onload = function()  
    34.             {  
    35.                 var extend = new extendAB();      
    36.                 extend.showSelfA();     // show A  
    37.                 extend.showSelfB();     // show B  
    38.             }  
    39.         </script>  
    40.     </body>  
    41. </html>  

    运行结果如下:
    baseB member
    baseB member
    测试环境:Google Chrome 10.0.648.45
    结果分析:
    预期的结果,应该是输出 baseA member 和 baseB member,但实际输出却是 baseB member 和 baseB member
    (已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等浏览器测试过,结果都是后者:baseB member)
    至此,机器是不会错的,这就需要我们深入分析
    我们可能会很容易想到是this引起的,this两次都指向了baseB对象,但是推测真是这样吗?
    为了探究实质,我们借助chrome浏览器的调试工具,下断点,进行调试,结果发现:

    当调用extend.showSelfA();时,此时的this指向extendAB(并不是我们推测的两次都指向baseB对象)
    真实原因是extendAB对象的成员变量member在被baseB.call(this);实例化时,被baseB的成员member覆盖了,即extendAB的成员member由baseA member赋值成了baseB member
    当然,我们也可以对上面baseA代码稍作修改,来验证我们调试分析的正确性:
    Js代码  收藏代码
    1. function baseA()        // base Class A  
    2. {  
    3.     this.memberA = "baseA member";   // member改成memberA,以区分baseB中的member  
    4.     this.showSelfA = function()  
    5.     {  
    6.         window.alert(this.memberA);    // 显示memberA  
    7.     }  
    8. }  

    再次运行chrome等浏览器,结果如下:
    baseA  member
    baseB member
    结果和我们的预期相同,同时chrome调试信息也验证了我们的正确性:



    继承改进(prototype)
    以上模拟继承方法,仔细分析不是最好的。
    因为每次在函数(类)中定义了成员方法,都会导致实例有副本,因此可以借助prototype原型,进行改进
    改进举例如下:
    Html代码  收藏代码
    1. <!doctype html>  
    2. <html>  
    3.     <head>  
    4.         <title> call - apply for prototype </title>  
    5.     </head>  
    6.       
    7.     <body>  
    8.         <script type="text/javascript">  
    9.             var Class = {  
    10.                 create: function()              // create Function  
    11.                 {  
    12.                     return function()  
    13.                     {  
    14.                         this.initialize.apply(this, arguments);  
    15.                     }  
    16.                 }  
    17.             };  
    18.               
    19.             var Person = Class.create();        // Create Class Person  
    20.             /*相当于  
    21.             var Person = function(){  
    22.                 this.initialize.apply(this, arguments);  
    23.             }  
    24.             */  
    25.             Person.prototype = {                // prototype initialize  
    26.                 initialize: function(obj1, obj2)  
    27.                 {  
    28.                     this.obj1 = obj1;  
    29.                     this.obj2 = obj2;  
    30.                 },  
    31.                 showSelf: function()  
    32.                 {  
    33.                     alert("obj: " + this.obj1 + " and " + this.obj2);  
    34.                 }  
    35.             }  
    36.               
    37.             // instance Class  
    38.             var person = new Person("man", "women");    // two params  
    39.             person.showSelf();                          // show person  
    40.         </script>  
    41.     </body>  
    42. </html>  

    运行结果如下:
    obj: man and women
  • 相关阅读:
    测试
    微商就该这么加粉丝,你造吗?
    下拉刷新ListView实现原理
    android studio出现 waiting for adb
    发现一个很好的android开发笔记库
    android studio 不能在线更新android SDK Manager问题解决办法
    asp.net中XmlDocument解析出现出错,处理特殊字符
    假如是你,你会怎么选择
    winrt 上的翻书特效组件 源码分享 转载请说明
    在Windows8 Winrt中 高性能处理多个条件语句 用于实现自定义手势
  • 原文地址:https://www.cnblogs.com/shsgl/p/4289866.html
Copyright © 2011-2022 走看看