来源:segmentfault.com/a/119000002…
new做了什么?
new操作符,通过执行自定义构造函数或js内置的构造函数,从而生成一个实例对象。
例1.1
function Person(name) {
this.name = name;
}
let p = new Person('jack')
console.log(p)
console.log(p.__proto__ === Person.prototype)上述demo操作:
1.new执行Person构造函数后,返回一个内部创建的新对象实例,并赋值给p。
2.this指向这个创建的新对象。
3.p的__proto__指向构造函数Person的prototype,实例p能够访问到Person构造函数原型中的属性和方法。
例1.2
function Person(name) {
this.name = name;
return {age: 18}
}
let p = new Person('jack')
console.log(p)上述demo:
构造函数返回了一个对象,结果将其直接返回,而不是返回内部创建的新对象。
上述两个例子,以及相关测试,总结出:
引用类型object或者function,即Function,Object,Array,Date,Error,Regexp。(typeof null == 'Object',记得排除null)。返回这些类型就会直接将其返回。
其他基本类型都会返回内部创建的新对象。
new内部操作步骤
现在再来理解new内部操作步骤,就会容易很多:
1.创建一个空的简单JavaScript对象(即{})
2.链接该对象(即设置该对象的构造函数)到另一个对象;
3.将步骤1新创建的对象作为this的上下文;
4.如果函数没有返回对象,则返回this。
实现一个new操作符
接下来,我们尝试实现一个new操作符。
封装方法myNew接受若干参数,第一个参数ctr为构造函数,其余为构造器所需参数arg1,arg2...
第一步
对应new内部操作步骤的1和2步,即创建和链接。
方法1
function myNew(ctr) {
let obj = Object.create(ctr.prototype)
}方法2
function myNew(ctr) {
let obj = {};
obj.__proto__ = ctr.prototype;
}第二步
上下文执行。
function myNew(ctr) {
let obj = Object.create(ctr.prototype)
const args = [].slice.call(arguments,1)
//或者 const args = Array.from(arguments).slice(1)
//或者 const args = [...arguments].slice(1)
let result = ctr.apply(obj,args)
}第三步
对返回值做兼容处理
function myNew(ctr) {
let obj = Object.create(ctr.prototype)
const args = [].slice.call(arguments,1)
let res = ctr.apply(obj,args)
if ((typeof res === "object" || typeof res === "function") && res !== null) {
return res ;
}
return obj
}此时,再看上面两个例子,就能很好的理解。