如何在JavaScript中为可调用对象创建构造函数?
我尝试了各种各样的方式,比如跟随。这个例子只是缩短了实际对象的例子。
function CallablePoint(x, y) {
function point() {
// Complex calculations at this point
return point
}
point.x = x
point.y = y
return point
}
这首先起作用,但它创建的对象不是CallablePoint
的实例,因此它不会复制CallablePoint.prototype
的属性并在false
上显示instanceof CallablePoint
。是否可以为可调用对象创建工作构造函数?
答案 0 :(得分:21)
事实证明它实际上是可能的。通过使用function
语法或Function
构造函数创建函数时,它将获取内部[[Call]]
属性。它不是函数本身的属性,而是任何函数在构造时获得的属性。
虽然这只意味着[[Call]]
的所有内容在构建时都只能Function
(好吧,有一个例外 - Function.prototype
本身不会从{{1}继承}),这并不意味着它在以后保留Function
属性时不能成为别的东西。好吧,如果您的浏览器不是IE< 11。
允许改变魔法的东西是来自ES6的[[Call]]
,已在许多浏览器中实现。 __proto__
是一个神奇的属性,包含当前的原型。通过更改它,我可以创建继承自非__proto__
的内容的函数。
Function
首先,function CallablePoint(x, y) {
function point() {
// Complex calculations at this point
return point
}
point.__proto__ = CallablePoint.prototype
point.x = x
point.y = y
return point
}
// CallablePoint should inherit from Function, just so you could use
// various function methods. This is not a requirement, but it's
// useful.
CallablePoint.prototype = Object.create(Function.prototype)
的构造函数使CallablePoint
(仅Function
s允许以Function
属性开头。接下来,我更改其原型,所以它会继承[[Call]]
。此时我有一个不从CallablePoint
继承的函数(有点令人困惑)。
在为Function
s定义构造函数后,我将CallablePoint
的原型设置为CallablePoint
,因此我Function
继承自CallablePoint
。< / p>
这样,Function
个实例具有原型链:CallablePoint
,同时仍然可以调用。此外,由于该对象是可调用的,因此根据规范,CallablePoint -> Function -> Object
等于typeof
。
答案 1 :(得分:1)
我会写下我的答案,假设您在Python中可用的__call__
功能之后,通常被称为&#34;可调用对象&#34;。 &#34;可调用对象&#34;在JavaScript环境中听起来很陌生。
我已经尝试了几个JavaScript引擎,但是我尝试过的任何一个都不允许你调用对象,即使你继承自Function
。例如:
function Callable(x) {
... "use strict";
... this.__proto__ = Function.prototype;
... this.toString = function() { return x; };
... }
undefined
> var c = new Callable(42);
var c = new Callable(42);
undefined
> c;
c;
{ toString: [function] }
> c(42);
c(42);
TypeError: Property 'c' of object #<Object> is not a function
at repl:1:1
at REPLServer.eval (repl.js:80:21)
at repl.js:190:20
at REPLServer.eval (repl.js:87:5)
at Interface.<anonymous> (repl.js:182:12)
at Interface.emit (events.js:67:17)
at Interface._onLine (readline.js:162:10)
at Interface._line (readline.js:426:8)
at Interface._ttyWrite (readline.js:603:14)
at ReadStream.<anonymous> (readline.js:82:12)
> c instanceof Function;
c instanceof Function;
true
c.apply(null, [43]);
TypeError: Function.prototype.apply was called on 43, which is a object and not a function
at Function.APPLY_PREPARE (native)
at repl:1:3
at REPLServer.eval (repl.js:80:21)
at repl.js:190:20
at REPLServer.eval (repl.js:87:5)
at Interface.<anonymous> (repl.js:182:12)
at Interface.emit (events.js:67:17)
at Interface._onLine (readline.js:162:10)
at Interface._line (readline.js:426:8)
at Interface._ttyWrite (readline.js:603:14)
>
这是V8(Node.js)。即你可能有一个对象,它正式继承自函数,但它不可调用,我找不到一种方法来说服运行时它可能被调用。我在Mozilla的JavaScrip实现中有类似的结果,所以我认为它必须是通用的。
然而,自定义类型在JavaScript中的作用非常小,所以我认为你无论如何都会错过它。但是,正如您已经发现的那样,您可以在函数上创建属性,就像在对象上一样。所以,你可以用一种不太方便的方式来做到这一点。
答案 2 :(得分:0)
如果您使用CallablePoint
关键字,我不确定您是否知道您的对象只是new
的实例。通过将其命名为“可调用”,您可以让我认为您想要使用new
。无论如何,有一种方法可以强制返回一个实例(感谢提示,Resig):
function CallablePoint(x, y) {
if (this instanceof CallablePoint) {
// Your "constructor" code goes here.
// And don't return from here.
} else {
return new CallablePoint(x, y);
}
}
这将返回CallablePoint
的实例,无论它是如何被调用的:
var obj1 = CallablePoint(1,2);
console.log(obj1 instanceof CallablePoint); // true
var obj2 = new CallablePoint(1,2);
console.log(obj2 instanceof CallablePoint); // true
答案 3 :(得分:-1)
如果您希望CallablePoint()
构造函数返回CallablePoint类型的对象,那么您可以执行类似这样的操作,其中CallablePoint对象包含一个点作为对象的属性,但仍然是CallablePoint对象:
function CallablePoint(x, y) {
this.point = {};
this.point.x = x
this.point.y = y
}
或者,如果您真正想做的是创建一个返回CallablePoint对象的函数,那么您可以创建一个因子函数:
function CallablePoint(x, y) {
this.point = {};
this.point.x = x
this.point.y = y
}
function makeCallablePoint(x, y) {
return new CallablePoint(x,y);
}