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?

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值