亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入了解js原型模式

 更新時(shí)間:2019年05月30日 09:20:45   作者:伯爵213  
在js中,創(chuàng)建對(duì)象的方式有工廠模式和構(gòu)造函數(shù)模式等,但是,構(gòu)造函數(shù)中的每個(gè)方法都需要在實(shí)例對(duì)象中重新創(chuàng)建一遍,不能復(fù)用,就需要使用原型模式來創(chuàng)建對(duì)象。下面我們來了解一下吧

一、什么是原型模式

在js中,創(chuàng)建對(duì)象的方式有工廠模式和構(gòu)造函數(shù)模式等; 而構(gòu)造函數(shù)模式最大的問題在于:構(gòu)造函數(shù)中的每個(gè)方法都需要在實(shí)例對(duì)象中重新創(chuàng)建一遍,不能復(fù)用,所以為了解決這一個(gè)問題,就需要使用原型模式來創(chuàng)建對(duì)象。
原型模式是把所有實(shí)例共享的方法和屬性放在一個(gè)叫做prototype(原型)的屬性中 ,在創(chuàng)建一個(gè)函數(shù)時(shí)都會(huì)有個(gè)prototype屬性, 這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。

// 構(gòu)造函數(shù)
function Person() {};
// 原型屬性prototype
Person.prototype.name = '張三';
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

1.理解原型對(duì)象

無論什么時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè)prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象,在默認(rèn)的情況下,所有的原型對(duì)象都自動(dòng)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這是一個(gè)指針,指向prototype屬性所在的函數(shù)。創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得constructor屬性;其他的方法則是從Object繼承來的。

當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例對(duì)象后,該實(shí)例的內(nèi)部將包含一個(gè)指針[[Prototype]],指向構(gòu)造函數(shù)的原型對(duì)象。這個(gè)連接存在于實(shí)例和構(gòu)造函數(shù)的原型對(duì)象之間,而不是存在實(shí)例和構(gòu)造函數(shù)之間。

每當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。搜索首先從對(duì)象實(shí)例本身開始。如果在實(shí)例中找到了就返回該屬性的值,沒有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性,如果在原型對(duì)象中找到了這個(gè)屬性,就返回該屬性的值。

雖然可以通過實(shí)例訪問保存在原型中的值,但不能通過實(shí)例對(duì)象重寫原型中的值,如果在實(shí)例中添加一個(gè)在原型中的同名屬性,該屬性會(huì)自動(dòng)屏蔽原型中的屬性,但是不會(huì)修改原型中的屬性,只會(huì)阻止訪問原型中的屬性,通過delete操作符則可以完全刪除實(shí)例屬性,使得可以重新訪問原型中的屬性。

2.原型與in操作符

hasOwnProperty()方法可以檢測(cè)一個(gè)屬性是否存在于實(shí)例對(duì)象中,

// 構(gòu)造函數(shù)
function Person() {
this.age = 16;
};
Person.prototype.name = "張三";
let person1 = new Person();
console.log(person1.hasOwnProperty('name')); // false
console.log(person1.hasOwnProperty('age')); // true

in操作符的使用可以分為兩類,單獨(dú)使用和在for-in循環(huán)使用,在單獨(dú)使用時(shí),in操作符會(huì)在通過對(duì)象能夠訪問給定屬性時(shí)返回true,無論該屬性存在于實(shí)例中還是原型中。

// 構(gòu)造函數(shù)
function Person() {}
Person.prototype.name = 'zhang';
let person1 = new Person();
console.log('name' in person1); // true
person1.age = 14;
console.log('age' in person1); // true

同時(shí)使用hasOwnProperty()方法和in操作符,可以確定該屬性時(shí)在原型上還是在存在于對(duì)象中。

// 構(gòu)造函數(shù)
function Person() {}
function hasPrototypeProperty(object, name) {
return !object.hasOwnProperty(name) && (name in object);
}
Person.prototype.name = "張三";
let person = new Person();
console.log(hasPrototypeProperty(person, 'name')); // true
console.log(hasPrototypeProperty(person, 'age')); // false

使用for-in循環(huán)時(shí),返回的是所有能夠通過對(duì)象訪問的、可枚舉的屬性,其中即包含存在于實(shí)例中的屬性,也包含與存在原型中的屬性。

let o = {
name: 'san',
age: 14,
};
for(let key in o) {
console.log(key);
}

要取得對(duì)象上所有可枚舉的實(shí)例屬性,可以使用Object.keys()方法,接收一個(gè)對(duì)象作為參數(shù),返回一個(gè)包含所有可枚舉屬性的字符串?dāng)?shù)組。

如果想得到所有實(shí)例屬性。無論是否可枚舉,都可以使用Object.getOwnPropertyNames()方法。

3.更簡(jiǎn)單的原型語法

為了減少不必要的輸入和從視覺上更好的封裝原型的功能,常見的做法是用一個(gè)包含所有屬性和方法的對(duì)象字面量來重寫整個(gè)原型對(duì)象。

// 構(gòu)造函數(shù)
function Person() {};
Person.prototype = {
sayHi: function() {
console.log(hi);
},
name: '張三',
};

通過這個(gè)方式會(huì)導(dǎo)致原型對(duì)象中的constructor屬性不在指向Person了。如果constructor的值真的很重要,可以像下面這樣特意將它設(shè)置回適當(dāng)?shù)闹怠?br />

// 構(gòu)造函數(shù)
function Person() {};
Person.prototype = {
constructor: Person,
sayHi: function() {
console.log(hi);
},
name: '張三',
};

但是通過這種方式會(huì)導(dǎo)致對(duì)象的[[Enumerable]]特性被設(shè)置為ture,默認(rèn)情況下,constructor屬性時(shí)不可枚舉的,可以通過Object.defineProperty()解決這個(gè)問題。

// 構(gòu)造函數(shù)
function Person() {};
Person.prototype = {
sayHi: function() {
console.log(hi);
},
name: '張三',
};
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false,
value: Person
}

4.原型的動(dòng)態(tài)性

當(dāng)對(duì)原型對(duì)象所做的任何修改都能夠立即從實(shí)例上反應(yīng)出來。

function Person() {};
var friend = new Person();
Person.prototype.sayHi = function() {
console.log('hi');
};
friend.sayHi(); // hi

但是如果是重寫整個(gè)原型對(duì)象,那么情況就不一樣了。調(diào)用構(gòu)造函數(shù)時(shí)會(huì)為實(shí)例添加一個(gè)指向最初原型的[[prototype]]指針,而把原型修改為另外一個(gè)對(duì)象 就相當(dāng)于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。 實(shí)例中的指針僅指向原型,而不是指向構(gòu)造函數(shù)。

// 構(gòu)造函數(shù)
function Person() {};
var friend = new Person();
Person.prototype = {
constructor: Person,
sayHi: function() {
console.log(hi);
}
};
friend.sayHi(); // Uncaught TypeError: friend.sayHi is not a function

創(chuàng)建了一個(gè)Person的實(shí)例,然后又重寫了其原型對(duì)象。但是在使用sayHi()時(shí)發(fā)生了錯(cuò)誤,這個(gè)時(shí)候?qū)嵗赶虻脑蛯?duì)象是一個(gè)新的對(duì)象。重寫原型對(duì)象切斷了現(xiàn)有原型與之前已經(jīng)存在的對(duì)象實(shí)例直接的聯(lián)系。所以報(bào)錯(cuò)了。

5.原生對(duì)象的原型

原型模式的重要性不僅體現(xiàn)在創(chuàng)建自定義類型方面,就連所有原生的引用類型,都采用這種模式,所有的原生引用類型(Object、Array、String)等,都在其構(gòu)造函數(shù)的原型上定義了方法。可以像修改自定義對(duì)象的原型一樣修改原生對(duì)象的原型。

二、原型模式的缺點(diǎn)

對(duì)于包含引用類型值的屬性來說,所有實(shí)例在默認(rèn)的情況下都會(huì)取得相同的屬性值。

// 構(gòu)造函數(shù)
function Person() {};
// 原型屬性prototype
Person.prototype = {
constructor: Person,
friends: ['張三', '李四'],
}
let person1 = new Person();
let person2 = new Person();
person1.friends.push('王五');
console.log(person1.friends); // ["張三", "李四", "王五"]
console.log(person2.friends); // ["張三", "李四", "王五"]

由于friends存在于Person的原型對(duì)象中,所以person1對(duì)friends的修改也會(huì)通過person2反應(yīng)出來,但是實(shí)例對(duì)象一般都是要有屬于自己的全部屬性,正因?yàn)槿绱?,很少有人單?dú)使用原型模式來創(chuàng)建對(duì)象。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論