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() // 最后返回了这个临时类型的一个新实例
}