在JavaScript中,函数是个很神奇的东西;
- 可以当做方法执行;
- 可以当做函数执行,返回值;
- 可以作为构造函数;
funcion Person(){ }
const p = new Person();
那么 new 函数到底做了什么?
此处要明白new是语言内操作符,它代表一系列动作,因此 new 时不仅仅是执行函数,还有更多的操作,执行函数仅仅是new操作符中的一个过程;
了解new的朋友都知道new的四部曲,我写了一个函数,来模拟new操作符的内部过程;
/**
* 描述 创新对象工厂,类似new操作符的内部操作
* @date 2021-06-23
* @param {any} fn 构造函数
* @param {any} ...args 待初始化的数据
* @returns {any} 返回对象
*/
function objectFactory(fn, ...args) {
// 1. 创建新建对象
const obj = {};
// 2. 新对象的 __proto__ 指向构造函数的 prototype 属性;
obj.__proto__ = fn.prototype;
// 3. 初始化属性,解决this绑定
const result = fn.call(obj, ...args);
// 4. 处理对象返回逻辑;
// 返回新对象,如果存在 result,则返回result
if (typeof result === 'object') {
return result;
}
return obj;
}
/**
* 描述 另一种实现
* @date 2021-06-23
* @returns {any}
*/
function objectNew() {
// 构造函数
const constructor = arguments[0];
// 额外参数
const args = Array.prototype.slice.call(arguments, 1);
// 1. 创建新建对象
let obj = {};
// 2. 链接到原型
obj = Object.create(constructor.prototype);
// 3. 初始化属性,解决this绑定
const result = constructor.apply(obj, args);
// 4. 处理对象返回逻辑;
// 返回新对象,如果存在 result,则返回result
if (typeof result === 'object') {
return result;
}
return obj;
}
/**
* 描述 构造函数
* @date 2021-06-23
* @param {any} name
* @param {any} address
* @returns {any}
*/
function Person(name, address) {
this.name = name;
this.address = address;
// 构造函数可以直接返回新对象,但不建议这么做,失去了构造函数本意;
// return { a: name, b: address };
}
/**
* 描述 给原型对象增加方法
* @date 2021-06-23
* @returns {any}
*/
Person.prototype.say = function () {
console.log(`I am ${this.name} from ${this.address}`);
};
const p1 = objectFactory(Person, 'foo', 'hz');
const p2 = objectFactory(Person, 'bar', 'bj');
console.log(p1);
console.log(p2);
console.log(p1.__proto__ === p2.__proto__); // true
console.log(p1.__proto__ === Person.prototype); // true
console.log(p1.__proto__.__proto__ === Object.prototype); // true
const p3 = objectNew(Person, 'baz', 'nj');
console.log(p1.__proto__ === p3.__proto__); // true
函数 objectFactory 作用与 new 操作符内部过程是类似的,参数也是必要的,构造函数和其他属性值;
从原型结果 p1 查询原型链路, 与 new Person('foo','hz')效果等价;