12

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

4 に答える 4

21

それは実際に可能であることが判明しました。function構文またはコンストラクターを使用して関数を作成すると、Function内部[[Call]]プロパティを取得します。これは関数自体のプロパティではなく、関数が構築されたときに取得するプロパティです。

[[Call]]それは、それが構築されたときにのみ存在する可能性があることを意味しFunctionますが(1つの例外があります-Function.prototypeそれ自体はから継承されません)、それはプロパティFunctionを保持しながら後で何かになることができないことを意味しません。[[Call]]ええと、あなたのブラウザがIE<11でなければ。

魔法を変えることができるのは__proto__、すでに多くのブラウザに実装されているES6からのものです。__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まず、 makesのコンストラクターFunctionFunctionsのみがプロパティで開始でき[[Call]]ます。次に、プロトタイプを変更して継承しCallablePointます。この時点で、継承しない関数がありFunctionます(混乱を招きます)。

sのコンストラクターを定義した後CallablePoint、のプロトタイプをに設定したCallablePointのでFunctionCallablePointから継承しFunctionます。

このように、CallablePointインスタンスにはプロトタイプチェーンがあります:CallablePoint -> Function -> Object、まだ呼び出し可能です。また、オブジェクトは呼び出し可能であるため、仕様に従って、にtypeof等しくなり'function'ます。

于 2013-06-14T14:59:14.117 に答える
1

__call__あなたがPythonで利用可能な機能を求めていて、しばしば「呼び出し可能オブジェクト」と呼ばれることを前提として、私の答えを書きます。「呼び出し可能オブジェクト」は、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でのカスタム型の役割はほとんどないので、とにかくそれを見逃すことはないと思います。ただし、すでに発見したように、オブジェクトの場合と同じように、関数のプロパティを作成できます。ですから、あまり便利ではない方法でそれを行うことができます。

于 2012-09-29T23:04:35.587 に答える
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
于 2012-09-29T22:40:43.410 に答える
-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);
}
于 2012-09-29T20:13:54.227 に答える