[toc]javascript
Object.create()
方法的做用:建立一個新對象,使用現有的對象來提供新建立的對象的__proto__(會返回一個新對象,帶着指定的原型對象和屬性)。html
默認狀況下,js中對象的隱式原型__proto__
指向其構造函數的顯示原型prototype
(這裏的指向能夠理解爲屬性與值的關係)java
// 字面量建立對象
let obj1 = {}
obj1.__proto__ === Object.prototype; // true
// 內置構造函數建立對象。等價於new Object();
let obj2 = Object();
obj2.__proto__ === Object.prototype; // true
// 自定義構造函數建立實例對象
let Ctr = function(){};
let obj3 = new Ctr();
obj3.__proto__ === Ctr.prototype; // true
複製代碼
而通過Object.create()
方法建立的對象能夠指定其隱式原型爲一個函數或者對象。node
// 首先自定義一個構造函數並初始化一個實例對象。
function Base(){
this.name = 'cuixiaodao'
}
Base.prototype.say = function (){
console.log(`1:`,1);
}
var base = new Base();
// 建立新對象,指定其隱式原型爲Base
var o1 = Object.create(Base);
o1.__proto__ === Base; // true
// 建立新對象,指定其隱式原型爲base
var o2 = Object.create(base);
o2.__proto__ === base; // true
複製代碼
如圖:segmentfault
能夠看出,Object.create
方法的主要邏輯:建立一個對象,手動設置其隱式原型__proto__
屬性爲傳入的參數,讓後將這個對象返回。函數
這樣看實現過程就比較簡單了。不過Object.create()
方法還能夠接受第二個參數,用來給新建立的對象添加可枚舉屬性,與Object.defineProperies
方法第二個參數用法同樣。ui
這裏咱們本着弄清Object.create
方法主要過程的原則,暫時不考慮第二個參數,對其主要功能作簡單實現。this
function _create(paramProto){
var isObject = (typeof paramProto === 'object') || (typeof paramProto === 'function');
var isUndefined = typeof paramProto === 'undefined';
if (isUndefined || !isObject){
throw new TypeError('Object prototype may only be an Object or null: ' + paramProto)
}
function F() { }
F.prototype = paramProto;
return new F();
}
複製代碼
上面最後三行代碼,返回了F
的實例對象,暫且稱爲f
,那麼也就是f.__proto__ === F.prototype
,而F.prototype = paramProto
,也就作到了f.__proto__ === paramProto
。spa
也能夠理解爲下面的形式prototype
function _create(paramProto) {
return {
__proto__: paramProto
}
}
複製代碼
Object.create()
參數爲對象和函數的區別自定義一個構造函數而且實例化,分別用1Object.create()
建立o一、o2另個對象。
function Base() {
this.name = 'cuixiaodao'
}
Base.age = '18';
Base.prototype.say = function () {
console.log(`1:`, 1);
}
let base = new Base();
let o1 = Object.create(Base);
var o2 = Object.create(base);
console.log(`o1:`,o1);
console.log(`o2:`,o2);
複製代碼
能夠看到o1的隱式原型是Base
,而o2隱式原型是baese
o1.__proto__ === Base; // true
o2.__proto__ === base; // true
複製代碼
o2能夠訪問到base
上的name
屬性及base
經過__proto__
繼承來的say
方法。
o2.name; // cuixiaodao
o2.say(); // 1
複製代碼
可是o1都訪問不到
o1.name; // 'Base'
o1.say; // undefined
複製代碼
函數自帶
name
屬性,也就是函數名,因此這裏返回了函數的名稱Base。相似的還有length
表示函數參數的個數,arguments
表明函數接收的全部參數。
主要是由於原型鏈繼承是經過對象的__proto__
屬性實現的:訪問一個對象的屬性時,先在基本屬性中查找,若是沒有,再沿着__proto__這條鏈向上找,這就是原型鏈。雖然o1.__proto__ === Base
,但因爲say
方法是定義在Base
原型上的,經過o1.__proto__
並訪問不到,因此是undefined。直接在Base
上面定義屬性,o1
是能夠訪問到的。
o1.age; // 18
複製代碼
Object.crete(null)
和{}
Object.crete(null)
會返回一個純淨的對象,不會繼承內置Object
的toString
、valueof
等方法。