面向對象(OOP)的語言都有一個特點,它們都會有類的這一概念,通過類可以抽象出創建具體相同方法與屬性的對象。但是ECMAScript中是沒有類的概念的,因此它的對象與基於類的語言如java的定義是有所不同的。
在JavaScript世界中函數作爲“一等公民”,它不僅擁有一切傳統函數的使用方式(聲明和調用),而且可以做到像簡單值一樣賦值、傳參、返回,這樣的函數也稱之爲第一級函數。不僅如此,而且還可以通過操作符new來充當類的構造器。
函數在充當類的構造器時,原型prototype是一個重要的概念。prototype是構造函數的一個屬性, 該屬性指向一個對象。而這個對象將作爲該構造函數所創建的所有實例的基引用(base reference), 可以把對象的基引用想像成一個自動創建的隱藏屬性。 當訪問對象的一個屬性時, 首先查找對象本身, 找到則返回;若不, 則查找基引用指向的對象的屬性(如果還找不到實際上還會沿着原型鏈向上查找, 直至到根)。 只要沒有被覆蓋的話, 對象原型的屬性就能在所有的實例中找到。
類一:
function ajQuery() { this.name = 'jQuery'; this.sayName = function(){ return this.name } var a = new ajQuery() var b = new ajQuery() var c = new ajQuery()
類二:
function ajQuery() { this.name = 'jQuery' } ajQuery.prototype = { sayName: function() { return this.name } } var a = new ajQuery() var b = new ajQuery() var c = new ajQuery()
類一與類二產生的結構幾乎是一樣的,而本質區別就是:類二new產生的a、b、c三個實例對象共享了原型的sayName方法,這樣的好處節省了內存空間,類一則是要爲每一個實例複製sayName方法,每個方法屬性都佔用一定的內存的空間,所以如果把所有屬性方法都聲明在構造函數中,就會無形的增大很多開銷,這些實例化的對象的屬性一模一樣,都是對this的引用來處理。除此之外類一的所有方法都是拷貝到當前實例對象上。類二則是要通過scope連接到原型鏈上查找,這樣就無形之中要多一層作用域鏈的查找了。
jQuery對象的構建如果在性能上考慮,所以就必須採用原型式的結構:
jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ); } jQuery.fn = jQuery.prototype = { init:function(){ return this }, jquery: version, constructor: jQuery, ……………… } var a = $() ;
使用原型結構,性能上是得到了優化,但是ajQuery類這個結構與目標jQuery的結構的還是有很大不一致:
☑ 沒有采用new操作符;
☑ return返回的是一個通過new出來的的對象 。