【JavaScript——基础篇】new操作符 到底做了什么事情?

217 阅读1分钟

大家好,相信大家都用到过new操作符,那么今天和大家聊一聊new操作符到底做了什么事情? 

一、首先让我们通过几个例子来看看new的作用 

function TestNew(name){     
    this.name = name; 
    this.sayname = function(){ 
        console.log(this.name); 
    } 
}   

TestNew.prototype.sayhello = function(name){
   console.log(`hello ${name}`); 
}

const test = new TestNew('test');
console.log(test.name); // test
test.sayname(); // test
test.sayhello('test'); //hello test

通过上面的例子我们可以看出来 

  1. new 操作符创建出来的 test 实例可以访问到TestNew里面的属性。
  2. new 操作符创建出来的 test 实例可以访问到TestNew原型链上的属性。

我们上面的 TestNew没有 return 值,那么当构造函数有返回值的情况下会怎么样呢?

function TestNew(name){     
    this.name = name; 
    return 'test return'
}

const test = new TestNew('test');
console.log(test.name); // test

我们发现结果还是返回了 test 并没有输出 test return,也就是说 返回值是字符串的时候 返回值并没有实际意义。

注意:我特意提到的当返回值是字符串的时候 返回值没有意义,那么如果是其他类型的返回值的情况呢?

function TestNew (name,age){ 
    this.name = name; 
    return {
        age
    }
}

const test = new TestNew('test',26);
console.log(test.name); // undefined
console.log(test.age); // 26

可以发现 返回值 生效了,这里只展示了返回值是对象和字符串的情况,有兴趣的同学可以自己去试试其他基本数据类型的返回值(结果和字符串是一样的),所以构造函数是不需要返回值的,如果是基本数据类型,则返回值失效,如果是对象,则会使new失去意义。

小结:

  1. new 操作符创建出来的 test 实例可以访问到TestNew里面的的属性
  2. new 操作符创建出来的 test 实例可以访问到TestNew原型链上的属性
  3. 尽量避免在构造函数中使用 return 返回值

理解了new的作用,那么我们接下来就可以尝试自己手写一个new了

二:手写 new

function myNew (Base,name){ 
    const obj= new Object(); // 创建空对象
    obj.__proto__ = Base.prototype; // 将obj通过__proto__指向Base的原型
    const rel = Base.call(obj,name); // 将新对象作为上下文(this),调用call来执行类的构造函数
    
    //如果fn返回的是null或undefined(也就是不返回内容)或者其他基础类型,我们返回的是obj,否则返回rel
    return rel instanceof Object ? rel : obj;
}

function TestNew(name){
    this.name = name;
    this.sayname = function(){
        console.log(this.name);
    }
}
TestNew.prototype.sayhello = function(name){
    console.log(`hello ${name}`);
}

const myTestNew = myNew(TestNew,'Constructor function');
console.log(myTestNew.name); // Constructor function
console.log(myTestNew.sayname()); // Constructor function
console.log(myTestNew.sayhello('prototype function')); // hello prototype function

至此我们也实现了自己的 new 操作符。