web-dev-qa-db-ja.com

myObj.hasOwnProperty(prop)ではなくObject.prototype.hasOwnProperty.call(myObj、prop)を使用する理由

正しく理解すれば、Javascriptの各オブジェクトはObjectプロトタイプを継承します。つまり、Javascriptの各オブジェクトは、プロトタイプチェーンを通じてhasOwnProperty関数にアクセスできます。

Require.jsのソースコードを読んでいるときに、私はこの関数につまずきました。

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwnObject.prototype.hasOwnPropertyへの参照です。この関数を次のように書くことに実際的な違いはありますか

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

そして、私たちはそこにいるのに、なぜこの関数を定義するのでしょうか?それは、(わずかな)パフォーマンス向上のためのプロパティアクセスのショートカットとローカルキャッシュの問題ですか、またはこのメソッドを持たないオブジェクトでhasOwnPropertyが使用される可能性がありませんか?

78
timkg

[私の例の間に]実際的な違いはありますか?

ユーザーは、Object.create(null)で作成されたJavaScriptオブジェクトを持っている場合があり、null[[Prototype]]チェーンを持つため、hasOwnProperty()は使用できません。このため、2番目のフォームを使用すると機能しません。

また、Object.prototype.hasOwnProperty()へのより安全な参照です(またより短い)。

あなたは誰かがやったかもしれないと想像することができます...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

2番目の例のように実装すると、hasProp(someObject)が失敗します(Object.prototype.hasOwnPropertyに委任される代わりに、オブジェクト上でそのメソッドを直接見つけて呼び出します)。

しかし、誰かがObject.prototype.hasOwnProperty参照をオーバーライドする可能性は低くなります。

そして、私たちはそこにいるのに、なぜこの関数を定義するのでしょうか?

上記を参照。

これは、(わずかな)パフォーマンス向上のためのプロパティアクセスのショートカットとローカルキャッシュの問題ですか?.

[[Prototype]]チェーンに従う必要がないため、理論的にはquickerになるかもしれませんが、これは無視できると思われますnot実装が理由である理由。

...または、このメソッドを持たないオブジェクトでhasOwnPropertyが使用される可能性のあるケースがありませんか?

hasOwnProperty()Object.prototypeに存在しますが、オーバーライドできます。すべてのネイティブJavaScriptオブジェクト(ただし、ホストオブジェクトはこれに従うことが保証されていません RobGの詳細な説明を参照 )チェーンの最後のオブジェクトとしてnullの前にObject.prototypeがあります(もちろんObject.create(null)によって返されるオブジェクト)。

89
alex

正しく理解すれば、JavascriptのすべてのオブジェクトがObjectプロトタイプを継承します

髪を分割しているように見えるかもしれませんが、javascript(ECMAScript実装の総称)とECMAScript(javascript実装に使用される言語)には違いがあります。継承スキームを定義するのはECMAScriptであり、javascriptではないため、ネイティブECMAScriptオブジェクトのみがその継承スキームを実装する必要があります。

実行中のjavascriptプログラムは、少なくとも組み込みのECMAScriptオブジェクト(オブジェクト、関数、数値など)と、おそらくいくつかのネイティブオブジェクト(関数など)で構成されます。また、いくつかのホストオブジェクト(ブラウザ内のDOMオブジェクト、または他のホスト環境内の他のオブジェクトなど)を持つこともあります。

組み込みオブジェクトおよびネイティブオブジェクトはECMA-262で定義された継承スキームを実装する必要がありますが、ホストオブジェクトは実装しません。したがって、javascript環境のすべてのオブジェクトmustObject.prototypeを継承しません。たとえば、IE ActiveXオブジェクトとして実装されたホストオブジェクトは、ネイティブオブジェクトとして扱われるとエラーをスローします(そのため、try..catchを使用してMS XMLHttpRequestオブジェクトを初期化します)。一部のDOMオブジェクト(NodeLists in IE)Arrayメソッドに渡されるとエラーがスローされる場合、DOMオブジェクトin IE 8以下にはECMAScriptのような継承スキームがありません。等々。

したがって、javascript環境内のすべてのオブジェクトがObject.prototypeから継承されると想定しないでください。

つまり、JavaScriptの各オブジェクトは、プロトタイプチェーンを介してhasOwnProperty関数にアクセスできます。

IE quirksモード(およびIE 8以下は常に))の特定のHostオブジェクトには当てはまりません。

上記を考えると、オブジェクトが独自のhasOwnPropertyメソッドを持っている理由と、代わりに他のhasOwnPropertyメソッドを呼び出すことの妥当性を熟考する価値がありますそれが良いアイデアであるかどうかの最初のテストなし。

編集

Object.prototype.hasOwnProperty.callを使用する理由は、一部のブラウザでは、HostオブジェクトにhasOwnPropertyメソッドがなく、callおよび組み込みメソッドは代替です。ただし、一般的にそうすることは、上記の理由から、良いアイデアとは思えません。

Hostオブジェクトが関係する場合、in演算子を使用して、一般的にプロパティをテストできます。

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in IE 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

別の方法(IE6などでテスト済み):

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

この方法では、オブジェクトに含まれていない(継承または別の)組み込みhasOwnPropertyのみを具体的に呼び出します。

ただし、オブジェクトにhasOwnPropertyメソッドがない場合、おそらくオブジェクトには継承がないため、in演算子を使用するのと同じくらい適切です。スキームとすべてのプロパティはオブジェクト上にあります(ただし、これは単なる仮定です)。 in演算子は、プロパティに対するDOMオブジェクトのサポートをテストする一般的な(そして一見成功しているように見える)方法です。

13
RobG

JavaScriptはプロパティ名を保護しませんhasOwnProperty

オブジェクトにこの名前のプロパティがある可能性がある場合は、外部のhasOwnPropertyを使用して正しい結果を取得する必要があります。

理解を深めるために、以下のコードスニペットをブラウザコンソールにコピーして貼り付けることができます

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

常にfalseを返します

foo.hasOwnProperty('bar'); // false

別のオブジェクトのhasOwnPropertyを使用し、this fooに設定して呼び出します

({}).hasOwnProperty.call(foo, 'bar'); // true

この目的でObjectプロトタイプのhasOwnPropertyプロパティを使用することもできます

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
6
Sudharshan

両方の既存の回答に記載されている情報はすぐにわかります。ただし、次の使用:

('propertyName' in obj)

数回言及されます。 hasOwnProperty実装は、テスト対象のオブジェクトにプロパティが直接含まれている場合にのみtrueを返すことに注意してください。

in演算子も、プロトタイプチェーン全体を検査します。

これは、プロトタイププロパティがfalseを返すhasOwnPropertyに渡されると、インスタンスプロパティがtrueを返すことを意味します。

in演算子を使用すると、インスタンスプロパティとプロトタイププロパティの両方がtrueを返します。

1
steve