声明:下面主要是写 new 的内部实现原理,但其中涉及到的其它东西,也会作出适当的说明
一. 实现步骤
- 创建一个新对象
- 将新对象的
__proto__指向 构造函数的prototype(利用 Object.create()) - 将 构造函数的
this指向 新对象(利用 call 或者 apply) - 判断返回值类型 —— 如果是基本类型,则返回新对象;如果是引用类型,则返回该引用类型的对象
二. 实现代码
function myNew(){
// 创建一个新对象
let newObj = null;
// 这行代码的意思是,将 shift 方法的 this 绑定为 arguments(类数组),并且由 arguments 调用,删除并返回 arguments 中的第一个值,然后再判断这个值是否是(构造)函数。此后 arguments 中就只包括构造函数的所有参数,而不包括构造函数本身
let constructor = Array.prototype.shift.call(arguments);
// 判断是否是(构造)函数
if(typeof constructor !== "function"){
console.log("type error");
return;
}
// 将 新对象的 __proto__ 指向 构造函数的 prototype
newObj = Object.create(constructor.prototype)
// 将 构造函数的 this 指向 新对象,并接收 构造函数的返回结果
// let result = constructor.call(newObj, ...arguments);
let result = constructor.apply(newObj, arguments);
// 如果 构造函数 没有返回值,或者是 直接 return; 则 result 为 undefined
// 如果 构造函数 返回的是基本类型,则 result 为 基本类型
// 如果 构造函数 返回的是引用类型,则 result 为 引用类型
// 判断 返回结果是什么
let flag = result && (typeof result === "object" || typeof result === "function");
// 如果 result 为 引用类型,则 flag 为 true,直接返回这个 引用类型对象,否则返回 新对象
return flag ? result : newObj;
}
// 使用方法
objectFactory(构造函数, 初始化参数);
三. 其它
1. 在函数形参中接收的 ...args 和 arguments 对象的区别
(1) ...args 是接收剩余参数,组成一个真数组,可以调用 Array 原型上的方法;而 arguments 是一个类数组,包括了所有参数,并且有 length 属性和其它的一些附加属性(如 callee)
(2) ...args 要写在函数的形参列表中;而 arguments 可以不写在函数形参列表中,可以直接使用
2. Object.create() 的作用和实现
(1) 作用:将传入的对象作为原型
(2) 实现:
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}