使用
想要知道怎么实现一个new方法,我们先要看看new怎么使用,咱们直接上例子
function Animal(type) {
this.type = type;
}
Animal.prototype.say = function() {
console.log('say');
};
let dog = new Animal('dog');
console.log(dog);
dog.say()
以上例子就简单的使用了new来创建一个dog实例 而且知道了:
- dog可以访问 Animal 构造函数里的属性
- dog可以访问 Animal.prototype 中的属性
- dog是一个实例对象
分析
我们来说下 构造函数-实例对象-原型对象 三者的关系
- 通过构造函数new得到实例对象
- 每个实例对象都有一个__proto__属性并且指向原型对象,
- 原型对象的constructor指向构造函数
new过程做了啥
- 创建了一个空对象
- 执行构造函数使得这个新创建的对象拥有构造函数的属性与方法
- 继承构造函数原型上的属性与方法
- 返回这个实例化后的对象
代码实现
- 有了上面的分析,我们就比较容易去实现一个自己的new方法了
function mockNew() {
let obj = {};
//创建 一个新对象
let constructor = [].shift().call(arguments);
//shift方法删除数组第一个元素并返回,shift是会改变数组的
obj.__proto__= constructor.prototype;
//实例的隐式原型指向构造函数原型
constructor.apply(obj,arguments);
//使用apply,改变构造函数this的指向新建的对象,这样obj就可以访问构造函数中的属性
//也可以用call 那就的展开arguments参数了
return obj;
//返回该对象
}
- 其实这个new还有一个特点,就是如果在构造函数里定义了返回值,会根据你定义的返回值不同的得到的实例结构也不一样
- 如果在构造函数里return了一个对象,那么返回值就是你定义的那个对象
- 如果在构造函数里没有定义return的值,会默认返回你所创建的对象
- 如果在构造函数里return的是非对象,而是基本类型的数据,那么自定义的return会被忽略,返回的还是我们创建的那个对象
- 这点需要注意
- 最终代码如下
function mockNew() {
let obj = {};
//创建 一个新对象
let constructor = [].shift().call(arguments);
//shift方法删除数组第一个元素并返回,shift是会改变数组的
obj.__proto__= constructor.prototype;
//实例的隐式原型指向构造函数原型
const result = constructor.apply(obj,arguments);
//使用apply,改变构造函数this的指向新建的对象,这样obj就可以访问构造函数中的属性
//也可以用call 那就的展开arguments参数了
return result instanceof Object ? result : obj;
//返回该对象
}
总结
以上是对new的简单理解与实现,如有问题还望大家指证,在评论区留言