代码之家  ›  专栏  ›  技术社区  ›  sasensi

令人惊讶的实例化模式-包装函数上使用的新关键字

  •  0
  • sasensi  · 技术社区  · 7 年前

    在工作 Paper.js 库,我在代码库中发现了一种实例化我以前从未使用过的类的方法。例如 here 实例化 Shape 班级。
    这个实例化模式可以简化为:给定 Ball 类与A createBall() 实例化它的方法:

    function Ball() {}
    function createBall() {return new Ball()}
    

    当然,我们可以通过以下方式获得一个球实例:

    var ball = createBall();
    

    但更令人惊讶的是,我们也可以通过调用(注意 new 关键字):

    var ball = new createBall();
    

    或者更抽象地说:

    var ball = new function() {return new Ball()};
    

    自从 创建BAL() 返回A 球 例如,它给人的印象是我们正在实例化 球 通过使用类 新的 它的一个实例上的关键字。

    但正如我们在下面的代码中看到的,这是不允许的,如果我们手动执行,就会引发错误:

    var ball1 = new Ball();
    var ball2 = new ball1();
    // error: ball1 is not a constructor
    

    有人能解释一下这背后的逻辑吗?

    下面是不同实例化方法的比较示例:

    // Class
    function Ball() {}
    
    // Method creating an instance of the class
    function createBall() {
      // Instantiate the class
      var ball = new Ball();
      // Return the instance
      return ball;
    }
    
    // Expected: instantiating directly works
    var ball1 = new Ball();
    console.log('ball1', ball1 instanceof Ball); // outputs true
    
    // Expected: instantiating through the creation method works
    var ball2 = createBall();
    console.log('ball2', ball2 instanceof Ball); // outputs true
    
    // Unexpected: instantiating like this surprisingly works
    var ball3 = new createBall();
    console.log('ball3', ball3 instanceof Ball); // outputs true
    
    // Expected: instantiating like this throws an error
    var ball4 = new ball1();
    // error: ball1 is not a constructor

    编辑

    在阅读了@robert zigmond评论之后,我发现了另一个误导性的案例:

    function Dog() {}
    
    function Ball() {
      return new Dog();
    }
    
    var instance = new Ball();
    
    console.log('is instance a Ball ?', instance instanceof Ball); // false
    console.log('is instance a Dog ?', instance instanceof Dog); // true
    2 回复  |  直到 7 年前
        1
  •  2
  •   Robin Zigmond    7 年前

    ball1 甚至不是一个函数,所以这就是为什么会出现错误的原因。

    可以使用new操作符调用javascript中的任何函数——本质上,这使得它构造了一个新的对象,该对象被视为 this 对函数的引用,并返回它(但仅当函数尚未返回对象时,如果返回对象,则会丢弃构造的对象)。

    看看这里到底是什么 new 操作员: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new#Description

    你的“其他误导性案例”一开始看起来确实令人困惑,因为 instance 定义为 new Ball() 但 instance instanceof Ball 收益率 false . 这是因为,正如我上面所说,“构造函数函数”只返回新构造的对象,否则它将返回一个根本不是对象的值。在大多数设计用作构造函数的函数中,实际上没有显式返回值-因此返回值是隐式的 undefined ,因此返回新构造的对象。

    但在本例中,函数将返回一个对象,该对象是 Dog -所以这个对象最终是 实例 .虽然创建于 新的BAR() 这是间接的 真正地 通过调用创建 new Dog() 因此 Dog.prototype 在它的原型链中,而不是 Ball.prototype . 这就解释了 instanceof 你观察到的接线员。

        2
  •  1
  •   Sean    7 年前

    什么时候? new Function 被称为

    1. 创建了一个新对象,继承了function.prototype
    2. 调用构造函数,并将其绑定到第一步创建的新对象。
    3. 如果没有返回任何内容,则将返回该对象,或者您可以像示例一样返回一个新对象。

    function createBall() { console.log('origin this', this); return new Ball(); } 什么时候? new createBall() 它创建了一个继承自createfoo.prototype的新对象。 this ,如果没有返回任何内容,则此对象将成为 新建CreateBall() 但在这里你返回一个 new Ball() 所以 这 对象已更改为 new Foo() 归还