myObj.hasOwnProperty(prop)の代わりにObject.prototype.hasOwnProperty.call(myObj、prop)を使用する理由


104

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

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

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

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

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

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

回答:


109

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

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

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

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

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

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

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

そして、私たちがそうしているので、なぜこの関数をまったく定義しないのですか?

上記を参照。

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

それは作ることが速くて、理論的には[[Prototype]]チェーンが続いする必要はありませんが、私は、これは無視できるとする疑いがないことがある理由の実装がある理由。

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

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


あなたの論理はおそらく正しいですが、私はあなたが親切にしていると思います。require.jsの作成者がhasOwnPropertyがオーバーライドされた可能性があると考える場合(これは非常にまれです)、すべての組み込みメソッドをそのように呼び出す必要があります(おそらくそうします)。
RobG 2012

@Periback本当に?私はそれがそれをサポートしていると確信していました。
アレックス、2015年

頻繁に使用する場合はES6ショートカット。const hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
Richard Ayotte 2017

15

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

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

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

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

したがって、JavaScript環境のすべてのオブジェクトがObject.prototypeを継承するとは限りません。

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

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

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

編集する

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

ホストオブジェクトが関係する場合、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オブジェクトサポートをテストする一般的な(そして一見成功している)方法です。


ありがとう。Object.prototype.hasOwnProperty.call(o、 'bar')はFF 18.0では機能しません(少なくとも私の場合)。だから私は(oの 'bar')を使うことにしました-そしてそれは助けになりました
最大

@Max inhasOwnProperty()ルックアップを実行しません。探していたプロパティがプロトタイプチェーンに存在していたと思います。
アレックス

これはeslint.org/docs/rules/no-prototype-builtinsの興味深い例ですたとえばhasOwnProperty、悪意のあるクライアントがクライアントからのJSON入力を解析して結果のオブジェクトを直接呼び出すことは、Webサーバーにとって安全ではありません。のようなJSON値を送信し{"hasOwnProperty": 1}、サーバーをクラッシュさせます。
naught101

もちろん、クライアントが提供するJSONをJSONスキーマでテストまたは検証して、問題がデータ品質だけである場合でも、このような問題を回避することをお勧めします。また、サーバーがクラッシュすることはありません。:-)
RobG

8

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

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

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

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

常にfalseを返します

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

別のオブジェクトのhasOwnPropertyを使用してそれを呼び出す これをfooに設定して

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

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

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

1
あなたが作っているポイントは、リターンのオーバーライドがあることを除いて、受け入れられた回答ですでに行われていhasOwnPropertyますtrue
ルイ

1

既存の回答の両方に記載されている情報は適切です。ただし、以下の使用:

('propertyName' in obj)

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

inオペレータは、あまりにもプロトタイプチェーンを通して下方検査します。

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.