常常会有这样的疑问?Object.create()到底作了什么工做? 像这样两行代码有什么不一样?数组
var obj ={a: 1}
var b = obj
var c = Object.create(obj)
复制代码
咱们来作一点事情,bash
var obj ={a: 1}
var b = obj
console.log(obj.a) // 1
console.log(b.a) // 1
b.a = 2
console.log(obj.a) //2
复制代码
var obj ={a: 1}
var b = Object.create(obj)
console.log(obj.a) // 1
console.log(b.a) // 1
b.a = 2
console.log(obj.a) //1
复制代码
因此咱们立马能够想到Object.create貌似建立了一个新的对象,这个对象继承(关联)了obj的属性,改变新对象的同名属性并不会影响原对象。app
若是直接用“=”来赋值,只是一个对象的引用。函数
那么,为何会这样呢?是由于Object.create()复制了一个新对象么?实际上并非,只是Object.create()返回了一个新的空对象,而且这个空对象的构造函数的原型(prototype)是指向obj的。因此当咱们访问新对象b.a的时候其实是经过原型链访问的obj中的a。ui
当咱们试图修改b.a的时候,这里有一个知识点(对象的遮蔽效应,若是修改对象的一个与原型链同名属性,那么会在当前对象中新建一个改属性,这个属性拥有更高级的访问优先级,因此就会遮蔽原型链中的同名属性)this
因此Object.create的具体内部实现模拟spa
_create = function (o) {
let F = function () {}
F.prototype = o
return new F()
}
复制代码
再来看这个例子prototype
var person = {
friends : ["Van","Louis","Nick"]
};
var anotherPerson = _create(person);
anotherPerson.friends.push("Rob");
var yetAnotherPerson = _create(person);
yetAnotherPerson.friends.push("Style");
alert(person.friends);//"Van,Louis,Nick,Rob,Style"
复制代码
至关于作了一次浅复制,新建立的各个对象其实是会共享原始对象中的引用类型的值,这意味着person.friends不只属于person全部,并且也会被anotherPerson以及yetAnotherPerson共享code
实际上真正的Object.create()还能够传入第二个参数,这个参数与Object.defineProperties方法的第二个参数格式相同, 经过第二个参数是会在新对象中从新建立一个属性的,而后经过属性遮蔽原理避免修改原对象。cdn
var person = {
name : "Van"
};
var anotherPerson = Object.create(person, {
name : {
value : "Louis"
}
});
alert(anotherPerson.name);//"Louis"
复制代码
Object.create(null) 会建立一个真正的空对象,并无继承Object原型链上的方法
var a = {} 这并非一个纯粹的空对象,它会继承原型链上的不少方法
关于new的内部实现模拟
function _new () {
// arguments其实是一个类数组对象,须要转成数组
let args = [].slice.call(arguments)
// 第一个参数是构造函数,把它拿出来
let constructor = args.shift()
// Object.create()返回一个新对象,这个对象的构造函数的原型指向Foo
let context = Object.create(constructor.prototype)
// 在返回的context对象环境中执行构造函数,为新的context添加属性
let result = constructor.apply(context, args)
// 若是Foo显示的返回了一个对象,那么应该直接返回这个对象,而不用理会以上全部的操做,通常不会发生这种状况,可是new的实现的确是这样的逻辑
// 这里之因此判断类型是否为object还要添加 != null 的判断,是由于null的typeof结果也是‘object’
// 不一样的对象在底层都表示为二进制,在Javascript中二进制前三位都为0的话会被判断为Object类型,null的二进制表示全为0,天然前三位也是0,因此执行typeof时会返回"object"
return (typeof result === 'object' && result != null) ? result : context
}
function Foo (name) {
this.name = name
}
Foo.prototype.getName = function() {
console.log(this.name)
}
var a = _new(Foo, 'tom')
a.getName()
复制代码
实际上new操做符, 就是经过Object.ctreate()建立一个新的对象,这个对象的原型指向构造函数,而且在新建对象的上下文环境中执行构造函数,初始化新建对象的属性。
固然这里的实现只是一个模拟实现,至于就是内部真正的实现方式必然是复杂得多。好比说这里的new方法和Object.create()必然不会相互引用,这样会产生一个无限循环的函数,因此说这里只是一个大概思路上的引导,对于理解js的对象继承,原型链的概念会有帮助。