JS:構造函數、原型、new

構造函數、原型對象、實例

1、每個函數都有一個prototype屬性,該屬性指向函數的原型對象,原型對象的用途是可以讓所有對象實例共享它所包含的屬性和方法。

2、默認情況下,每個原型對象都會自動獲得一個constructor屬性,該屬性指向prototype屬性所在的函數。constructor屬性最初是用來標識對象類型的,但檢測對象類型,還是instanceof更可靠些(因爲對象的constructor可被改寫,指向的函數不同於原型對象construtor指向的函數):

person1 instanceof Person // 檢測Person.prototype是否在person1的原型鏈上,在就返回true。

3、當調用構造函數創建一個對象實例後,該實例的內部將包含一個指針[[Prototype]](內部屬性),指向構造函數的原型對象。Firefox、Safari和Chrome等瀏覽器在每個對象上都加了一個__proto__,來訪問[[Prototype]],而在其他實現中,這個屬性則完全不可見。對象實例和構造函數沒有直接關係。可以通過isPrototypeOf()來確定是否爲對象的原型對象:

Person.prototype.isPrototypeOf(person1);

ES5中增加了新方法Object.getPrototypeOf(),返回[[Prototype]]的值(IE 9+,Firefox 3.5+,Safari 5+,Opera 12+,Chrome):

Object.getPrototypeOf(person1) === Person.prototype // true

4、讀取對象某個屬性時,會先搜索該對象實例,如果找到同名屬性,返回該屬性值;如果沒有找到,繼續搜索該對象的原型對象,這是多個對象實例共享原型對象屬性和方法的基本原理。對象實例中的屬性會屏蔽原型對象中的同名屬性,使用delete操作符可以刪除實例屬性,從而能重新訪問原型中的屬性。

function Person() {}
Person.prototype.name = 'Nicholas';
Person.prototype.sayName = function () { 
    alert(this.name); 
}

let person1 = new Person();
let person2 = new Person();

person1.name = 'Greg';
alert(person1.name); // 'Greg'
alert(person2.name); // 'Nicholas'

delete person1.name;
alert(person1.name); // 'Nicholas

hasOwnProperty():若屬性爲實例屬性,返回true:

person1.hasOwnProperty('name') // 如果person1實例本身有name屬性,返回true

in操作符:無論該屬性在實例中還是原型中,只要能通過對象訪問,就返回true。

'name' in person1 // 檢測person1是否有name屬性,無論是實例還是原型屬性

for-in: 返回的是所有能通過對象訪問的、可枚舉的屬性,包括實例屬性和原型屬性。屏蔽了原型中不可枚舉屬性的實例屬性也會被返回,因爲按規定,開發人員定義的屬性都是可枚舉的(IE8及更早版本中例外)。

Object.keys():返回對象上所有可枚舉的實例屬性(IE 9+,Firefox 4+,Safari 5+,Opera 12+ 和 Chrome)。

Object.getOwnPropertyNames():返回對象上所有實例屬性,包括不可枚舉的(IE 9+,Firefox 4+,Safari 5+,Opera 12+ 和 Chrome)。

用new創建實例時經歷的步驟

  1. 創建一個空的js對象,即{};
  2. 將該空對象[[Prototype]]屬性鏈接到構造函數的原型對象 ;
  3. 將步驟1新創建的對象作爲this的上下文 ;
  4. 執行構造函數內的代碼(爲這個新對象添加屬性);
  5. 如果該函數沒有返回對象,則返回this

用代碼示意,記函數A爲構造函數, new A() 實際做了如下事情:

let obj = {};
obj.__proto__ = A.prototype;
return A.call(obj) || obj;

1、new的過程中並不涉及constructor屬性。改變A.prototype.constructor,也不影響new A()的執行過程:

function A () { console.log('A'); }
function B () { console.log('B'); }
B.prototype.constructor = A;
let b = new B(); // 'B'
console.log(b.__proto__ === B.prototype); // true
console.log(b.construtor === A); // true

2、new A也可以創建實例,和new A()的區別是new A不可以傳入參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章