new 与 Object.create()
一、new
1、原理解释
1-1、红宝书上解释
- 创建一个新对象。
- 将构造函数的作用域赋给新对象。
- 执行构造函数中的代码。
- 返回新对象。
1-2、MDN 上的解释
- 一个继承自
Foo.prototype
的新对象被创建。 - 使用指定的参数调用构造函数
Foo
,并将this
绑定到新创建的对象。new Foo
等同于new Foo()
,也就是没有指定参数时,Foo
不带任何参数调用的情况。 - 如果构造函数返回了一个“对象”,那么这个对象会取代整个
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;
}
也就是说,函数内部发生了以下变化:
- 创建一个新对象,并继承构造函数
Foo
的原型对象Foo.prototype
。 - 构造函数
Foo
被执行,执行时传入相应的参数,并将this
指定为新的实例。 - 判断实例是否为对象,是则返回实例,否则返回构造函数。
因此,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
,第二个可选参数是对象的属性描述符。
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' }
打印 city1、city2 的结果如下: