「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。
使用new运算符发生了什么
《Javascript权威指南》中的定义:
new运算符创建并初始化一个新对象。关键字new后跟随一个函数调用。这里的函数称为构造函数(constructor),构造函数初始化一个新创建的对象。
也就是说 new 的作用其实就是根据构造函数创建一个新的对象,如果要模拟 new 需要了解一下这个新建的对象有些什么性质,并且和他的构造函数有什么关系
举个栗子
- 创建一个构造函数
Foo,用new Foo()创建一个实例f1
var Foo = function(name) {
this.name = name
}
Foo.prototype.say = function() {}
var f1 = new Foo('味精王') // 实例
- 实例中没有显式的
return,new之后会自动返回一个对象 - 查看实例
f1上的属性
- 实例对象的
constructor指向该对象的构造函数 - 实例对象的属性
__proto__指向该对象的构造函数的原型对象prototype,并且继承原型属性上的方法
关于
__proto__和prototype祭出一张神图
再举个显示
return的栗子
var Foo1 = function(name) {
this.name = name
return 'I am Shane'
}
var Foo2 = function(name) {
this.name = name
return {
age: 18
}
}
var r1 = new Foo1('味精王')
var r2 = new Foo2('味精王')
- 如果有显式的
return并且是一个对象类型则会返回这个return的对象,否则都会无视这个return还是返回之前新建的对象
小结
- 创建一个空对象
- 将空对象的
__proto__属性指向构造函数的prototype,因此实例对象可以共享原型上的属性和方法 - 改变
this的指向,指向这个空对象 - 判断构造函数的返回值,
- 如果没有返回,则返回
this - 如果有返回先判断 对象类型则返回该对象,否则 返回this
- 如果没有返回,则返回
模拟实现new运算符
知道了 new 的作用后就可以模拟来实现一下,这里模拟用的是一个函数,并加上了注释
关键方法 Object.create()
function newOperator(ctor) {
// 需要传入一个构造函数
if (typeof ctor !== 'function') {
throw 'newOperator function the first param must be a function'
}
// 创建一个新对象继承构造函数的原型
var newObj = Object.create(ctor.prototype)
// 获取第一个参数后面的参数
var argsArr = [].slice.call(arguments, 1)
// 改变this指向,并传入后面的参数,并执行构造函数
var ctorReturnResult = ctor.apply(newObj, argsArr)
// 判断是否有手动的返回值
var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null
var isFunction = typeof ctorReturnResult === 'function'
if (isObject || isFunction) {
return ctorReturnResult
}
// 返回新建的对象
return newObj;
}
- 验证效果:还是使用之前的例子
var f1 = newOperator(Foo, '味精王')
var r1 = newOperator(Foo1, '味精王')
var r2 = newOperator(Foo2, '味精王')
- 达到了new的效果
至此,就完成了 new 运算符的模拟,谢谢您的阅读。