Object.create和new的区别

2019-05-15  本文已影响0人  _章鱼小丸子

js中创建对象的方式一般有两种Object.createnew

const Base = function(){};
const o1 = Object.create(Base);
const o2 = new Base();

在讲述两者区别之前,我们需要知道:

  1. 构造函数Foo的原型属性Foo.prototype指向了原型对象。
  2. 原型对象保存着实例共享的方法,有一个指针constructor指回构造函数。
  3. js中只有函数有prototype属性,所有的对象只_proto_隐式属性。

好了,首先,我们来看看var o1 = new Base()的时候new做了什么。

var o1 = new Object();
o1._proto_ = Base.prototype;
Base.call(o1);

下面这张图能清晰地看到每个函数和对象之间的关系,用圆形表示对象,方形表示函数。new做的操作就是先创建一个新的对象o1,这时o1._proto_指向Object.prototype。然后更改o1._proto_指向Base.prototype。最后用call强行转换作用环境,将构造函数的this指向o1,也就是o1拥有了构造函数Base定义的全部属性。

new过程示意图.png

再看看Object.create的实现方式

Object.create =  function (Base) {
    var F = function () {};
    F.prototype = Base;
    return new F();
};

如下图所示,首先创建一个空函数F,函数的prototype指向Base函数。new一个函数的实例,即让该实例的_proto_指向函数F的prototype,也就是Base函数,最后将该实例返回。即通过Object.create创建的对象o2,实际上完成了o2._proto_ = Base的操作。注意传入的参数Base2是一个对象。如果传入的是一个构造函数的话,该实例是无法继承的。

object.create过程示意图.png

理解他们的内部操作之后,来看个实际例子:

demo1.png

new之后,o1有了Base的全部属性,所以o1.a 的值是2。由于Object.create传入的参数是构造函数,o2的_proto_是无法指向Base的,而o2本身是由一个空构造函数F实例化出来的,也不具有a属性,所以输出undefined。

假如我们把构造函数Base换成对象

image.png

可以看到,此时o2去原型链上找a属性,o2的_proto_指向的是Base2,所以访问到属性a的值为1。

上一篇下一篇

猜你喜欢

热点阅读