JavaScript中使用new操作符实例化对象时构造函数有返回值的情况分析

Posted 孙群

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中使用new操作符实例化对象时构造函数有返回值的情况分析相关的知识,希望对你有一定的参考价值。

目录

javascript中的函数具有两面性,既可以作为普通的函数进行执行,也可以作为类的构造函数实例化对象。

函数的两面性

  • 作为普通函数执行

    当函数作为普通函数执行时,对函数传入参数,函数内部进行处理后返回值(当然也可以没有入参以及返回值),这种情况下函数更多体现的是面向过程编程的思想,如下所示:

      function add(a, b) 
        return a + b;
      
    
      const sum = add(40, 50);
      console.log(sum);
    
  • 作为类的构造函数实例化对象

    当函数作为类的构造函数执行时,可以实例化一个类的对象,此时函数可以看做是一个类,这种情况下体现的面向对象编程的思想。在JavaScript中经常使用new操作符实例化一个对象,其语法为

      new constructor[([arguments])]
    

    new操作符后面是一个类的构造函数,例如存在构造函数X, 一般情况下,我们可以通过执行const x = new X()是实例化一个X的实例对象。通常,当我们将函数作为类的构造函数使用时,构造函数中一般不会写返回值,但是如果构造函数中存在返回值又会如何呢?下面我们具体分析一下构造函数在不同返回值的情况下对得到的实例的影响。

作为类的构造函数使用时在不同返回值情况下的情况分析

  • 构造函数无返回值

      function Person(name) 
        this.name = name;
      
    
      var p = new Person('zhangsan');
    
      console.log(p);
      console.log('p instanceof Person: ', p instanceof Person);
      console.log('p.__proto__ === Person.prototype: ', p.__proto__ === Person.prototype);
      console.log('Person.prototype.isPrototypeOf(p): ', Person.prototype.isPrototypeOf(p));
    
    

    构造函数Person中无返回值,输出如下:

    我们可以看到变量p是类Person的一个实例化对象,Person.prototype是对象p的原型。

    结论: 当构造函数无返回值时,执行var x = new X()时,会执行x.__proto__ = X.prototype,将实例化对象的原型设置为对应的类的prototype对象,从而实现对象的实例化。

  • 构造函数有返回值,返回值是非 null 的对象

    我们在以上示例的基础上修改下构造函数,使得构造函数返回一个非 null的对象,如下所示:

      function Person(name) 
        this.name = name;
    
        const obj = 
          a: 1,
          b: 2
        ;
    
        return obj;
      
    
      var p = new Person('zhangsan');
    
      console.log(p);
      console.log('p instanceof Person: ', p instanceof Person);
      console.log('p.__proto__ === Person.prototype: ', p.__proto__ === Person.prototype);
      console.log('Person.prototype.isPrototypeOf(p): ', Person.prototype.isPrototypeOf(p));
    

    输出结果如下:

    我们可以看到变量p不是类Person的实例化对象,Person.prototype不是p的原型。

    结论: 当构造函数有返回值,且返回值是一个非null的对象时,执行var x = new X(),此时只是将X作为普通的函数执行,函数执行的返回值直接作为变量x的值,变量x不是类X的实例化对象,X.prototype也不是变量x的原型。

  • 构造函数有返回值,返回值是函数

    我们在以上示例的基础上修改下构造函数,使得构造函数返回一个函数,如下所示:

function Person(name) 
  this.name = name;
  
  function add(a, b) 
    return a + b;
  

  return add;


var p = new Person('zhangsan');

console.log(p);
console.log('p instanceof Person: ', p instanceof Person);
console.log('p.__proto__ === Person.prototype: ', p.__proto__ === Person.prototype);
console.log('Person.prototype.isPrototypeOf(p): ', Person.prototype.isPrototypeOf(p));

输出结果如下:

我们可以看到变量p不是类Person的实例化对象,Person.prototype不是p的原型。

结论: 当构造函数有返回值,且返回值是一个函数时,执行var x = new X(),此时只是将X作为普通的函数执行,函数执行的返回值直接作为变量x的值,变量x不是类X的实例化对象,X.prototype也不是变量x的原型。

  • 构造函数有返回值,返回值不是对象也不是函数或者返回值是 null

    我们再次修改构造函数,使得构造函数具有返回值,且返回值不是对象或者返回值是null,包括以下多种case,例如返回了nullundefined、数字、字符串等,如下所示:

      function Person(name) 
        this.name = name;
    
        // 返回以下值均等价
        // return null;
        // return undefined;
        // return 'abc';
        // return String('abc');
        // return Number(1);
        return 1;
      
    
      var p = new Person('zhangsan');
    
      console.log(p);
      console.log('p instanceof Person: ', p instanceof Person);
      console.log('p.__proto__ === Person.prototype: ', p.__proto__ === Person.prototype);
      console.log('Person.prototype.isPrototypeOf(p): ', Person.prototype.isPrototypeOf(p));
    

    输出结果如下:

    我们可以看到变量p是类Person的一个实例化对象,Person.prototype是对象p的原型。

    结论: 当构造函数有返回值,且返回值不是对象或者返回值是null时,执行var x = new X(),会完全忽略构造函数的返回值,依然执行x.__proto__ = X.prototype,将实例化对象的原型设置为对应的类的prototype对象,从而实现对象的实例化。

总结

综上分析,我们可以得出如下结论:

  • 当构造函数返回了函数或非 null 对象时
    执行var x = new X(),此时只是将X作为普通的函数执行,函数执行的返回值直接作为变量x的值,变量x不是类X的实例化对象,X.prototype也不是变量x的原型。
  • 其他情况(构造函数无返回值、返回值不是对象也不是函数、返回值是null)
    其他所有情况下执行var x = new X()时,构造函数会将this赋值给变量x,且会执行x.__proto__ = X.prototype,将实例化对象的原型设置为对应的类的prototype对象,从而实现对象的实例化。

参考

MDN - new operator
Stackoverflow - What values can a constructor return to avoid returning this?

以上是关于JavaScript中使用new操作符实例化对象时构造函数有返回值的情况分析的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript设计模式之工厂模式

javascript中new是啥意思

JS使用new操作符创建对象的方法分析

JavaScript中用new操作符创建对象的时候具体发生了啥过程

javascript中的new有啥用

JavaScript中啥是prototype原型对象?它有和作用?