2012-09-29 13 views
10

JavaScriptで呼び出し可能オブジェクトのコンストラクタを作成するにはどうすればよいですか?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からプロパティをコピーしないとinstanceof CallablePointfalseを言います。呼び出し可能オブジェクトの作業コンストラクタを作成することは可能ですか?

+2

あなたは 'function point(){return point}'が関数自体を返すだけであることは知っていますか?あなたはこれで何をしようとしていますか? 'p()()()()()()()()()'を実行することができますが、そのポイントは何ですか? (意図された馬小屋)。 –

+2

@FelixKling分かりやすく私はこの質問に答えることを拒否しなければならなかった – Pointy

+0

完全性のために、ES6はもっと良い解決策を持っています。http://stackoverflow.com/questions/36871299/how-to-extend-function-with -es6-classes – 0xc0de

答えて

19

実際は可能です。ファンクションが作成されると、function構文またはFunctionコンストラクタのいずれかを使用して、内部の[[Call]]プロパティが取得されます。それは関数自体のプロパティではなく、構築されたときに関数が取得するプロパティです。それは後で何か他のものになることができないという意味ではありません

ことが唯一の[[Call]]を使って何がそれが構築されていますのみFunctionときかもしれないことを意味しますが(まあ、Functionから継承しない唯一の例外– Function.prototype自体があります)、 [[Call]]プロパティを保持しています。あなたのブラウザがIEでない場合< 11.

魔法を変えることができるものは、すでに多くのブラウザで実装されているES6の__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(のみFunction sが、私は、そのプロトタイプを変更[[Call]]プロパティ。次で始まるが許可されているので、それはCallablePointを継承します。この時点で私はdoesnの機能を持っています「tはFunction(混乱の一種)を継承しています。

私はCallablePoint秒のコンストラクタを定義した後、私はFunctionCallablePointのプロトタイプを設定するので、私はFunctionから継承CallablePointを持っている。

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

-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); 
} 
+0

私は思っています*戻り値が関数であることを望みます。私はなぜ、しかし、理解することはできません。 – Pointy

+0

@Pointy - 私はOPが何をしようとしているのかがはっきりしていないことに同意します。私は別のオプションを追加しました。 – jfriend00

+2

あなたの 'point.x'は' this.point'で作成したものではありません – Alnitak

0

私はあなたがしているかどうかわからないんだけどあなたのオブジェクトはインスタンスに過ぎないことに気付くnewというキーワードを使用すると、CallablePointとなります。それを「呼び出し可能」と命名すると、にはnewを使用しないと思っています。かかわらず、それが呼ばれたかのこれはCallablePointのインスタンスを返します

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

:とにかく、返されるインスタンスを強制する方法(先端に感謝、Resig)がある

var obj1 = CallablePoint(1,2); 
console.log(obj1 instanceof CallablePoint); // true 

var obj2 = new CallablePoint(1,2); 
console.log(obj2 instanceof CallablePoint); // true 
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のカスタムタイプの役割は非常に小さいので、とにかくそれをそれほど欠けているとは思わないでしょう。しかし、すでに発見したように、オブジェクトの場合と同じ方法で、関数のプロパティを作成することができます。だから、それほど簡単ではない方法でそれを行うことができます。

関連する問題