前言:
以下记录模拟实现
new
方法,本文将以简单且清晰逻辑的带你一步步理解如何手写new
函数。
首先抛出最终版本的new函数,如果有不明白的请你一定随我看下去!一定有收获!( ఠൠఠ )ノ!!!
function myNew(Fn) {
if (typeof Fn !== 'function') throw new TypeError('This is not a constructor') // Fn校验
var args = Array.from(arguments).slice(1) // 取入参
var obj = {} // 1.创建一个空的简单JavaScript对象(即` {} `)
obj.__proto__ = Fn.prototype // 2. 为步骤1新创建的对象添加属性` __proto__ `,将该属性链接至构造函数的原型对象
var res = Fn.call(obj, ...args) // 3. 将步骤1新创建的对象作为this的上下文并传入参数;
return Object(res) === res ? res : obj // 4. 如果该函数没有返回对象,则返回this。
}
new
一句话概括:实例化构造函数。
new
关键字会进行如下的操作:
- 创建一个空的简单JavaScript对象(即
{}
); - 为步骤1新创建的对象添加属性
__proto__
,将该属性链接至构造函数的原型对象 ; - 将步骤1新创建的对象作为
this
的上下文 ; - 如果该函数没有返回对象,则返回
this
。 以上4点是MDN上关于new的描述,可以按照以上4步去写
1. 第一版本new
function myNew1(Fn) {
var obj = {} // 1.创建一个空的简单JavaScript对象(即` {} `)
obj.__proto__ = Fn.prototype // 2. 为步骤1新创建的对象添加属性` __proto__ `,将该属性链接至构造函数的原型对象 ;
var res = Fn.call(obj) // 3. 将步骤1新创建的对象作为this的上下文 ;
return res ? res : obj // 4. 如果该函数没有返回对象,则返回this。
}
var Fn = function(name, age) {
this.name = name
this.age = age
}
Fn.prototype.say = function() {
console.log('Fn.prototype.say')
}
// 测试
var newObj = myNew1(Fn)
newObj // Fn {name: undefined, age: undefined}
newObj.say() // Fn.prototype.say
var newObj1 = new Fn()
newObj1 // Fn {name: undefined, age: undefined}
newObj1.say() // Fn.prototype.say
好了,本文结束!
然而事情貌似没有这么简单😂
new
可以传参Fn函数
校验问题- 如果
Fn函数
内有返回又会怎样
2. 第二版本new
问题一:
function myNew2(Fn) {
var args = Array.from(arguments).slice(1) // 取入参
var obj = {} // 1.创建一个空的简单JavaScript对象(即` {} `)
obj.__proto__ = Fn.prototype // 2. 为步骤1新创建的对象添加属性` __proto__ `,将该属性链接至构造函数的原型对象
var res = Fn.call(obj, ...args) // 3. 将步骤1新创建的对象作为this的上下文并传入参数;
return res // 4. 如果该函数没有返回对象,则返回this。
}
var Fn = function(name, age) {
this.name = name
this.age = age
}
Fn.prototype.say = function() {
console.log('Fn.prototype.say')
}
// 测试
var newObj = myNew2(Fn, 'Leo', 18)
newObj // Fn {name: 'Leo', age: 18}
newObj.say() // Fn.prototype.say
var newObj1 = new Fn('Leo', 18)
newObj1 // Fn {name: 'Leo', age: 18}
newObj1.say() // Fn.prototype.say
问题二:
function myNew2(Fn) {
if (typeof Fn !== 'function') throw new TypeError('this is not a constructor')
var args = Array.from(arguments).slice(1) // 取入参
var obj = {} // 1.创建一个空的简单JavaScript对象(即` {} `)
obj.__proto__ = Fn.prototype // 2. 为步骤1新创建的对象添加属性` __proto__ `,将该属性链接至构造函数的原型对象
var res = Fn.call(obj, ...args) // 3. 将步骤1新创建的对象作为this的上下文并传入参数;
return res // 4. 如果该函数没有返回对象,则返回this。
}
// 测试
var newObj = myNew2(1, 'Leo', 18) // uncaught TypeError: this is not a constructor
var Fn = 1
var newObj1 = new Fn('Leo', 18) // Uncaught TypeError: Fn is not a constructor
问题三:
function myNew2(Fn) {
if (typeof Fn !== 'function') throw new TypeError('this is not a constructor')
var args = Array.from(arguments).slice(1) // 取入参
var obj = {} // 1.创建一个空的简单JavaScript对象(即` {} `)
obj.__proto__ = Fn.prototype // 2. 为步骤1新创建的对象添加属性` __proto__ `,将该属性链接至构造函数的原型对象
var res = Fn.call(obj, ...args) // 3. 将步骤1新创建的对象作为this的上下文并传入参数;
return Object(res) === res ? res : obj // 4. 如果该函数没有返回对象,则返回this。
}
var Fn = function(name, age) {
this.name = name
this.age = age
return 1 // 这里返回的是非对象(null/undefined/number/string/boolen)
}
Fn.prototype.say = function() {
console.log('Fn.prototype.say')
}
// 测试
var newObj = myNew2(Fn, 'Leo', 18)
newObj // Fn {name: 'Leo', age: 18}
newObj.say() // Fn.prototype.say
var newObj1 = new Fn('Leo', 18)
newObj1 // Fn {name: 'Leo', age: 18}
newObj1.say() // Fn.prototype.say
var Fn = function(name, age) {
this.name = name
this.age = age
return {} // 注意这里返回了对象
}
Fn.prototype.say = function() {
console.log('Fn.prototype.say')
}
// 测试
var newObj = myNew2(Fn, 'Leo', 18)
newObj // Fn {}
newObj.say() // Uncaught TypeError: newObj.say is not a function
var newObj1 = new Fn('Leo', 18)
newObj1 // Fn {}
newObj1.say() // Uncaught TypeError: newObj.say is not a function
var Fn = function(name, age) {
this.name = name
this.age = age
return function cbFn(){} // 注意这里返回了函数(本质上也是对象,不理解的可以去复习一下对象类型)
}
Fn.prototype.say = function() {
console.log('Fn.prototype.say')
}
// 测试
var newObj = myNew2(Fn, 'Leo', 18)
newObj // ƒ cbFn(){}
newObj.say() // Uncaught TypeError: newObj.say is not a function
var newObj1 = new Fn('Leo', 18)
newObj1 // ƒ cbFn(){}
newObj1.say() // Uncaught TypeError: newObj.say is not a function
至此对于new
的模拟告一段落
最终输出结果:
function myNew(Fn) {
if (typeof Fn !== 'function') throw new TypeError('This is not a constructor') // Fn校验
var args = Array.from(arguments).slice(1) // 取入参
var obj = {} // 1.创建一个空的简单JavaScript对象(即` {} `)
obj.__proto__ = Fn.prototype // 2. 为步骤1新创建的对象添加属性` __proto__ `,将该属性链接至构造函数的原型对象
var res = Fn.call(obj, ...args) // 3. 将步骤1新创建的对象作为this的上下文并传入参数;
return Object(res) === res ? res : obj // 4. 如果该函数没有返回对象,则返回this。
}
相关知识:
- apply/call
- 对象类型相关
- 原型链相关
相关文章推荐
最后
原创不易希望大家多多支持,欢迎拍砖!!~ o( ̄▽ ̄)o