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

标签 javascript new-operator instantiation

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

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

当然,我们可以通过调用来获取球实例:

var ball = createBall();

但更令人惊讶的是,我们还可以通过调用(注意 new 关键字)来获取球实例:

var ball = new createBall();

或者作为更抽象的方式:

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

由于 createBall() 返回一个 Ball 实例,因此给人的印象是我们正在使用 new 实例化 Ball 其实例上的关键字。

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

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

最佳答案

ball1 甚至不是一个函数,所以这就是您在那里收到错误的原因。

Javascript 中的任何函数都可以使用 new 运算符来调用 - 本质上,这会使其构造一个新对象,该对象被视为函数的 this 引用,并返回它(但前提是函数尚未返回对象 - 如果返回,则构造的对象将被丢弃)。

请参阅此处了解 new 运算符的具体用途:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new#Description

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

但在此示例中,该函数将返回一个对象,该对象是 Dog 的实例 - 因此该对象最终作为 实例。虽然是通过 new Ball() 创建的,但这有点间接,它实际上是通过调用 new Dog() 创建的,因此 Dog.prototype 位于其原型(prototype)链中,而不是 Ball.prototype 中。这解释了您观察到的 instanceof 运算符的行为。

关于javascript - 令人惊讶的实例化模式 - 在包装函数上使用新关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53378738/

相关文章:

javascript - 如何隐藏 HTML 文本直到被点击

c++ - 为什么我的全局 new() 覆盖被绕过?

iphone - 应用程序首次运行时加载所有选项卡栏 View

C++ unique_ptr 单独声明和实例化

javascript - 根据元素的类显示工具提示文本

javascript - 在鼠标点击位置显示 div,占滚动

php - 为 iSpeech 创建 Send-to Hook

使用 new 运算符和 .class.newInstance() 方法创建 java 对象

c++ - 您应该能够分配多少内存?

c++ - C++ 参数列表中实例化对象的内存管理