一:建立對象
1 工廠模式函數
function createPerson(name, age, jod){ var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.sayName = function(){ console.log(this.name); }; return obj; } var person1 = createPerson('NEVAR', 23, 'Front-end Engineer'); var person2 = createPerson('Amy', 27, 'Doctor');
2 構造函數模式this
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ console.log(this.name); } } var person1 = new Person('NEVAR', 23, 'Front-end Engineer'); var person2 = new Person('Amy', 27, 'Doctor'); //person1和person2都是Person的不一樣實例。 alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true //便是Object的實例也是Person的實例 alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true //構造函數產生的是兩個不一樣實例,同名函數是不相等的 alert(person1.sayName == person2.sayName); //false
3 原型模式prototype
function Person(){ } Person.prototype.name = 'NEVAR'; Person.prototype.age = 23; Person.prototype.job = 'Front-end Engineer'; Person.prototype.sayName = function(){ console.log(this.name); }; var person1 = new Person(); person1.sayName(); //NEVAR var person2 = new Person(); person2.sayName; //NEVAR console.log(person1.sayName == person2.sayName);// true var person3 = new Person(); person3.name = 'PP'; console.log(person3.name); //PP 來自實例 delete person3.name; console.log(person3.name); //NEVAR 來自原型 alert(person1.hasOwnProperty("name")); //false 來自原型 alert(person3.hasOwnProperty("name")); //true 來自實例 alert("name" in person1); //true in操做符的使用 function hasPrototypeProperty (obj, name){ return !obj.hasOwnProperty(name) && (name in obj) } //判斷屬性來自實例 真 而後取反 //而且name屬性存在於obj原型鏈上 說明這個 屬性是屬於prototype的 alert(hasPrototypeProperty(person1,'name')) // true alert(hasPrototypeProperty(person3,'name')) // false alert(Object.keys(Person.prototype)) //"name,age,job,sayName" //Person的可枚舉屬性
不過以上方法太過於麻煩 每次都要寫重複的prototypecode
function Person(){ } Person.prototype = { name : 'NEVAR', age : '23', job : 'Front-end Engineer', sayName : function(){ console.log(this.name); } };
constructor 屬性再也不指向Person 了 指向Object對象
var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true
因而能夠這樣原型鏈
Person.prototype = { constructor : Person, name : 'NEVAR', age : '23', job : 'Front-end Engineer', sayName : function(){ console.log(this.name); } };
原型的動態性原型
var friend = new Person(); Person.prototype.sayHi = function(){ alert('Hi'); } friend.sayHi();//Hi //這時沒有問題,若是咱們重寫原型對象 那麼狀況就不同了 function Person(){ } var friend = new Person(); Person.prototype = { constructor: Person, name : "NEVAR", age : 23, job : "Front-end Engineer", sayName : function () { alert(this.name); } }; friend.sayName(); //error
重寫原型對象切斷了現有原型與任何以前已經存在的對象實例之間的聯繫;它們引用的仍然是最初的原型。io
原型模式也不是沒有缺點。首先,它省略了爲構造函數傳遞初始化參數這一環節,結果全部實例在默認狀況下都將取得相同的屬性值console
對於那些包含基本值的屬性倒也說得過去,畢竟(如前面的例子所示),經過在實例上添加一個同名屬性,能夠隱藏原型中的對應屬性。然而,對於包含引用類型值的屬性來講,問題就比較突出了function
function Person(){ } Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", friends : ["Shelby", "Court"], sayName : function () { alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court,Van" alert(person1.friends === person2.friends); //true
4組合使用構造函數模式和原型模式
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ['Shelby','Court']; } Person.prototype = { constructor : Person, sayName : function(){ console.log(this.name); } } var person1 = new Person('NEVAR', 23, 'Front-end Engineer'); var person2 = new Person('Amy', 27, 'Doctor'); person1.friends.push('Van'); console.log(person1.friends) //'Shelby,Court,Van' console.log(person2.friends) //'Shelby,Court' console.log(person1.friends === person2.friends); // false console.log(person1.sayName === person2.sayName); //true
5動態原型模式
它把全部信息都封裝在了構造函數中,而經過在構造函數中初始化原型(僅在必要的狀況下),又保持了同時使用構造函數和原型的優勢。換句話說,能夠經過檢查某個應該存在的方法是否有效,來決定是否須要初始化原型。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; if(typeof this.sayName != function){ Person.prototype.sayName = function(){ console.log(this.name); } } } var person1 = new Person('NEVAR', 23, 'Front-end Engineer'); friend.sayName();
6寄生構造函數模式
//不使用this和new function Person(name, age, job){ //建立要返回的對象 var o = new Object(); //能夠在這裏添加私有變量和函數 //添加方法 o.sayName = function(){ console.log(name); } return o; }
注意,在以這種模式建立的對象中,除了使用sayName()方法以外,沒有其餘辦法訪問name 的值