JavaScript中可调用对象的构造方法

时间:2012-09-29 20:08:46

标签: javascript constructor callable

如何在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 。是否可以为可调用对象创建工作构造函数?

4 个答案:

答案 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);
}