Skip to main content

new 与 Object.create()

一、new

1、原理解释

1-1、红宝书上解释

  1. 创建一个新对象。
  2. 将构造函数的作用域赋给新对象。
  3. 执行构造函数中的代码。
  4. 返回新对象。

1-2、MDN 上的解释

  1. 一个继承自 Foo.prototype 的新对象被创建。
  2. 使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数时,Foo 不带任何参数调用的情况。
  3. 如果构造函数返回了一个“对象”,那么这个对象会取代整个 new 出来的结果。如果构造函数没有返回对象,那么 new 出来的结果为步骤 ① 创建的对象。

2、过程分析

使用 new 运算符时,其实就做了这三件事:

// 创建了一个空对象 obj,并将这个空对象的 __proto__ 成员指向 Foo 函数对象 prototype 成员对象
var obj = {};
obj.__proto__ = Foo.prototype;

// 将 Foo 函数对象的 this 指针替换成 obj,然后再调用Foo函数
Foo.call(obj);

// 判断实例类型是否为对象,是则返回实例,否则返回构造函数
if (typeof obj === 'object') {
return obj;
} else {
return Foo;
}

也就是说,函数内部发生了以下变化:

  1. 创建一个新对象,并继承构造函数 Foo 的原型对象 Foo.prototype
  2. 构造函数 Foo 被执行,执行时传入相应的参数,并将 this 指定为新的实例。
  3. 判断实例是否为对象,是则返回实例,否则返回构造函数。

因此,new 的原理可总结为:

创建一个新对象,并继承原构造函数的 prototype,然后将 this 指定为新的实例,最后返回新对象。

二、Object.create()

1、方法详解

Object.create(proto [,propertiesObject])

功能:创建一个对象,其原型为 prototype,同时可添加多个属性。

参数:

  • proto(必须):原型对象,可以为 null 表示没有原型。
  • propertiesObject(可选):包含一个或多个属性描述符的对象。如果该参数被指定且不为 undefined,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
propertiesObject 参数详解

数据属性:

  • value:值。
  • writable:是否可修改属性的值。
  • configurable:是否可通过 delete 删除属性,重新定义。
  • enumerable:是否可 for-in 枚举。

访问属性:

  • get():访问。
  • set():设置。

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

示例:

function Person(name) {
this.name = name;
}
Person.prototype.say = function () {
console.log('my name is ' + this.name + ', my age is ' + this.age);
}

var person = new Person('Tim');
var p = Object.create(person, {
age: {
value: 23,
writable: true,
configurable: true
},
sex: {
configurable: true,
get: function () { return sex + '士'; },
set: function (value) { sex = value; }
}
});

p.sex = '男';
p.say(); // 'my name is Tim, my age is 23'
console.log(p.sex); // '男士'
p.sex = '女';
console.log(p.sex); // '女士'

Object.create(proto [,propertiesObject]) 是 E5 中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不是一个子函数,可以传一个 null,第二个可选参数是对象的属性描述符。

更多 Object 内置属性/方法请点击

2、原理

Object.create() 第一个参数是 proto,第二个参数是对象属性,其内部原理与原型式继承相似:

function clone(proto) {
function F() { }
F.prototype = proto
return new F()
}

过程:

创建一个新对象,将第一个参数 proto 作为新对象的隐式原型(__proto__),将第二个参数对象属性复制到新对象中,最后返回新对象。

三、new 与 Object.create() 的区别

  • new 会保存原构造函数的属性,而 Object.create() 不会。
  • new 创建的对象其隐式原型(__proto__)是原构造函数的 prototype,而 Object.create() 创建的对象其隐式原型(__proto__)是原构造函数(或对象)本身。
function City() {
this.city = 'Guangzhou'
}

var city1 = new City()
var city2 = Object.create(City)

console.log(city1.__proto__) // {constructor: ƒ}
console.log(city2.__proto__) // ƒ City() { this.city = 'Guangzhou' }

打印 city1city2 的结果如下: