new 运算符
方法说明
new
运算符会创建一个用户自定义对象类型(就是自定义函数、或者说构造函数)的实例或具有构造函数的内置对象(比如:Number、String等原生对象)的实例,具体的过程如下:
- 创建一个空对象,
{}
- 将第一步的空对象链接到另一个对象(
new
操作符后面跟着的构造函数的原型对象)- 将第一步创建的对象作为构造函数的
this
上下文- 返回对象实例,如果构造函数有返回对象,则对象实例就是构造函数返回的对象,否则就返回
this
作为对象实例
划重点
从上面的第3步和第4步可以看出来,通过
new
操作符创建一个对象实例时,构造函数中的this
并不一定指向创建出来实例对象,大家可以复制以下 “示例代码” 去测试:
示例代码
// 示例一,构造函数没有返回对象,this等于创建出来的实例对象
let obj1 = null
function E1 () {
obj1 = this
}
const ins1 = new E1()
console.log(obj1 === ins1) // true
// 示例二,构造函数返回了一个对象,this不等于创建出来的实例对象
let obj2 = null
function E2 () {
obj2 = this
return { e: 'ee' }
}
const ins2 = new E2()
console.log(obj2 === ins2) // false
源码点拨
逻辑较为简单,重点在于理解上面的 “方法说明” 、 “划重点”、”示例代码“ 三部分内容,源码就是实现 “方法说明” 的一个过程,通过
闭包 + Object.create() + Function.prototype.call
来实现,具体的可参考代码中的详细注释
源码
const myNew = function (constructor) {
return function (...args) {
// 完成1、2两步,创建一个链接到构造函数的原型对象的对象
const obj = Object.create(constructor.prototype)
// 将obj作为构造函数的this上下文
constructor.call(obj, ...args)
// 如果构造函数有返回值,则将返回值作为实例对象返回,否则返回obj作为实例对象
return constructor() || obj
}
}
// 示例 1,构造函数无返回值
function T1 (arg1, arg2) {
this.arg1 = arg1
this.arg2 = arg2
}
const ins1 = myNew(T1)(1, 2)
console.log(ins1) // {arg1: 1, arg2: 2}
// 示例 2,构造函数有返回值
function T2 (arg1, arg2) {
this.arg1 = arg1
this.arg2 = arg2
return { a: 'aa' }
}
const ins2 = myNew(T2)(1, 2)
console.log(ins2) // {a: "aa"}