在开发 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/