通過new操作符構建一個對象,一般經過四步:
A.創建一個新對象
B.將構造函數的作用域賦給新對象(所以this就指向了這個新對象)
C.執行構造函數中的代碼
D.返回這個新對象
最後一點就說明了,我們只要返回一個新對象即可。其實new操作符主要是把原型鏈跟實例的this關聯起來,這纔是最關鍵的一點,所以我們如果需要原型鏈就必須要new操作符來進行處理。否則this則變成window對象了。
我們來剖析下jQuery的這個結構,以下是我們常見的類式寫法:
var $$ = ajQuery = function(selector) { this.selector = selector; return this } ajQuery.fn = ajQuery.prototype = { selectorName:function(){ return this.selector; }, constructor: ajQuery } var a = new $$('aaa'); //實例化 a.selectorName() //aaa //得到選擇器名字
首先改造jQuery無new的格式,我們可以通過instanceof判斷this是否爲當前實例:
var $$ = ajQuery = function(selector) { if(!(this instanceof ajQuery)){ return new ajQuery(selector); } this.selector = selector; return this }
但是注意千萬不要像下面這樣寫:
var $$ = ajQuery = function(selector) { this.selector = selector; return new ajQuery(selector); } Uncaught RangeError: Maximum call stack size exceeded
這樣會無限遞歸自己,從而造成死循環並且溢出。
jQuery爲了避免出現這種死循環的問題,採取的手段是把原型上的一個init方法作爲構造器
var $$ = ajQuery = function(selector) { //把原型上的init作爲構造器 return new ajQuery.fn.init( selector ); } ajQuery.fn = ajQuery.prototype = { name: 'aaron', init: function() { console.log(this) }, constructor: ajQuery }
這樣確實解決了循環遞歸的問題,但是又問題來了,init是ajQuery原型上作爲構造器的一個方法,那麼其this就不是ajQuery了,所以this就完全引用不到ajQuery的原型了,所以這裏通過new把init方法與ajQuery給分離成2個獨立的構造器。