3

これは初心者の質問かもしれませんが、説明を見つけたり考えたりすることができません。

Node.js コンソールを開始し、次のことを行います。

> global.hasOwnProperty === hasOwnProperty
true

それでなんで

> global.hasOwnProperty("x")
false

しかし

> hasOwnProperty("x")
TypeError: Cannot convert undefined or null to object
at hasOwnProperty (<anonymous>)
at repl:1:1
at sigintHandlersWrap (vm.js:22:35)
at sigintHandlersWrap (vm.js:96:12)
at ContextifyScript.Script.runInThisContext (vm.js:21:12)
at REPLServer.defaultEval (repl.js:313:29)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
at REPLServer.<anonymous> (repl.js:513:10)
at emitOne (events.js:101:20)

?

4

4 に答える 4

3

ここでの問題は、それhasOwnProperty()がオブジェクトのメソッドであり、その機能全体がそのオブジェクトのプロパティを操作することです。そのため、呼び出されたときに適切なオブジェクト コンテキストが与えられた場合にのみ機能します。通常、これらはメソッドとして記述されておりthis、メソッドが呼び出されたときにオブジェクト コンテキストが の値に到達することを期待します。

JavaScript のほとんどの場合 (アロー構文で定義された関数を除く)、 の値はthisメソッドの呼び出し方法によって決まります。適切なオブジェクトでメソッドを呼び出す通常の最も一般的な方法は、次のとおりです。

obj.method()

これにより、JavaScript が呼び出されたときにが設定thisされます。objmethod()

次のようなことをすると:

var myFunction = obj.method;

そして、次のようにオブジェクト参照なしでそのメソッドを呼び出します。

var myFunction = obj.method;
myFunction();

次に、オブジェクト参照objが失われ、メソッドに渡されません。JavaScript インタープリターは、のデフォルト値を選択しますthis

厳密モードでthisは、 に設定されundefined、その値を使用しようとするメソッドは、オブジェクト参照であると想定して失敗します。

非厳密モードでは、ブラウザはthis「何らかのデフォルト値」を指すように設定されます。ブラウザでは、それがwindowオブジェクトです。そのため、window オブジェクトでメソッドを使用しようとしている場合、見よ、それはたまたま機能します。私はこれを多少の事故であり、良いコードではないと考えています。

IMO、物語の教訓は、オブジェクトに関連付けられることを期待するメソッドは、明示的なオブジェクト参照で呼び出す必要があるということです。次に、すべての混乱を取り除き、厳密モードと非厳密モードの間のすべての違いを取り除き、ブラウザーと Node.js の間のすべての違いを取り除きます。

では、なぜこれが起こるのですか:

hasOwnProperty("x")

TypeError: undefined または null をオブジェクトに変換できません

hasOwnProperty()node.js でグローバル オブジェクトのプロパティをテストするために呼び出しようとしている場合は、次のようにglobalオブジェクトのコンテキストでメソッドを呼び出します。

global.hasOwnProperty("a")

これはどこでも機能し、優れた適切な Javascript コードと見なされます。適切なオブジェクト コンテキストなしで呼び出すと、this値が既定値に設定されます。node.js では、そのデフォルト値が必ずしもグローバル オブジェクトになるとは限りません。しかし、どのような場合でも、そのデフォルト値に依存するべきではありません。目的のオブジェクト参照を常に指定して正しくプログラミングすれば、コードはどこでも正常に動作します。


this参考までに、関数に渡されるものを制御する方法は、単にobj.method(). 他の方法については、こちらの他の回答をご覧ください。それらには.call()、 、.apply()、アロー関数 ( ES6の場合) などが含まれます...

于 2017-01-05T22:55:29.783 に答える
1

ご利用の際はhasOwnProperty("x")

  1. hasOwnProperty識別子です。ランタイム セマンティクスを参照してください

  2. 識別子は、 GetIdentifierReferenceを呼び出すResolveBindingを使用して解決されます

  3. おそらくいくつかの再帰の後、これは参照を生成します

    { base: globalEnvRec, referencedName: "hasOwnProperty", strict: strictFlag }
    
  4. それからあなたはそれを呼びます。ランタイム セマンティクスを参照してください

  5. 次のように、GetValueを使用して関数を取得します。

    1. グローバル環境レコードのGetBindingValueを呼び出します
    2. 宣言されたバインディングがないと仮定すると、オブジェクト レコードのGetBindingValueが呼び出されます。
    3. それはバインディングオブジェクトでGetを呼び出します
  6. 参照のベースは環境レコードであるため、はグローバル環境レコードのWithBaseObjectthisValueから取得され、常に を返します。undefined

  7. 最後に、呼び出しはEvaluateDirectCallによって評価され、これは にthisValue設定されたものを使用しundefinedます。

ご利用の際はglobalObj.hasOwnProperty("x")

  1. の識別子の解決が行われglobalObjます。グローバルオブジェクトを取得するとしましょう。

  2. プロパティ アクセサーが評価されます。ランタイム セマンティクスを参照してください

  3. 参照を返します

    { base: globalObj, referencedName: "hasOwnProperty", strict: strictFlag }
    
  4. それからあなたはそれを呼びます。ランタイム セマンティクスを参照してください

  5. GetValueを使用して関数を取得します。これはプロパティ参照であり、ベースはオブジェクトであるため、[[Get]]内部メソッドが使用されます。

  6. 参照はプロパティ参照であるため、ベース (グローバル オブジェクト) を返すGetThisValuethisValueから取得されます。

  7. 最後に、呼び出しはEvaluateDirectCallthisValueによって評価され、グローバル オブジェクトへのセットが使用されます。

ここで、関数が値をどのように扱うかが重要thisです。

デフォルトでは、[[Call]]OrdinaryCallBindThisを使用します。これは、ずさんなモードでnullorundefined thisArgumentをグローバル オブジェクトに変換します。関数が厳密モードで定義されている場合、これは発生しません。

最後に、 の定義は値に対してToObjectObject.prototype.hasOwnPropertyを使用します。またはの場合にスローされます。thisnullundefined

console.log(function(){ return this }() === window);
console.log(function(){ "use strict"; return this }() === undefined);

それで、hasOwnProperty厳格モードで定義されていますか?さて、組み込み関数オブジェクトの場合、

各組み込み関数について、[[Call]] で呼び出されると、[[Call]] thisArgumentthis値を提供し、[[Call]] argumentsListは名前付きパラメーターを提供し、NewTarget 値は 未定義です。

そのため、this値は変換せずにそのまま渡されnullundefinedグローバル オブジェクトに渡されます。厳密な関数のように。

当然のことながら、グローバルオブジェクトをベースとして指定せずに直接使用したい場合hasOwnPropertyは、ずさんなモード関数で再定義するだけです。これはお勧めしません。それはただの楽しみです。

(function() {
  var has = Object.prototype.hasOwnProperty;
  Object.prototype.hasOwnProperty = function() {
    return has.apply(this, arguments);
  };
})();
console.log(hasOwnProperty('hello')); // false
console.log(hasOwnProperty('window')); // true

またはゲッターアプローチ:

Object.defineProperty(window, 'hasOwnProperty', {get: function() {
  return Object.prototype.hasOwnProperty.bind(this);
}});
console.log(hasOwnProperty('hello')); // false
console.log(hasOwnProperty('window')); // true

ただし、ECMASCript 標準では、グローバル オブジェクトが から継承されることは保証されていませんObject.prototype

InitializeHostDefinedRealmから、完全に実装に依存します。

ホストがrealmglobal objectとして機能するエキゾチックなオブジェクトの使用を必要とする場合、 globalを実装定義の方法で作成されたそのようなオブジェクトにします

したがって、一般的には使用しglobalObj.hasOwnPropertyないでhasOwnPropertyください。一部の実装では問題ない場合があります (たとえば、Web ブラウザーの場合、これはW3CおよびWHATWG標準によって強制されます) が、他の実装では完全に失敗する可能性があります。

実装に問題がなくても、まだ悪い. hasOwnProperty陰になる可能性があります。たとえば、Webでは がwindowから継承されていると言いましたObject.prototypeが、グローバルな汚染者はプロトタイプ チェーンの近くにあり、id="hasOwnProperty"!!を含む要素が存在する可能性があります。

代わりに、次のいずれかをお勧めします。

Object.prototype.hasOwnProperty.call(globalObj, prop)
Object.getOwnPropertyDescriptor(globalObj, prop) !== undefined
于 2017-01-06T01:26:50.843 に答える
1

更新 2017-01-16strict mode : Node.js は、明示的に設定するまで機能しません。それでも、Node.js と Firefox には違いがありますnon strict mode(Firefox では、単純な への呼び出しはhasOwnProperty例外なく機能します)。さらに検索して、結果が見つかった場合にこの回答を更新します。


解決策: Node.js の方法はstrict mode

で、実行コンテキストによって定義されていないstrict mode場合はそのままです。thisundefined

(これは、hasOwnProperty を直接呼び出した場合です。)

詳細については、こちら (セクションSimple Call )を参照してください。

于 2017-01-05T22:24:48.727 に答える
1

ここで理解しておく必要がある主なポイントはthis、関数実行内の の値は、関数の呼び出し方法に応じて変化するということです。ここで関連する 2 つの方法は次のとおりです。

  • 関数がオブジェクト (例: foo.bar())のプロパティとして呼び出されるthisと、所有するオブジェクトに設定されます。

  • 関数が「そのままの」関数 (例: bar()) として呼び出される場合、this値は次のいずれかです。

    • 関数に非厳密モード コードがある場合は、グローバル オブジェクト、または
    • undefined、関数に厳密モード コードがある場合

この関数の目的は、オブジェクト (値として指定) に特定の名前 (関数の引数として指定) を持つプロパティがあるhasOwnPropertyかどうかをテストすることです。の値を使用し、値にという名前のプロパティがあるかどうかをテストします。thisfoo.hasOwnProperty("baz")thisfoothisbaz

を呼び出すhasOwnProperty("baz")と、スタンドアロン識別子hasOwnPropertyは からグローバルにアクセス可能な値を参照しますwindow.hasOwnPropertyが、呼び出しは の形式bar(...)ではなく の形式foo.bar(...)です。したがって、this値を指定するための上記の 2 番目のルールが適用されます。

Node.js のhasOwnPropertyメソッドは厳密モードであるように見えるため、その値としてhasOwnProperty("baz")提供されます。プロパティがあるかどうかを尋ねるのは賢明ではないため、この呼び出しではエラーが発生します。undefinedthisundefined

対照的に、Firefox のhasOwnPropertyメソッドは非厳密であるように見えるため、グローバル オブジェクトを として取得しますthis。これにより、 と の呼び出しの結果がwindow.hasOwnproperty(...)同一hasOwnproperty(...)になります。これは、両方とも がthis等しいためwindowです。

于 2017-01-05T22:32:59.753 に答える