js-20170819-prototype對象
阿新 • • 發佈:2017-09-12
get 函數返回 上層 bsp scrip com 常用方法 完全 判斷 1. 概述
1.1 構造函數的缺點
JavaScript 通過構造函數生成新對象,因此構造函數可以視為對象的模板。實例對象的屬性和方法,可以定義在構造函數內部
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function () {
console.log(‘mew, mew, mew...‘);
};
}
var cat1 = new Cat(‘大毛‘, ‘白色‘);
var cat2 = new Cat(‘二毛‘, ‘黑色‘);
cat1.meow === cat2.meow
// false
上面代碼中,cat1和cat2是同一個構造函數的實例。但是,它們的meow方法是不一樣的,就是說每新建一個實例,就會新建一個meow方法。這既沒有必要,又浪費系統資源,因為所有meow方法都是同樣的行為,完全應該共享。
1.2 prototype 屬性的作用
JavaScript 的每個對象都繼承另一個對象,後者稱為“原型”(prototype)對象。只有null除外,它沒有自己的原型對象
原型對象上的所有屬性和方法,都能被派生對象共享。這就是 JavaScript 繼承機制的基本設計
通過構造函數生成實例對象時,會自動為實例對象分配原型對象。每一個構造函數都有一個prototype屬性,這個屬性就是實例對象的原型對象
當實例對象本身沒有某個屬性或方法的時候,它會到構造函數的prototype屬性指向的對象,去尋找該屬性或方法。這就是原型對象的特殊之處。
原型對象的作用,就是定義所有實例對象共享的屬性和方法。這也是它被稱為原型對象的原因,而實例對象可以視作從原型對象衍生出來的子對象
1.3 原型鏈
所有對象的原型最終都可以上溯到Object.prototype,即Object構造函數的prototype屬性指向的那個對象。那麽,Object.prototype對象有沒有它的原型呢?回答可以是有的,就是沒有任何屬性和方法的null對象,而null對象沒有自己的原型
“原型鏈”的作用是,讀取對象的某個屬性時,JavaScript 引擎先尋找對象本身的屬性,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的Object.prototype還是找不到,則返回undefined
需要註意的是,一級級向上,在原型鏈尋找某個屬性,對性能是有影響的。所尋找的屬性在越上層的原型對象,對性能的影響越大。如果尋找某個不存在的屬性,將會遍歷整個原型鏈。
舉例來說,如果讓某個函數的prototype屬性指向一個數組,就意味著該函數可以當作數組的構造函數,因為它生成的實例對象都可以通過prototype屬性調用數組方法
1.4 constructor 屬性
prototype對象有一個constructor屬性,默認指向prototype對象所在的構造函數。
function P() {}
P.prototype.constructor === P
// true
由於constructor屬性定義在prototype對象上面,意味著可以被所有實例對象繼承。
2. instanceof 運算符
instanceof運算符返回一個布爾值,表示指定對象是否為某個構造函數的實例。
var v = new Vehicle();
v instanceof Vehicle // true
instanceof運算符的左邊是實例對象,右邊是構造函數。它會檢查右邊構建函數的原型對象,是否在左邊對象的原型鏈上。因此,下面兩種寫法是等價的。
v instanceof Vehicle
// 等同於
Vehicle.prototype.isPrototypeOf(v)
3. Object.getPrototypeOf()
Object.getPrototypeOf方法返回一個對象的原型。這是獲取原型對象的標準方法。
// 空對象的原型是Object.prototype
Object.getPrototypeOf({}) === Object.prototype
// true
// 函數的原型是Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype
// true
// f 為 F 的實例對象,則 f 的原型是 F.prototype
var f = new F();
Object.getPrototypeOf(f) === F.prototype
// true
4. Object.setPrototypeOf()
Object.setPrototypeOf方法可以為現有對象設置原型,返回一個新對象。
Object.setPrototypeOf方法接受兩個參數,第一個是現有對象,第二個是原型對象。
var a = {x: 1};
var b = Object.setPrototypeOf({}, a);
// 等同於
// var b = {__proto__: a};
b.x // 1
5. Object.create()
生成實例對象的常用方法,就是使用new命令,讓構造函數返回一個實例。但是很多時候,只能拿到一個實例對象,它可能根本不是由構建函數生成的,那麽能不能從一個實例對象,生成另一個實例對象呢?
JavaScript 提供了Object.create方法,用來滿足這種需求。該方法接受一個對象作為參數,然後以它為原型,返回一個實例對象。該實例完全繼承繼承原型對象的屬性。
下面三種方式生成的新對象是等價的。
var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype);
var obj3 = new Object();
使用Object.create方法的時候,必須提供對象原型,即參數不能為空,或者不是對象,否則會報錯。
6. Object.prototype.isPrototypeOf()
對象實例的isPrototypeOf方法,用來判斷一個對象是否是另一個對象的原型。
var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
o2.isPrototypeOf(o3) // true
o1.isPrototypeOf(o3) // true
上面代碼表明,只要某個對象處在原型鏈上,isPrototypeOf都返回true。
Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
上面代碼中,由於Object.prototype處於原型鏈的最頂端,所以對各種實例都返回true,只有繼承null的對象除外
7. Object.prototype.__proto__
__proto__屬性(前後各兩個下劃線)可以改寫某個對象的原型對象。
8. 獲取原型對象方法的比較
__proto__屬性指向當前對象的原型對象,即構造函數的prototype屬性。
var obj = new Object();
obj.__proto__ === Object.prototype
// true
obj.__proto__ === obj.constructor.prototype
// true
獲取實例對象obj的原型對象,有三種方法。
obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf(obj)
推薦使用第三種Object.getPrototypeOf方法,獲取原型對象。
var o = new Object();
Object.getPrototypeOf(o) === Object.prototype
// true
js-20170819-prototype對象