在JS中创建对象最常见的方式一般有两种:Object.create(),new Object(),{}(对象字面量创建)
再说区别之前我们先要明确一些相关的概念:
1、对象有属性__proto__
,指向该对象的构造函数的原型对象
2、构造函数函数除了有属性__proto__
,还有属性prototype
,__proto__
指向构造这个函数的构造函数的原型对象,prototype
指向该构造函数函数的原型对象
function item(){
a = 123;
}
const item1 = {
a : 1234
}
var o1 = Object.create(item)
var o2 = object.create(item1)
var n = new item()
首先最明显的不同就是,Object.create(proto,[propertiesObject])
中的proto
可以是个对象实例(如上面的item1)也可以为构造函数函数(如上面的item),甚至可以为null
,用作新构造对象的原型对象。
而new Object( constructor )
只能传入构造函数
Object.create
在创建的对象上没有继承 Object.prototype 原型链上的属性或者方法,例如:toString(), hasOwnProperty()等方法
先看Object.create()
的实质:
Object.create = function (o) {
var F = function () {}; //创建一个临时的构造函数
F.prototype = o; //将传进来的参数作为F的原型
return new F(); //用这个临时的构造函数去new出一个实例,并返回这个实例
};
例子:
var Base = function () {
this.a = 2
}
Base.prototype.a = 3;
var o1 = new Base();
var o2 = Object.create(Base);
console.log(o1.a); //2
console.log(o2.a); //undefined
console.log(o2.__proto__) //ƒ () { this.a = 2 }
console.log(o2.prototype) //{a: 3, constructor: ƒ}
console.log(Base.prototype) //{a: 3, constructor: ƒ}
console.log(o1) //Base {a: 2}
console.log(o1.__proto__) ////{a: 3, constructor: ƒ}
看起来很复杂,怎么一个实例还有prototype的???
图解:
Object.create
new
综上,他们俩比较明显的区别就是:new关键字创建的对象会保留原构造函数的属性,而用Object.create()创建的对象不会。
new
原生JS实现new的过程
/**
*
* @param fn 构造函数
* @param arg 传入的形参
*/
function _mynew(fn, ...args) {
const t = typeof(fn)
//判断fn是否为一个函数(先判断为函数再判断是否能被new的函数)
if(t !== "function"){
throw new TypeError('${t} must be a function')
}
//1. 新建一个对象
let _this = Object.create(fn.prototype); //由fn.prototype作为原型去新建一个对象
//2. 将实例的__proto__指向构造函数的prototype
Object.setPrototypeOf(_this, fn.prototype);
//3. 设置实例的constructor
_this.constructor = fn;
//4. 通过apply构造函数来传参
const result = fn.apply (_this,args);
//5.返回值判断(return值如果为引用值,则改变为其本身)
if(result&&(typeof result === "object"||typeof result === "function")){
return result
}
return _this;
}
{}
{}
是javascript对象字面量创建的形式,其本质和new Object()
并无区别,默认都是继承了Object对象上的prototype