先导知识
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例 (MDN)
new 操作符做了什么?
- 在内存中创建一个新对象
- 这个对象会被执行
[[Protoype]]
(也就是_proto_
) 链接 - 生成的新对象会绑定到函数调用的
this
- 通过
new
创建的每个对象将最终被[[Prototype]]
链接到这个函数的prototype
对象上 - 如果函数没有返回对象类型
Object
(包含Functoin, Array, Date, RegExg, Error
),那么new
表达式中的函数调用会自动返回这个新的对象
模拟实现 (更好理解一点吧)
当代码 new Foo(...)
执行时,会发生以下事情:
a. 一个继承自 Foo.prototype
的新对象被创建。
b. 使用指定的参数调用构造函数 Foo
,并将 this 绑定到新创建的对象。new Foo
等同于 new Foo()
,也就是没有指定参数列表,Foo
不带任何参数调用的情况。
c. 由构造函数返回的对象就是 new
表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤 a 创建的对象。
Object.create()
方法创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__
Object.create(null)
创建一个不继承任何原型的新对象
let o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype)
new.target
属性允许你检测函数或构造方法是否是通过 new
运算符被调用的
在通过 new
运算符被初始化的函数或构造方法中,new.target
返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target
的值是 undefined
let o = {};
o = Object.create(Object.prototype)
console.log(o._proto_) // undefined
/**
* 模拟实现 new 操作符
* @param {Function} ctor [构造函数]
* @return {Object|Function|Regex|Date|Error} [返回结果]
*/
function newOperator(ctor) {
if(typeof ctor !== 'function') {
throw 'newOperator function the first params must be a function'
}
// ES6 new.target 是指向被 new 调用的构造函数
newOperator.target = ctor
// new 的 1、2、4 模拟 ,即创建新对象...
const newObj = Object.create(ctor.prototype)
// ES5 arguments 转成数组,当然也可以用 ES6 [...arguments], Aarry.from(arguments)
// 除去 arguments 中的第一个参数
const argsArr = [].slice.call(arguments, 1) // 等同于 [].shift.call(arguments)
// new 的 3 模拟,新对象绑定到函数调用的 this
// 获取 ctor 函数返回结果
const ctorReturnResult = ctor.apply(newObj, argsArr)
// Functoin, Array, Date, RegExg, Error 这些类型中合并起来只有 Object 和 Function 两种类型 typeof null 也是 'object' 所以要不等于 null,排除 null
const isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null
const isFunction = typeof ctorReturnResult === 'function'
if(isObject || isFunction){
return ctorReturnResult;
}
// 模拟 new 5
return newObj
}
// 验证
function Student(name, age) {
this.name = name
this.age = age
}
const student = newOperator(Student, '白醭飙尘', 24)
console.log(student) // Student {name: '白醭飙尘', age: 24}
const str = new String(123) // String {'123'}
console.log(str[1]) // 2
console.log(typeof str[1]) // string