做者:zccst
2014-6-10
昨天對Array.prototype.slice.call(arguments);仍是不太理解,不知道爲何slice調用時,能夠將arguments切爲數組。
今天理解call(this, args);中的this是一個對象。而不是一個函數function(){}。
- var test1 = {
- age : 10,
- sum : function(){
- return this.age;
- }
- }
- console.log(Array.prototype.slice.call(test1));
-
-
- function test2(){
- this.age = 10;
- this.sum =function(){
- return this.age;
- }
- }
- console.log(Array.prototype.slice.call(test2));
-
-
- var test3 = {
- 0 : 10,
- 1 : function(){
- return this[0];
- },
- length:2
- }
- console.log(Array.prototype.slice.call(test3));
-
-
- function Product(name, price) {
- this.name = name;
- this.price = price;
-
- if (price < 0)
- throw RangeError('Cannot create product "' + name + '" with a negative price');
- return this;
- }
-
- function Food(name, price) {
- console.log(this);
- Product.call(this, name, price);
- this.category = 'food';
- }
- Food.prototype = Object.create(Product.prototype);
-
- function Toy(name, price) {
- console.log(this);
- Product.call(this, name, price);
- this.category = 'toy';
- }
- Toy.prototype = Object.create(Product.prototype);
-
- var cheese = new Food('feta', 5);
- var fun = new Toy('robot', 40);
2014-6-9
從新看之前call的文章,以爲call應該就是指定某一個函數在某一個做用域中執行。
好比:Array.prototype.slice.call(arguments);
jquery的proxy的實現
- proxy: function( fn, context ) {
- var tmp, args, proxy;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
-
-
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
-
- args = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
- };
-
-
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- }
2013-8-21
call和apply,它們的做用都是將函數綁定到另一個對象上去運行
二者的格式和參數定義:
call( thisArg [,arg1,arg2,… ] ); // 參數列表,arg1,arg2,...
apply(thisArg [,argArray] ); // 參數數組,argArray
上面兩個函數內部的this指針,都會被賦值爲thisArg,這可實現將函數做爲另一個對象的方法運行的目的
1、call 的簡單用法
首先,咱們先看個簡單的例子(call):
- <!doctype html>
- <html>
- <head>
- <title> call-apply </title>
- </head>
-
- <body>
- <input type="text" id="idTxt" value="input text">
-
- <script type="text/javascript">
- var value = "global var";
-
- function mFunc()
- {
- this.value = "member var";
- }
-
- function gFunc()
- {
- alert(this.value);
- }
-
- window.gFunc(); // show gFunc, global var
- gFunc.call(window); // show gFunc, global var
- gFunc.call(new mFunc()); // show mFunc, member var
- gFunc.call(document.getElementById('idTxt')); // show element, input text
- </script>
-
- <script language="javascript">
- var func = new function()
- {
- this.a = "func";
- }
-
- var func2 = function(x)
- {
- var a = "func2";
- alert(this.a);
- alert(x);
- }
-
- func2.call(func, "func2"); // show func and func2
- </script>
- </body>
- </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模擬繼承
測試代碼:
- <!doctype html>
- <html>
- <head>
- <title> call - apply for inherit </title>
- </head>
-
- <body>
- <script type="text/javascript">
- function baseA() // base Class A
- {
- this.member = "baseA member";
- this.showSelfA = function()
- {
- window.alert(this.member);
- }
- }
-
- function baseB() // base Class B
- {
- this.member = "baseB member";
- this.showSelfB = function()
- {
- window.alert(this.member);
- }
- }
-
- function extendAB() // Inherit Class from A and B
- {
- baseA.call(this); // call for A
- baseB.call(this); // call for B
- }
-
- window.onload = function()
- {
- var extend = new extendAB();
- extend.showSelfA(); // show A
- extend.showSelfB(); // show B
- }
- </script>
- </body>
- </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代碼稍做修改,來驗證咱們調試分析的正確性:
- function baseA()
- {
- this.memberA = "baseA member";
- this.showSelfA = function()
- {
- window.alert(this.memberA);
- }
- }
再次運行chrome等瀏覽器,結果以下:
baseA member
baseB member
結果和咱們的預期相同,同時chrome調試信息也驗證了咱們的正確性:
繼承改進(prototype)
以上模擬繼承方法,仔細分析不是最好的。
由於每次在函數(類)中定義了成員方法,都會致使實例有副本,所以能夠藉助prototype原型,進行改進
改進舉例以下:
- <!doctype html>
- <html>
- <head>
- <title> call - apply for prototype </title>
- </head>
-
- <body>
- <script type="text/javascript">
- var Class = {
- create: function() // create Function
- {
- return function()
- {
- this.initialize.apply(this, arguments);
- }
- }
- };
-
- var Person = Class.create(); // Create Class Person
- /*至關於
- var Person = function(){
- this.initialize.apply(this, arguments);
- }
- */
- Person.prototype = { // prototype initialize
- initialize: function(obj1, obj2)
- {
- this.obj1 = obj1;
- this.obj2 = obj2;
- },
- showSelf: function()
- {
- alert("obj: " + this.obj1 + " and " + this.obj2);
- }
- }
-
- // instance Class
- var person = new Person("man", "women"); // two params
- person.showSelf(); // show person
- </script>
- </body>
- </html>
運行結果以下: obj: man and women