121

私が正しく理解していれば、JavaScriptのすべてのオブジェクトはObjectプロトタイプから継承します。つまり、JavaScriptのすべてのオブジェクトは、プロトタイプチェーンを介してhasOwnProperty関数にアクセスできます。

RequireJSのソースコードを読んでいるときに、この関数に出くわしました。

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

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

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

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

4

6 に答える 6

127

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

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

これは、より安全なObject.prototype.hasOwnProperty()(そしてより短い)参照でもあります。

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

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

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

ただし、誰かが参照を上書きする可能性は低くなりObject.prototype.hasOwnPropertyます。

そして、私たちはそれに取り組んでいるので、なぜこの関数を定義するのですか?

上記を参照。

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

チェーンをたどる必要がないため、理論的にはより速くなる可能性がありますが、これは無視できるものであり、実装が理由ではないのではないかと思います。[[Prototype]]

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

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

于 2012-08-18T10:11:01.853 に答える
18

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

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

実行中のJavaScriptプログラムは、少なくとも組み込みのECMAScriptオブジェクト(Object、Function、Numberなど)と、おそらくいくつかのネイティブオブジェクト(関数など)で構成されています。また、いくつかのホストオブジェクト(ブラウザのDOMオブジェクト、または他のホスト環境の他のオブジェクトなど)が含まれている場合もあります。

組み込みオブジェクトとネイティブオブジェクトはECMA-262で定義されている継承スキームを実装する必要がありますが、ホストオブジェクトは実装しません。したがって、JavaScript環境のすべてのオブジェクトがObject.prototypeから継承する必要はありません。たとえば、ActiveXオブジェクトとして実装されたInternet Explorerのホストオブジェクトは、ネイティブオブジェクトとして扱われるとエラーをスローします(したがって、try..catchを使用してMicrosoft XMLHttpRequestオブジェクトを初期化します)。一部のDOMオブジェクト(QuirksモードのInternet ExplorerのNodeListsなど)は、Arrayメソッドに渡されるとエラーをスローし、Internet Explorer 8以下のDOMオブジェクトには、ECMAScriptのような継承スキームがありません。

したがって、JavaScript環境内のすべてのオブジェクトがObject.prototypeから継承すると想定するべきではありません。

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

これは、少なくともQuirksモード(およびInternet Explorer 8以下)のInternetExplorerの特定のホストオブジェクトには当てはまりません。

上記を考えると、オブジェクトが独自のhasOwnPropertyメソッドを持っている理由と、それが良いアイデアかどうかを最初にテストせずに、代わりに他のhasOwnPropertyメソッドを呼び出すことをお勧めします。

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

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

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

// false in most browsers, throws an error in Internet Explorer 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');

別の方法( Internet Explorer 6などでテスト済み):

function ownProp(o, prop) {

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

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

そうすれば、オブジェクトに(継承されているかどうかにかかわらず)組み込まれていないhasOwnPropertyのみを具体的に呼び出すことができます。

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

于 2012-08-18T13:29:00.920 に答える
1

ここでの残りの回答に加えて、より簡潔で短いコードを記述できるようにする代わりに、新しい方法Object.hasOwn(ほとんどのブラウザーでサポートされており、残りのブラウザーでもすぐにサポートされる予定です)を使用できることに注意してください。Object.hasOwnProperty.call

詳細Object.hasOwn- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn

ブラウザーの互換性 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn#browser_compatibility

于 2021-09-28T13:20:47.617 に答える