28

私は JavaScript 関数オブジェクトを次のように持っています。

var addNum = function(num1, num2) {
        return num1 + num2;
}

今アクセスしようとすると

addNum.divide()

上記のコードのプロトタイプ チェーンを理解したかったのです。上記の例では、addNum は、divide() で検索され、続いて Function.prototype が検索され、最後に Object.prototype が検索されることを読みました。

しかし、私の質問は上記の例にあります。

のようなものを指していますか?

var addNum = function(num1, num2) {

this.divide = function(){}

            return num1 + num2;
    }

addNum が Division() で検索されると書かれている行を理解できませんでした

同じことを理解するのを手伝ってください。

4

5 に答える 5

55

これがあなたの質問に答えるかどうかはわかりませんが、いくつかの洞察を与えるかもしれません. 次の例を検討してください。

var Person = (function () {
    var Person = function (name) {
        this.name = name;
    }

    Person.greet = function () {
        console.log("Hello!");
    }

    Person.prototype = {
        greet: function () {
            console.log('Hello, my name is ' + this.name);
        }
    };
    return Person;
})();

var bob = new Person("Bob");

Person.greet(); // logs "Hello!"
bob.greet(); // logs "Hello, my name is Bob

関数オブジェクト「Person」には、関数である直接の「greet」プロパティがあります。OOP に関して言えば、これはほとんどの場合、Person 関数 (Person.greet()) から直接呼び出すことができる静的メソッドと考えることができます。Person コンストラクターから person オブジェクトを「インスタンス化」すると、その新しいオブジェクト「bob」は Person.prototype オブジェクトのメソッドを参照します。これで、bob.greet() を呼び出すと、プロトタイプ オブジェクトでgreet 関数が使用されます。

それが役立つことを願っています。

于 2013-03-02T12:18:51.403 に答える
24

あなたが自分でそう言うように:あなたは関数オブジェクトを持っています。関数は、オブジェクトリテラル、配列、またはその他のものと同じように、JSのオブジェクトです。関数には、プロパティとメソッドを自由に割り当てることができます。

var someAnonFunction = function(foo)
{
    console.log(this);
    console.log(this === someAnonFunction);//will be false most of the time
};
someAnonFunction.x = 123;//assign property
someAnonFunction.y = 312;
someAnonFunction.divide = function()
{
    console.log(this === someAnonFunction);//will be true most of the time
    return this.x/this.y;//divide properties x & y
};
someAnonFunction.divide();

この場合、によって参照される関数オブジェクトにはsomeAnonFunction、呼び出される無名関数への参照が割り当てられていますdivide(無名関数への参照はとにかくdivideと呼ばれていました)。したがって、ここにはプロトタイプの関与はまったくありません。自分で言うように、気をつけてください。すべてのオブジェクトはさかのぼることができます。Object.prototypeこれを試してみてください。

console.log(someAnonFunction.toString === Function.prototype.toString);//functions are stringified differently than object literals
console.log(someAnonFunction.hasOwnProperty === Object.prototype.hasOwnProperty);//true

または、おそらくこれはより明確です:メソッド/プロパティ呼び出しがJSの値に解決される方法の単純なスキーム:

[      F.divide      ]<=========================================================\ \
F[divide] ===> JS checks instance for property divide                           | |
 /\ ||                                                                          | |
 || || --> property found @instance, return value-------------------------------| |
 || ||                                                                          | |
 || ===========> Function.prototype.divide could not be found, check prototype  | |
 ||      ||                                                                     | |
 ||      ||--> property found @Function.prototype, return-----------------------| |
 ||      ||                                                                     | |
 ||      ==========> Object.prototype.divide: not found check prototype?        | |
 ||          ||                                                                 | |
 ||          ||--> property found @Object.prototype, return---------------------|_|
 ||          ||                                                                 |=|
 ||          =======>prototype is null, return "undefined.divide"~~~~~~~~~~~~~~~|X|
 ||                                                                             \ /
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< TypeError can't read property 'x' of undefined

したがって、上記のコードをプロトタイプを使用して機能させる場合は、ある種のプロトタイプ(この場合はFunction.prototype)を拡張する必要があります。これは推奨されるべきではないことを知っておいてください。実際、「ネイティブ」プロトタイプの変更はしばしば眉をひそめます。まだ:

Function.prototype.divide = function (a, b)
{
    a = +(a || 0);//coerce to number, use default value
    b = +(b || 1) || 1;//division by zeroe is not allowed, default to 1
    return a/b;
};
function someFunction ()
{
    return 'someString';
};
var another = function(a, b)
{
    return a + b;
};
someFunction.divide(12, 6);//will return 2
another.divide(12, 4);//3

someFunctionどちらの場合も、名前(または)で参照される関数オブジェクトは、見つからないという名前anotherのプロパティをスキャンされます。次に、そのようなプロパティが見つかったdivideをスキャンします。 そうでない場合、JSはチェックも行います。それが失敗した場合、最終的にエラーがスローされます。Function.prototype
Object.prototype

私はしばらく前にこの主題に関するSOについてかなり長い回答を投稿しました:

my.class.jsがこれほど高速になる理由は何ですか?(プロトタイプチェーンを扱う)
javascriptのオブジェクトと関数(関数の要約<=>オブジェクト<=>コンストラクター)
JavaScriptの「クラス」定義のこれら3つのパターンの違いは何ですか?(まだ少し情報があります)
Javascript-関数の内容を動的に変更します(無名関数に漠然と触れ、変数とプロパティに割り当てられ、それらのコンテキストを変更します)

于 2013-03-02T12:31:51.907 に答える
3

divide[一種の]staticメソッドとして作成できます。

var addNum = function(num1, num2) {
  addNum.divide = function(){return num1/num2;};
  return num1 + num2;
}
// now you first have to run addNum
var onethirds = addNum(1,3); //=> 4
addNum.divide(); //=> 0.333333...

ただし、お勧めできません。コンストラクター関数を作成することをお勧めします。

function Pair(n1,n2){
   n1 = n1 || 1;
   n2 = n2 || 1;
   // create instance methods
   this.add      = function(){return n1+n2;};
   this.divide   = function(){return n1/n2;};
   this.multiply = function(){return n1*n2;}
}
var pair1 = new Pair(2,6)
   ,pair2 = new Pair(1,2);
pair1.add();    //=> 8
pair2.divide(); //=> 0.5
//etc.

または、よりプロトタイプ的なアプローチ(メソッドは、すべてのインスタンスではなく、コンストラクターのプロトタイプに追加されます):

function Pair(n1,n2){
   this.n1 = n1 || 1;
   this.n2 = n2 || 1;
   // create prototype methods (once)
   if (!Pair.prototype.add){
    var proto      = Pair.prototype;
    proto.add      = function(){return this.n1+this.n2;};
    proto.divide   = function(){return this.n1/this.n2;};
    proto.multiply = function(){return this.n1*this.n2;}
   }
}

ものを読む

于 2013-03-02T12:34:54.960 に答える
2

addNumいいえ、最後のコードは、コンストラクター関数として使用した場合にのみ意味があります。

var instance = new addNum();
instance.divide();

ただし、関数はオブジェクトであるため、次は有効です。

var addNum = function(num1, num2) {
        return num1 + num2;
}
addNum.divide = function() {}

この場合、プロトタイプのいずれかではなく、それ自体divideのプロパティになります。addNum

于 2013-03-02T12:24:42.553 に答える
0

プロトタイプの継承を理解することは、最初はやや不明瞭ですが、その名前が示すように考えてみてください。JavaScript にはいくつかのプロトタイプがあり、Function はその 1 つです。

新しい関数を作成するときはいつでも、コマンドでそのタイプを確認できますtypeof。あなたの場合:

var a = function(a,b) { return a + b; }

返さ"function"れるので、a変数にさらにメソッドを追加するには2つの方法があります。@Keith Morrisが示唆したように、新しいコンストラクターを作成し、そのメソッドを内部に配置して返すことです。これは、基本的なオブジェクトを、それらによって表されるすべてのオブジェクトに拡張されるプロトタイプのメソッドで汚染しないため、推奨される方法でもあります。

つまり、代わりにこれを行うと:

Function.prototype.divide = function(a, b) { return a / b; }

私は今できるしa.divide(2, 1);、それが返され2ます。しかし、たとえば、使用jQueryして行うと、関数の直接のスコープでそれを見つけようとするため、jQuery.divide(2,1)取得することもできます。2そうでない場合は、そのプロトタイプに移動します。

これがあなたにそれをもう少しよく説明することを願っています.

于 2013-03-02T12:25:53.803 に答える