new的作用及手写new

·  阅读 1989

首先要知道为什么使用new

我们都知道new是将构造函数变为实例对象 ,如果不使用new操作符会怎么样?

首先看一段有没new操作符代码

// 创建一个构造函数
function Foo(name, age){
    this.name = name;
    this.age = age;
}
// 添加方法
Foo.prototype.sayhi = function (){ // 切记不要用箭头函数 否则this指向全局作用域
    console.log(this.name);
}
// 直接调用构造函数
const foo = Foo('哈哈',123);
console.log(foo); // undefined
console.log(window.name); //  '哈哈'
复制代码

在看一段使用new操作符代码

// 创建一个构造函数
function Foo(name, age){
    this.name = name;
    this.age = age;
}
// 添加方法
Foo.prototype.sayhi = function (){ // 切记不要用箭头函数 否则this指向全局作用域
    console.log(this.name);
}
// 直接调用构造函数
const foo = new Foo('哈哈',123); // 使用new操作符
console.log(foo); //Foo {name: '哈哈', age: 123, __proto__:{sayhi: ƒ ()}}
foo.sayhi(); //  '哈哈'
console.log(foo.name); // '哈哈'
复制代码

new操作符 和不用new操作符区别是什么?

有new操作符无new操作符
foo 实例对象foo undefined
this 指向 foothis 指向 window

new操作符到底做了什么?

1.把函数变为一个对象

2.foo原型链和构造函数Foo原型对象绑定

3.this指向foo

根据上面我们来实现一个new操作符

// const xxx = _new(Foo,'哈哈',123)  ==> new Foo('哈哈',123)
function _new(fn){
    // 1 获取除fn以外的所有arguments 
    // 使用slice删除arguments第一个元素就得到其他arguments
    const args = Array.prototype.slice.call(arguments,1); // ['哈哈',123]
    // 新建一个对象 用于函数变对象
    const newObj = {};
    // 原型链被赋值为原型对象
    newObj.__proto__ = fn.prototype;
    // this 指向新对象 
    fn.apply(newObj, args);
    // 返回这个新对象
    return newObj;
}
复制代码

这段代码比较难理解的是 fn.apply(newObj, args);

正常的理解是fn这个方法被执行了 将args赋值给this中的属性

其实还可以换个角度思考一下这段代码

function Foo(){
    this.name = '咿呀';
    this.age = 123;
}
const obj = {};
Foo.apply(obj);
// Foo 执行后
// Foo中的this属性被绑定在obj对象上
console.log(obj) // {name: '咿呀', age: 123}
复制代码

new到底做了什么?专业描述如下:

1.在内存中创建一个新对象

2.这个新对象内部的[[prototype]]特性被赋值为构造函数的prototype属性

3.构造函数内部的this被赋值为这个新对象(即this指向新对象)

4.执行构造函数内部的代码(给新对象添加属性)

  1. 如果构造函数返回非空 对象,则返回该对象;否则,返回刚创建的新对象。

最后还差一点没有说,上代码

function Foo(name){
    this.name = name;
    return {
        height:180
    }
}
const foo = new Foo('哈哈');
// 如果构造函数返回非空 对象,则返回该对象;
console.log(foo); // {height: 180}
复制代码

再对代码做一下完善并升级

function _new(fn,...args){
    const newObj = Object.create(fn.prototype);
    const value = fn.apply(newObj,args);
    // 如果函数返回 非空并是对象 返回 value 否则 返回 newObj
    return value instanceof Object ? value : newObj;
}
复制代码

重点: 使用new就不要在构造函数中 return

重点: 使用new就不要在构造函数中 return

重点: 使用new就不要在构造函数中 return

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改