- JavaScript的函数既可以作为普通函数被调用,也可以作为构造函数被调用。
- 我们使用new运算符来调用函数时,此时的函数就是一个构造器。
- JavaScript中绝大部分数据都是对象,那么JavaScript中也一定会有一个根对象的存在,这些对象的鼻祖(根源)都来自于这个根对象。
- JavaScript中的根对象是Object.prototype对象,而Object.prototype.__proto__对象是一个空对象,追其根源,我们遇到的大部分对象都是从Object.prototype克隆而来的,Object.prototype对象就是他们的原型。
- 原型链:从Object.prototype克隆除了A对象,我们又从A对象克隆出了B对象,实际上他们的关联就是一个链路,彼此关联,同时根原型就是Object.prototype
- 使用new运算符来创建对象的过程:实际上就是先去克隆Object.prototype对象,再进行一些其他额外操作的过程。
首先:
- 创建一个普通函数(使用它来当做构造函数)
function person(name) {
this.name = name;
}
2.在它的原型上创建一个方法
person.prototype.getName = function () {
return this.name
}
- 实现一个new
let _new = function () {
// 从Object上克隆一个对象
let obj = new Object();
// 获取外部传入的构造器 person
Constructor = [].shift.call(arguments);
console.log(arguments);
// 指向正确的原型:我们使用person对象创建的
obj.__proto__ = Constructor.prototype;
// 给obj设置属性
var ret = Constructor.apply(obj, arguments);
// 返回这个对象
return typeof ret === 'object' ? ret : obj;
};
- 验证这个new是否创建成功
let obj_1 = _new(person, 'sven');
console.log(obj_1.name); // => sven
- 完整代码
function person(name) {
this.name = name;
}
person.prototype.getName = function () {
return this.name;
};
let _new = function () {
// 从Object上克隆一个对象
let obj = new Object();
// 获取外部传入的构造器 person
Constructor = [].shift.call(arguments);
console.log(arguments);
// 指向正确的原型
obj.__proto__ = Constructor.prototype;
// 克隆构造器的属性给obj
var ret = Constructor.apply(obj, arguments);
// 返回这个对象
return typeof ret === 'object' ? ret : obj;
};
let obj_1 = _new(person, 'sven');
console.log(obj_1.name);
- 7 可能会疑惑的地方
[].shift.call(arguments): 这个是获取arguments对象的第一个参数,arguments类似一个数组对象,但是它又不具备数组的一些方法,打印出来如下:
arguments
{'0': [Function: person], '1': 'sven' }
借用array.prototype对象上的方法就可以完成shift操作,会给我们返回第一个值,也就是person对象,其他的值就是我们传入的参数。
Constructor.apply(obj, arguments); :用来链接构造器,其实就是把剩下的参数也克隆给obj。
{"0":'sven'}