An old dog learns code

恶趣味构造函数

October 29, 2018



引子

理论上说,只要对函数使用new语法,任何function都可以作为constructor创建新实例,但是如果function不按常理出牌呢?还可以实现创建新实例的目标吗?

注:本文内容为JavaScript Ninja的读书笔记。

带返回值的构造函数

  1. 返回值为基本类型
function retPrimType() {
  this.value = 'I am a function returning a primitive type';
  this.getMyThis = function() {
    return this;
  };
  return 'I return a new Object as this';
}

const a = new retPrimType();
console.log(retPrimType()); //'I return a new Object as this'
console.log(a.getMyThis() === a); //true
  1. 返回值为对象
const ref = { key: 'object' };
function retObjectType() {
  this.value = 'I am a funtion returning an Object';
  this.getMyThis = function() {
    return this;
  };
  return ref;
}

const b = new retObjectType();
console.log(retObjectType()); //{key:'object'}
console.log(b.getMyThis === b); // error: b.getMyThis is not a function
console.log(b === ref); //true

const c = new retObjectType();
console.log(b === c); //true
  1. 小结

    • function返回基本类型,new之后其返回值被忽略,依然能够创建新实例,并且this的指向正确
    • function返回对象,new 之后该对象将被返回,无法创建新实例

一点引申: 单例模式

开一点脑洞,如果要求某个对象使用new后只能返回同一个实例,即实现单例模式,如何利用上面的结论来实现?

const singleton = (function() {
  const retObj = { key: 'I am singleton!' };
  return function() {
    return retObj;
  };
})();
const a = new singleton();
const b = new singleton();
console.log(a === b); //true
a.key = 'everyone changes with me';
console.log(a); //{key: 'everyone changes with me'}
console.log(b); //{key: 'everyone changes with me'}

用 IIFE+闭包构造一个singleton对象,它的值就是内层匿名函数,可以访问其外层自由变量retObj。按照上面总结的规则,每当对singleton执行new操作时,它总是会返回对象retObj,这样就实现了恶趣味单例模式。