原型模式
每個函式都會創建一個prototype屬性,這個屬性是一個物件,包含著由特定參考型別的實體共享的屬性和方法,這個物件就是呼叫建構式創建的物件的原型,好處就是,在它上面定義的屬性和方法可以被物件實體共享,原來在建構式中直接賦值給物件實體的值可以直接賦值給他們的原型,
function Person(){}
Person.prototype.name = '小白'
Person.prototype.age = 22
Person.prototype.job = '開發'
Person.prototype.sayName = function(){ console.log(this.name)}
let person1 = new Person()
person1.sayName() //小白
let person2 = new Person()
person2.sayName() //小白
console.log(person1.sayName == person2.sayName) //true
/**
* 所有的屬性和方法都被添加到Person建構式的prototype屬性中了
* 建構式主體中什么都沒有,使用這種方式定義的屬性和方法是由所有的實體
* 共享的,因此person1和person2訪問的都是相同的屬性和sayName()函式
*/
理解原型
只要是創建一個函式,就會為根據特定的規則為這個函式創建prototype屬性指向原型物件,原型物件又會有一個constructor屬性,指向與之關聯的建構式,比如Person.prototype.constructor 指向的是 Person,因建構式而異,也可能會給原型上創建其他屬性和方法,自定義建構式的時候,原型物件上的有些方法會繼承自Object ,每次呼叫建構式創建一個實體,會暴露一個__proto__屬性,通過這個屬性可以訪問物件的原型,主要是一點,實體與建構式原型之間有直接的聯系,與建構式之間沒有直接的聯系
/**
* 建構式可以是函式宣告也可以是運算式
* function Person(){}
* let Person = function(){}
*/
console.log(Person.prototype)
//{
// constructor:f Person(),
// __proto__:Object
// }
/**
* 建構式有一個prototype屬性參考原型物件
* 原型物件有一個constructor屬性參考建構式
* 兩者回圈參考
*/
console.log(Person.prototype.constructor === Person) //true
/**
* 正常的原型鏈都會終止于Object的原型物件,Object的原型的原型是null
*/
console.log(Person.prototype.__proto__ === Object.prototype) //true
console.log(Person.prototype.__proto__.constructor === Object); // true
console.log(Person.prototype.__proto__.__proto__ === null);
let person1 = new Person()
let person2 = new Person()
/**
* 建構式 實體 原型物件 是三個不同的物件
*/
console.log(perosn1 === Person) //false
console.log(person1 === Person.prototype) //false
console.log(Person.prototype === Person) //false
/**
* 實體的__proto__屬性指向建構式的原型物件
* 建構式通過prototype鏈接到原型物件
*/
console.log(person1.__proto__ === Person.prototype) //true
console.log(person1.__proto__.constructor === Person) //true 建構式與實體之間沒有直接的聯系
/**
* 同一個建構式的兩個實體共享同一個原型物件
*/
console.log(person1.__proto__ === person2.__proto__) //true

Object.getPrototypeOf()可以回傳傳入物件的原型
console.log(Object.getPrototypeOf(person1) ==Person.prototype); //true
console.log(Object.getPrototypeOf(person1).name); //小白
Object 型別還有一個 setPrototypeOf() 方法,可以重寫物件的原型繼承關系
let newProto = {
gender:"男"
}
let person = {
name: '小明'
};
Object.setPrototypeOf(person, newProto);
console.log(person.name);// 小明
console.log(person.gender);// 男
console.log(Object.getPrototypeOf(person) ===newProto); // true
//也可以通過Object.create()創建一個物件并為其指定一個原型
let person = Object.create(newProto);
console.log(Object.getPrototypeOf(person) ===newProto); // true
原型層級
通過物件訪問屬性的時候,會先在物件的自身實體上開始搜索,如果沒有找到的話就會沿著指標找到原型物件,找到了就回傳,如果在實體上添加了與原型中同名的屬性,就會遮住物件原型上的屬性
function Person(){}
Person.prototype.name == '小白'
let person1 = new Person()
let person2 = new Person()
person1.name = '小紅'
console.log(person1.name) //小紅 來自實體
console.log(person2.name) //小白 來自原型
//在實體上找到這個屬性之后就不會再搜索圓形物件,使用delete運算子可以洗掉實體上的屬性
delete person1.name
console.log(person1.name) //小白 來自原型
hasOwnProperty() 方法用于確定某個屬性是在實體上還是在原型物件上,在實體上就會回傳true
person1.name = '小紅'
console.log(person1.hasOwnProperty("name")); //true
console.log(person2.hasOwnProperty("name")); //false
in運算子 可以通過物件訪問指定屬性的時候回傳true 無論屬性在實體上還是在原型上
console.log(person2.hasOwnProperty("name")); //false
console.log('name' in person2); //true
如果要確定某個屬性是否存在于原型上,則可以像下面這樣同時使用 hasOwnProperty() 和 in運算子:
function hasPrototypeProperty(obj,name){
return !obj.hasOwnProperty(name) && (name in obj)
}
要獲得物件上可列舉的實體屬性 Enumerable:true 可以使用Object.keys() 接受一個物件作為引數 回傳這個物件上所有的可列舉的屬性名稱字串組成的陣列
function Person() {}
Person.prototype.name = '小白'
Person.prototype.age = 23
Person.prototype.job = '開發'
console.log(Object.keys(Person.prototype)) //['name','age','job']
如果想列出所有實體屬性,無論是否可以列舉,都可以使用
Object.getOwnPropertyNames() :
Object.getOwnPropertyNames(Person.prototype)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/272263.html
標籤:其他
