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,這可實現將函數做爲另一個對象的方法運行的目的

1、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
最後,分析結果
一、全局對象window調用函數gFunc,this指向window對象,所以this.value爲global var
二、函數gFunc調用call方法,this默認指向第一個參數window對象,所以this.value也爲global var
三、函數gFunc調用call方法,this默認指向第一個參數new mFunc(),即mFunc的對象,所以this.value爲mFunc的成員變量member var
四、函數gFunc調用call方法,this默認指向第一個參數input text控件,即id=‘idTxt’的控件,所以this.value爲input控件的value值input text
五、函數func2調用call方法,this默認指向第一個參數func函數對象,所以this.value爲this.a,即func
六、函數func2調用call方法,第二個參數屬於函數對象func2的參數,所以alert(x)爲第二個參數func2

2、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
(已在IE九、八、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
相關文章
相關標籤/搜索