function Car () { this.color = "red"; } Car.prototype.sayHi=function(){ console.log('你好') }
var car =new Car(); var car2 = Object.create(Car);
new XXX()時發生了什么?
var obj={}; obj.__proto=Car.prototype Car.call(obj)
第一步,創建了一個空對象obj
第二步,將空對象的__proto__成員指向了Car函數的原型屬性,該原型屬性是一個原型對象,也就意味着obj的原型屬性上擁有了Car.prototype中的屬性或方法
第三步,將Car函數中的this指針指向obj,obj有了Car構造函數中的屬性或方法 ,然后Car函數無返回值或返回的不是對象,直接返回obj,否則返回Car函數中的對象
tip:__proto__是什么
每個對象都有一個[[prototype]}屬性,這個屬性是隱藏屬性,誰創建了它,該屬性就指向誰的prototype屬性,因為是隱藏屬性,不能直接訪問,所以有的瀏覽器提供了一個__proto__屬性來訪問,然而這不是一個標准的訪問方法,所以ES5中用Object.getPrototypeOf函數獲得一個對象的[[prototype]]。ES6中,使用Object.setPrototypeOf可以直接修改一個對象的[[prototype]]
Object.create時發生了什么?
Object.create()
方法創建一個新對象,並使用現有的對象來提供新創建的對象的__proto__,關鍵代碼如下
關鍵代碼如下:
Object.create = function (o) { var F = function () {}; F.prototype = o; var newObj=new F(); return newObj; };
可以看到Object.create內部創建了一個新對象newObj,默認情況下newObj.__proto__== F.prototype,在本例中則重寫了構造函數F的原型屬性,最終的原型關系鏈為newObj.__proto__== F.prototype == o
如果現有的對象是一個構造函數,即var car2=Object.create(Car)會發生什么呢?
console.log(car2.color) //undefined console.log(car2.sayHi()) //undefined
執行代碼發現都是undefined, 為什么會這樣呢?
問題1:因為Object.create內部的新對象是new F()創建的,跟Car構造函數沒有半毛錢的關系,所以自然不能訪問到Car中的屬性了
問題2:調用car2.sayHi()時首先判斷car2對象有沒有相應的方法,如果沒有,則查找car2的原型鏈上有沒有該方法,car2的原型屬性是Car構造函數(可以通過car2.__proto__來證明),構造函數沒有sayHi方法,自然也就是undefined了。
那如果將var car2=Object.create(car)又發生了什么呢?
function Car () { this.color = "red"; this.person={name:'張三'} } Car.prototype.sayHi=function(){ console.log('你好') } var car =new Car(); var car2 = Object.create(car); car2.person.name ='李四' console.log(`car是${car.person.name},car2是${car2.person.name}`)
相當於實現了原型繼承方式(注意不是原型鏈繼承),本質上來說是對一個對象進行了淺拷貝
最終結論:
1. Object.create(o),如果o是一個構造函數,則采用這種方法來創建對像沒有意義
2.Object.create(o),如果o是一個字面量對象或實例對象,那么相當於是實現了對象的淺拷貝