Bootstrap

Object.create 和 new 区别与原理

Object.create 和new 区别与原理

今天无意中看到一篇关于 Object.create 和 new 区别的博客,看完后觉得很不对劲。再一看评论,果然有问题。所以写个通俗易懂的博客,也再次理清自己的思绪。我会先说原型链的一些概念,从原型链讲他们的区别,引出继承的例子,顺便引出 new 实现的原理,最后给出完整的 Object.create 规范

(一)Object.create 和 new 区别

因为那篇文章的作者似乎没弄清原型链的一些问题,所以首先你得有这个概念,参考我以前博客

ES6 Class 的原生写法
https://blog.csdn.net/u014168594/article/details/79448711

在这里插入图片描述

截取我博客中的图:

1.Object.create 是创建一个新对象,使用现有的对象来提供新创建对象的 _proto_。意思就是生成一个新对象,该新对象的 _proto_(原型) 指向现有对象。

2.new 生成的是构造函数的一个实例,实例继承了构造函数及其 prototype(原型属性)上的属性和方法。

function a(){
	this.name = 1
}
a.prototype.sayName = function(){
	console.log(1)
}
var a1 = new a()
var a2 = Object.create(a.prototype)

看上面代码,从代码分析更直观

对象 a2 的 _proto_ 指向 a.prototype, 只继承了 a 的原型方法 sayName

在这里插入图片描述

a1 是构造函数 a 的实例,继承了构造函数 a 的属性 name及其 prototype(原型) 的原型方法 sayName

在这里插入图片描述

两者不同在于,Object.create 创建的新函数并没有继承构造函数的属性和方法,只继承了原型方法和原型属性

这就是为什么组合寄生式继承优于普通的组合继承的地方,因为之前已经继承过一次,不再重复继承多一次原型的属性和方法。

组合继承

function SuperType(name) {	
	this.name = name;	
	this.colors = ["red","green","black"];
}; 
SuperType.prototype.sayName = function() {
	return this.name
}; 
function SubType(name, age) {	
	SuperType.call(this, name);	//继承一次
	this.age = age;
}; 

/* 普通组合继承 */
SubType.prototype = new SuperType();	//继承第二次

/* 组合寄生 */
function inherit(sub,super){
	var prototype = Object.create(super.prototype)	//不发生第二次继承
	prototype.constructor =  sub
	sub.prototype = prototype 
}
inherit(SubType,SuperType)

SubType.prototype.sayAge = function () {return this.age};

(二)new 实现原理

从上面几张图我们已经知道了 new 其实就是在实现 Object.create (使用现有的对象来提供新创建的对象 _proto_)的基础上,继承了原对象的属性和方法

function a(){
	this.name = 1
}
a.prototype.sayName = function(){
	console.log(1)
}
var a1 = new a()

这个例子实际上就干了三件事

var a1 = {}		//创建一个空对象
a1._proto_  =  a.prototype	//使用现有的对象来提供新创建对象的  \_proto_
a.call(a1) 		//继承原对象属性和方法

所以我们在对象原型里面 x.prototype 里面增加属性和方法会被继承,就是因为这个 proto 属性

(三)Object.create() 规范

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

Object.create(proto, [propertiesObject])

proto

新创建对象的原型对象,可以为 null。

propertiesObject

可选。如果没有指定为 undefined,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数

返回值

一个新对象,带着指定的原型对象和属性。

例子

var o = {}
o = Object.create(Object.prototype, {
	// foo会成为所创建对象的数据属性
	foo: { 
		writable:true,
		configurable:true,
		value: "hello" 
	},
	// bar会成为所创建对象的访问器属性
	bar: {
		configurable: false,
		get: function() { return 10 },
		set: function(value) {
		  console.log("Setting `o.bar` to", value);
		}
	}
});
;