web-dev-qa-db-ja.com

JavaScript関数オブジェクトのプロパティ

JavaScript関数オブジェクトがあります。

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

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

addNum.divide()

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

しかし、私の質問は上記の例にあり、div()をaddNumで検索する方法

それは次のようなものを指しますか?

var addNum = function(num1, num2) {

this.divide = function(){}

            return num1 + num2;
    }

AddNumがDivide()を検索するという行を理解できませんでした

同じことを理解してください。

24
testndtv

これがあなたの質問に答えるかもしれませんが、洞察を与えるかもしれません。次の例を考えてみましょう。

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

お役に立てば幸いです。

51
Keith Morris

あなた自身がそう言っているように:あなたには関数objectがあります。関数は、オブジェクトリテラル、配列などと同様に、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)を追加する必要があります。これは推奨されるものではないことを知ってください。実際、 "native"プロトタイプの変更はしばしば眉をひそめます。それでも:

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と呼ばれるプロパティをスキャンします。ただし、そのようなプロパティが見つかったFunction.prototypeをスキャンします。
それが当てはまらない場合、JSはObject.prototypeもチェックし、失敗した場合、最終的にエラーをスローします。

私はSOにかなり長い回答をこのテーマについてしばらく前に投稿しました:

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

19

divideを[sort of a] 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...

しかし、それはお勧めできません。 constructor 関数をより良く作成します:

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

読み物

3
KooiInc

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

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

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

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

この場合、divideは、プロトタイプの1つではなく、addNum自体のプロパティになります。

2

プロトタイプの継承を理解することは、最初は多少わかりにくいですが、名前が示すように、JavaScriptにはいくつかのプロトタイプがあり、Functionはその1つです。

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

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

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

意味、代わりにこれを行う場合:

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

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

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

0
gmaliar