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

1,399 阅读3分钟

JavaScript中创建一个对象可以采用3种方式:
1)new Object()
2)Object.create()
3) 字面量写法

一、new Object()

new Object()这种方式即我们常说的“使用构造函数创建对象”,new运算符实际做了以下4件事情:
1)创建一个空的javascript对象;
2)链接该对象(即设置该对象的constructor)到另一个对象;
3)将步骤1中新创建的对象作为this上下文;
4)如果该函数没有自己的返回对象则返回this。

function Person(name) {
    this.name = name;
}
var linda = new Person('Linda');
typeof(linda)  // "object"
linda instanceof Person // true ——new创建并返回了一个新对象,这个新对象是构造函数的实例
linda.__proto__ === Person.prototype // true ——实例的__proto__ 关联到构造函数的原型对象
linda.constructor === Person // true ——该实例的constructor链接到其构造函数
linda.constructor === Person.prototype.constructor // true


如何手写实现一个new呢?

1.法一

// new是关键字,这里用函数来模拟new Foo(args) <=> fakeNew(Foo, args)
function fakeNew(foo, ...args) {
  // 创建新对象,并继承构造方法的prototype属性,
  // 这一步是为了把obj挂原型链上, 相当于obj.__proto__ = Foo.prototype
  let obj = Object.create(foo.prototype)  
  
  // 执行构造方法, 并为其绑定新this, 
  // 这一步是为了让构造方法能进行this.name = name之类的操作, 
  // args是构造方法的入参, 因为这里用myNew模拟, 所以入参从myNew传入
  let result = foo.apply(obj, args)

  // 如果构造方法已经return了一个对象, 那么就返回该对象, 
  // 一般情况下,构造方法不会返回新实例,
  // 但使用者可以选择返回新实例来覆盖new创建的对象 否则返回myNew创建的新对象
  return typeof result === 'object' && result !== null ? result : obj
}

function Foo(name) {
  this.name = name
}
const newObj = fakeNew(Foo, 'Linda')
console.log(newObj)                 // Foo {name: "Linda"}
console.log(newObj instanceof Foo)  // true

2.法二(以下代码参考大佬

function newFake() {
    var obj = new Object()

    // 取出第一个参数即要传入的构造函数。此外shift 会修改原数组故arguments会被去除第一个参数
    var constructor = Array.prototype.shift.call(arguments) // 通过call()让arguments能够借用shift方法

    // 关联 __proto__ 到 constructor.prototype
    // 这样 obj 就可以访问到构造函数原型中的属性
    obj.__proto__ = constructor.prototype

    // 将构造函数的 this 指向新建的对象
    // 这样 obj 就可以访问到构造函数中的属性
    var result = constructor.apply(obj, arguments);
    
    // 返回类型判断, 如果是对象则返回构造函数返回的对象;否则返回创建的新对象
    return typeof result === 'object' ? result : obj; 
};

二、Object.create()


ES5新增的**Object.create()** 方法创建一个新对象,使用现有的对象(传入的第一个参数)来作为新创建对象的prototype。(即将创建的新对象的__proto__指向已存在对象的原型)

其作用(只传1个参数情况下)与道格拉斯·克罗克福德的“原型式继承”函数相同:(JavaScript高级程序设计P170)

function object(o) {
  function F () {} // 先创建一个临时性的构造函数
  F.prototype = o // 然后将传入的对象作为这个构造函数的原型
  return new F() // 最后返回了这个临时类型的一个新实例
}