javascript沒有類的概念,經過函數實現構造函數,經過new運算符來建立對象javascript
function Person(name, age, job) { this.name = name; this.age = age; this.friends = ["A","B"]; this.sayname = function(){ alert(this.name); }; } var P = new Person("P",22,"coder");
Person與普通函數並沒有區別,若是直接調用則是向this(window)對象添加屬性java
用new操做符實現了4個步驟:c++
上述方法稱爲構造函數模式,每個對象互相獨立,其屬性和方法都獨立建立,耗費空間,尤爲是方法,沒必要要獨立建立。閉包
原型模式:每個函數都有一個原型屬性,默認的原型屬性有一個constructor域指向函數,原型爲全部函數new出的對象所共有。相似於c++中的static屬性或方法。下例爲推薦寫法函數
function Person() { this.name = name; this.age = age; this.friends = ["A","B"]; } //原型模式寫法1,在默認prototype上補充 Person.prototype.sayName = function() { alert(this.name); } Person.prototype.startid = 0; //共享 //寫法2,覆蓋默認的prototype Person.prototype = { constructor : Person, // 注意覆蓋寫法應加入constructor屬性 sayName: function(){ alert(this.name); } startid:0 }
全部對象共享Prototype域,而構造函數裏添加的域是獨立的。對象構造完之後若是再給prototype中的域賦值能夠將其覆蓋,注意不是刪除,由於若是將本身新加的delete以後,prototyoe中的就又出現了。this
動態原型模式:在構造函數中解決原型的初始化,只有構造的第一個對象會觸發if條件,填充Person的原型.net
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; if (typeof this.sayName != "function") { // 檢查一個屬性就行 Person.prototype.sayName = fuction() { alert(this.name); } Person.prototype.startid = 0; } }
繼承——利用原型鏈 (不能解決全部子類原型共用一個超類實例的問題,不推薦用)prototype
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function() { return this.property; }; function SubType() { this.subproperty = false; } //繼承 SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function() { return this.subproperty; } var instance = new SubType();
可是,因爲SubType沒有重定義constructor,因此繼承了SuperType的constructor。可是constructor不影響instanceof設計
借用構造函數: 不是new一個父類對象,而是調用構造函數向子類添加父類的域,因此子類沒法訪問父類的原型中的內容,不推薦使用指針
function SuperType() { this.colors = ["red","blue"]; } fuction SubType() { SuperType.call(this); // 借用構造函數,在子類中再構造一次父類 }
組合繼承:調用兩次父類構造函數,效率低,此方法子類的constructor也是錯的
function SuperType(name) { this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function() { alert(this.name); }; function SubType(name, age) { SuperType.call(this,name); // 借用父類構造函數 this.age = age; } SubType.prototype = new SuperType(); //原型繼承 SubType.prototype.sayAge = function() { alert(this.age); }
寄生組合式:推薦使用,用此函數替代組合繼承的的 SubType.prototype = new SuperType();
// 書中寫法,constructor在原型裏 function object(o) { function F(){} F.prototype = o; return new F(); } function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); //拷貝原型 prototype.constructor = subType; //添加constructor subType.prototype = prototype; //指定原型 } //網上的另外一個寫法, 感受也是對的, 區別是constructor不在原型裏。 SubType.prototype = SuperType.prototype; SubType.constructor = SubType;
有關prototype、constructor和__proto__的關係參考下面這篇文章,寫的很清晰
閉包:定義在函數內的函數,內層函數擁有指向外層函數活動記錄的指針,能夠訪問外層函數的變量。
私有權限:用閉包實現,有this的是公有權限,var的是非公有權限
function MyObject() { //私有變量和私有函數 var privateVariable = 10; function privateFunction() { return false; } //特權方法,外界可調用 this.publicMethod = function() { privateVariable++; return privateFunction(); } } var m = new MyObject();
靜態私有:解決上述中函數不共享的問題,私有變量和prototype是共享的
(function(){ //私有 var privateVariable = 10; function privateFunction() { return false; } MyObject = function(value) { //函數中不帶var的變量是全局變量 }; MyObject.prototype.publicMethod = function() { privateVariable++; return privateFunction(); }; })(); var m = new MyObject(value);