標籤:
問題1 Jquery 中建立對象的奧秘
問題2 JavaScript中this的指向問題
問題3 return this 的作用
問題4 instanceof / 對象和類之間的關係
//代碼1(Jquery 建立對象)
var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){name="iQueryPrototypeInit"; //5return this; //2},name : "iQueryPrototype" //6};iQuery.prototype.init.prototype=iQuery.prototype; //3
這時我有問題了,//1 處有無new 的區別。//2 處有無 return this 的區別。 //3處的作用
在這裡我通過對//代碼1 進行分解來回答 問題1 到 問題4
//代碼2 我將//代碼1 中的 //3 處去掉 //2 處去掉 //1 處去掉
var iQuery=function (){name="iQuery";return iQuery.prototype.init();};iQuery.prototype={init : function(){name="iQueryPrototypeInit"; //5},name : "iQueryPrototype"};iQuery().name; //結果為 VM105:1 Uncaught TypeError: Cannot read property ‘name‘ of undefined(…)
分析: iQuery.prototype.init() 是調用了init函數,由於函數沒有傳回值,所以只返回了控制
所以 return iQuery.prototype.init() 也沒有傳回值 所以 iQuery().name;會有以上錯誤提示
//代碼3
var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){name="iQueryPrototypeInit"; //5},name : "iQueryPrototype" //6};iQuery().name; //結果為 undefined 這裡並不提示錯誤,而是說name沒有定義;
分析: //4處 name為iQuery 的局部變數,//5 處name是init的局部變數 執行 iQuery()
時建立了一個init的對象,這時init是建構函式,執行時流程
1 建立一個對象
2 返回建立的對象
這就是有無 new 的區別
//代碼4 多了個this
var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){this.name="iQueryPrototypeInit"; //5},name : "iQueryPrototype" //6};iQuery().name; //結果為 iQueryPrototypeInit
分析: 執行 iQuery().name;執行流程
1 建立一個對象
2 讓 this 引用這個對象
3 為 this 所引用的對象添加屬性 name
4 返回 this 所引用的對象
iQuery() instanceof iQuery //false
iQuery() instanceof iQuery.prototype //VM125:1 Uncaught TypeError: Right-hand side of ‘instanceof‘ is not callable(…)
說 iQuery.prototype 是一個對象 instanceof 右邊必須是類,即函數名
iQuery() instanceof iQuery.prototype.init; //true
這裡調用 iQuery() 是建立了init的一個對象。
//代碼5 多了//2
var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){this.name="iQueryPrototypeInit"; //5return this; //2},name : "iQueryPrototype" //6};iQuery().name; //結果為 iQueryPrototypeInit
分析: 執行 iQuery().name;執行流程
1 建立一個對象
2 讓 this 引用這個對象
3 為 this 所引用的對象添加屬性 name
4 返回 this 所引用的對象
iQuery() instanceof iQuery //false
iQuery() instanceof iQuery.prototype //VM125:1 Uncaught TypeError: Right-hand side of ‘instanceof‘ is not callable(…)
說 iQuery.prototype 是一個對象 instanceof 右邊必須是類,即函數名
iQuery() instanceof iQuery.prototype.init; //true
這裡調用 iQuery() 是建立了init的一個對象。
總結1 如果使用new建立對象加不加 return this 是一樣的。
//代碼6 去掉//1 處的 new //2處有 return this
var iQuery=function (){name="iQuery"; //4return iQuery.prototype.init(); //1};iQuery.prototype={init : function(){this.name="iQueryPrototypeInit"; //5return this; //2},name : "iQueryPrototype" //6};iQuery().name; // iQueryPrototypeInit
如果去掉 //5
iQuery().name; // iQueryPrototype
分析: 執行 iQuery() 返回了 iQuery.prototype 這個由字面常量建立的對象
如果沒有去掉 //5 則給 iQuery.prototype 添加了 name 屬性覆蓋了原有的name
在這裡 iQuery.prototype.init() 是 iQuery.prototype 這個對象調用了 init 函數
所以 init 的 this 指向了 iQuery.prototype
結論2: 函數中的 this 始終指向直接調用它的對象 ,注意是直接,為什麼說是直接 請看 //代碼6
//代碼7
var iQuery=function (){name="iQuery"; //4return iQuery.prototype.init(); //1};iQuery.prototype={init : function(){return this; //2},name : "iQueryPrototype" //6};var temp ={};temp.name="temp";temp.sayName=iQuery().init; // 等價於 temp.sayName=iQuery.prototype.init;temp.name; // 結果 temptemp.sayName.name; // 結果 temp
分析: 執行 temp.sayName=iQuery().init; 為對象 temp 添加了一個 sayName 方法,
sayName 引用了 iQuery().init/temp.sayName=iQuery.prototype.init
這時 init 中的 return this 這個 this 指向 temp 因為是 temp 直接調用 init
總結: JavaScript中的 this 是上下文 這個上下文特指是函數的上下文,就是函數所屬的對象
JavaScript中的 bind,call,apply 方法都能切換 函數的上下文,這和代碼 //6 的原理相同
都是改變 this 的指向,所以叫做環境切換
//代碼8 (本文最重要的點) 對象和類之間的關係(instanceof)
var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){},name : "iQueryPrototype" //6};iQuery.prototype.init.prototype=iQuery.prototype; //3
注意 增加了 //3
這是執行:
a: iQuery() instanceof iQuery().init; //true
b: iQuery() instanceof iQuery; //true;
如果去掉 //3
c: iQuery() instanceof iQuery; //false;
分析: 我調用 iQuery() 建立的明明是 構造器 init 的對象啊 a:的結果才是符合邏輯的結果,b: 是什麼鬼啊,和他有毛關係啊
請看 //代碼9 //代碼10
//代碼9
var pro={};var A=function(){};A.prototype=pro;var B=function(){};B.prototype=pro;var a=new A();var b=new B();執行:a instanceof A; //truea instanceof B; //trueb instanceof A; //trueb instanceof B; //true
//代碼10
var pro={};var A=function(){};A.prototype=pro;var B=function(){};B.prototype=pro;var a=new A();var b=new B();var C=function(){};C.prototype=a;var c=new C();c instanceof A; //truec instanceof B; //truec instanceof C; //true
分析: 看到這裡大家一定會明白Jquery的設計者為什麼加 iQuery.prototype.init.prototype=iQuery.prototype;
雖然源碼中用了 fn 但是 fn 就是 Jquery.prototype
我給出我的結論
結論3: JavaScript 中的對象和類(即 構造器) 之間除了 對象的_proto_ 屬性指向了 類(構造器)指定的 prototype之外,
對象和類之間沒有更多的關係。類型完全由 prototype 決定。具有相同 prototype 的所有構造器的對象都具有相同的
類型
最後: Jquery中的init中有 return this 對於使用 new 函數名() 這樣的方式建立對象有無 return this 是一樣的。那Jquery
為什麼加啊,因為Jquery中的很多其它方法可以進行 鏈式調用,這些方法中通過 return this 返回由 init建立的對象,為了
保持一致 所以 init中的 return this 真的可以去掉。
對於使用 new 函數名() 建立 對象 return this 和無傳回值一樣因為預設就會返回 this。
return 基本類型,則 return 會被忽略依然 return this。
如果 return 參考型別 那麼返回結果就是 參考型別的對象。
由Jquery建立對象引發的思考