209

JavaScriptは私を驚かせ続け、これは別の例です。最初は理解できなかったコードに出くわしました。だから私はそれをデバッグし、この発見に到達しました:

alert('a'['toUpperCase']());  //alerts 'A'

が文字列型のメンバーとして定義されている場合、これは明らかなはずですtoUpperCase()が、最初は意味がありませんでした。

ともかく、

  • toUpperCase'a'のメンバーであるため、これは機能しますか?それとも、舞台裏で何か他のことが起こっていますか?
  • 私が読んでいたコードには、次のような機能があります。

    function callMethod(method) {
        return function (obj) {
            return obj[method](); //**how can I be sure method will always be a member of obj**
        }
    }
    
    var caps2 = map(['a', 'b', 'c'], callMethod('toUpperCase')); // ['A','B','C'] 
    // ignoring details of map() function which essentially calls methods on every 
    // element of the array and forms another array of result and returns it
    

    任意のオブジェクトに対して任意のメソッドを呼び出すのは、ちょっと一般的な関数です。しかし、それは、指定されたメソッドがすでに指定されたオブジェクトの暗黙のメンバーになることを意味しますか?

JavaScript関数の基本的な概念についての真剣な理解が欠けていると確信しています。これを理解するのを手伝ってください。

4

12 に答える 12

294

それを分解する。

  • .toUpperCase()の方法ですString.prototype
  • 'a'はプリミティブ値ですが、オブジェクト表現に変換されます
  • オブジェクトのプロパティ/メソッドにアクセスするための2つの可能な表記法、ドット表記法とブラケット表記法があります

それで

'a'['toUpperCase'];

からのプロパティの角かっこ表記によるアクセスです。このプロパティはメソッドを参照しているため、アタッチすることで呼び出すことができますtoUpperCaseString.prototype()

'a'['toUpperCase']();
于 2013-03-27T13:22:49.807 に答える
78

foo.barfoo['bar']等しいので、投稿したコードはと同じです

alert('a'.toUpperCase())

使用する場合foo[bar](引用符がないことに注意してください)、リテラル名ではbarなく、変数barに含まれる値を使用します。したがって、foo[]代わりに表記foo.を使用すると、動的プロパティ名を使用できます。


見てみましょうcallMethod

まず、obj引数を取る関数を返します。その関数が実行されるとmethod、そのオブジェクトが呼び出されます。したがって、指定されたメソッドは、objそれ自体またはそのプロトタイプチェーンのどこかに存在する必要があります。

toUpperCaseそのメソッドがから来ている場合String.prototype.toUpperCase-存在するすべての単一の文字列に対してメソッドの個別のコピーを持っているのはかなり愚かです。

于 2013-03-27T13:20:16.880 に答える
25

.propertyName表記法または表記法を使用して、任意のオブジェクトのメンバーにアクセスできます["propertyName"]。それがJavaScript言語の特徴です。メンバーがオブジェクト内にあることを確認するには、メンバーが定義されているかどうかを確認します。

function callMethod(method) {
    return function (obj) {
        if (typeof(obj[method]) == 'function') //in that case, check if it is a function
           return obj[method](); //and then invoke it
    }
}
于 2013-03-27T13:21:45.977 に答える
17

基本的に、javascriptはすべてをオブジェクトとして扱います。つまり、すべてのオブジェクトを辞書/連想配列として表示できます。そして、関数/メソッドは、オブジェクトに対してまったく同じ方法で定義されます-この連想配列のエントリとして。

つまり、基本的には、'a'オブジェクト(この場合は文字列型)の'toUpperCase'プロパティを参照/呼び出しています(' () 'に注意してください)。

これが私の頭のてっぺんのコードです:

function myObject(){
    this.msg = "hey there! ;-)";
    this.woop = function(){
        alert(this.msg); //do whatever with member data
    }
}

var obj = new myObject();
alert( obj.msg );
alert( obj['msg'] );
obj['woop']();
于 2013-03-27T13:30:06.640 に答える
10

anyObject['anyPropertyName']問題のないキャラクターがいないanyObject.anyPropertyName場合と同じです。anyPropertyName

MDNの「オブジェクトの操作」を参照してください。

toUpperCaseメソッドはString型に付加されます。プリミティブ値(ここでは)で関数を呼び出すと'a'、オブジェクト(ここでは文字列)に自動的にプロモートされます。

メソッドがプリミティブ文字列で呼び出される場合、またはプロパティルックアップが発生する場合、JavaScriptは文字列プリミティブを自動的にラップし、メソッドを呼び出すか、プロパティルックアップを実行します。

ロギングによって関数が存在することがわかりますString.prototype.toUpperCase

于 2013-03-27T13:21:31.133 に答える
9

したがって、Javascriptでは、objectsですobjects。それは彼らがこの性質のものであるということです{}。オブジェクトのプロパティは、次のいずれかを使用して設定できます:a.greeting = 'hello';またはa['greeting'] = 'hello';。どちらの方法でも機能します。

取得も同じように機能します。a.greeting(引用符なし)は'hello'a['greeting']です'hello'。例外:プロパティが数値の場合、bracketメソッドのみが機能します。ドット法はそうではありません。

実際には関数であるプロパティを'a'持つオブジェクトもそうです。'toUpperCase'関数を取得して、後で次のいずれかの方法で呼び出すことができます:'a'.toUpperCase()または'a'['toUpperCase']()

しかし、マップ関数を作成するためのより良い方法は、

var caps = ['a','b','c'].map( function(char) { return char.toUpperCase(); } )

誰がそのcallMethod関数を必要としているのかということです。

于 2013-03-27T16:03:56.793 に答える
6

すべてのJavaScriptオブジェクトはハッシュテーブルであるため、キーを指定することでそのメンバーにアクセスできます。たとえば、変数が文字列の場合、toUpperCase関数が必要です。だから、あなたはそれを呼び出すことができます

var str = "a"
str['toUpperCase'](). // you get the method by its name as a key and invoke it.

したがって、インラインstrを使用すると、以下のようになります。

"a"["toUpperCase"]()
于 2013-03-27T13:23:19.100 に答える
6

toUpperCaseは標準のjavascriptメソッドです:https ://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase

このように機能する理由'a'['toUpperCase']()は、toUpperCase関数が文字列オブジェクトのプロパティであるため'a'です。object[property]またはを使用して、オブジェクトのプロパティを参照できますobject.property。構文'a''toUpperCase'は、'a'文字列オブジェクトの'toUppercase'プロパティを参照し、それを呼び出していることを示します()。

于 2013-03-27T13:24:55.260 に答える
4

しかし、それは、指定されたメソッドがすでに指定されたオブジェクトの暗黙のメンバーになることを意味しますか?

いいえ。誰かがそのオブジェクトを渡す可能性があります

  1. toUpperCase;という名前のプロパティはありません。また
  2. toUpperCase関数ではないという名前のプロパティがあります

最初のケースでは、存在しないプロパティにアクセスするとが返され、関数としてundefined呼び出すことができないため、エラーがスローundefinedされます。

2番目のケースでは、非関数を関数として呼び出すことができないため、エラーがスローされます。

JavaScriptは非常に緩く型付けされた言語であることを忘れないでください。必要がない限り、タイプチェックはほとんどまたはまったく行われません。渡されたオブジェクトには関数という名前のプロパティがあるため、表示したコードがtoUpperCase機能する場合があります。

引数が正しいタイプのプロパティを持つことが保証されていないという事実はobj、いわばJavaScriptをまったく気にしません。「待機して見る」姿勢を採用し、実行時に実際の問題が発生するまでエラーをスローしません。

于 2013-03-27T21:34:10.557 に答える
4

javascriptのほとんどすべてをオブジェクトとして扱うことができます。あなたの場合、アルファベット自体が文字列オブジェクトとして機能し、toUpperCaseそのメソッドとして呼び出すことができます。角かっこは、オブジェクトプロパティにアクセスするための単なる代替方法であり、メソッドであるため、フォームの次に単純なtoUpperCaseかっこ()が必要です。['toUpperCase']['toUpperCase']()

'a'['toUpperCase']()と同等です'a'.toUpperCase()

'a'['toUpperCase']() // returns A
'a'.toUpperCase() // returns A
于 2013-03-28T10:07:27.377 に答える
3

ここで注意すべき重要な点は、Javascriptは動的言語であるため、すべてのオブジェクトは、基本的に、単なる栄光のハッシュマップであるということです(いくつかの例外を除きます)。また、Javascriptオブジェクトのすべてには、角かっこ表記とドット表記の2つの方法でアクセスできます。

質問の最初の部分に答える2つの表記法について簡単に説明し、次に2番目の部分に進みます。

角かっこ表記

このモードは、他のプログラミング言語でハッシュマップや配列にアクセスするのに似ています。この構文を使用して、任意のコンポーネント(データ(他のオブジェクトを含む)または関数)にアクセスできます。

これはまさにあなたがあなたの例でしていることです。があります'a'。これは文字列です(C ++などの言語のように文字リテラルではありません)。

角かっこ表記を使用して、そのtoUpperCaseメソッドにアクセスします。しかし、それにアクセスするだけではまだ十分ではありません。alertたとえば、Javascriptで入力するだけでは、メソッドは呼び出されません。それは単純なステートメントです。関数を呼び出すには、括弧を追加する必要があります。パラメータを受け取らなかったため、をalert()含む単純なダイアログボックスが表示されます。undefinedこれで、この知識を使用してコードを解読できます。これは次のようになります。

alert('a'.toUpperCase());

これははるかに読みやすいです。

実際、これをもう少しよく理解するための良い方法は、次のJavascriptを実行することです。

alert(alert)

これは、2番目のアラートも実行せずにalert、関数オブジェクトを渡すことによっても呼び出します。alert表示されるのは(少なくともChrome 26では)次のとおりです。

function alert() { [native code] } 

呼び出し:

alert(alert())

を含む2つの連続したメッセージボックスを示していますundefined。これは簡単に説明できます。内部alert()が最初に実行され、表示されundefined(パラメーターがなかったため)、何も返されません。外部アラートは内部アラートの戻り値を受け取ります。これは何もありません。またundefined、メッセージボックスにも表示されます。

jsFiddleですべてのケースを試してみてください!

ドット表記

.これはより標準的なアプローチであり、ドット( )演算子を使用してオブジェクトのメンバーにアクセスできます。これは、ドット表記でのコードの外観です。

alert('a'.toUpperCase())

はるかに読みやすい。では、いつドット表記を使用する必要があり、いつブラケット表記を使用する必要があるのでしょうか。

比較

2つの方法の主な違いは、セマンティックです。他にもいくつかの詳細がありますが、それらについてはすぐに説明します。最も重要なのは、実際にやりたいことです。経験則では、オブジェクトが持つ確立されたフィールドとメソッドにはドット表記を使用し、実際にオブジェクトをハッシュマップとして使用する場合はブラケット表記を使用します。 。

このルールが非常に重要である理由の良い例をあなたの例で示すことができます-コードはドット表記がはるかに賢明だった場所でブラケット表記を使用しているため、コードが読みにくくなります。そして、それは悪いことです。なぜなら、コードは書かれているよりも何度も読み取られるからです

場合によっては、ドット表記を使用する方が賢明であったとしても、角かっこ表記を使用する必要があります。

  • オブジェクトのメンバーに1つ以上のスペースまたはその他の特殊文字を含む名前がある場合、ドット表記を使用することはできません。foo.some method()機能しませんが、foo["some method"]()機能します。

  • オブジェクトのメンバーに動的にアクセスする必要がある場合は、角かっこ表記を使用しても問題が発生します。

例:

for(var i = 0; i < 10; ++i) {
   foo["method" + i](); 
 }

つまり、オブジェクトをハッシュマップとして使用する場合は角かっこ構文を使用し(foods["burger"].eat())、「実際の」フィールドとメソッドを操作する場合はドット構文を使用する必要があります(enemy.kill())。Javascriptは動的言語であるため、オブジェクトの「実際の」フィールドとメソッド、およびその中に格納されている「その他の」データの間の境界線はかなりぼやけることがあります。しかし、紛らわしい方法でそれらを混ぜない限り、あなたは大丈夫なはずです。


さて、あなたの質問の残りの部分に移りましょう(最後に!:P)。

メソッドが常にobjのメンバーになることをどのように確認できますか

できません。それを試してみてください。derp文字列を呼び出してみてください。次の行でエラーが発生します。

Uncaught TypeError: Object a has no method 'derp' 

任意のオブジェクトに対して任意のメソッドを呼び出すのは、ちょっと一般的な関数です。しかし、それは、指定されたメソッドがすでに指定されたオブジェクトの暗黙のメンバーになることを意味しますか?

はい、あなたの場合はそうしなければなりません。そうしないと、上記のエラーが発生します。ただし、関数で使用する必要はありませ。独自の機能を追加して、map関数で使用することができます。すべての文字を大文字に変換するハードコードされたメソッドは次のとおりです。return obj[method]();callMethod()

function makeCap()
{
    return function(obj) {
        return obj.toUpperCase();
    }
}

var caps2 = map(['a', 'b', 'c'], makeCap()); // ['A','B','C'] 
console.log(caps2)

リンクしたチュートリアルのコードは、部分関数を使用しています。それらはそれ自体がトリッキーな概念です。その主題についてもっと読むことは、私がこれまでに作ることができたよりも物事をより明確にするのに役立つはずです。


注:これは、質問のコードで使用されているマップ関数のコードです。ソースはこちらです。

function map(arr, iterator) {
  var narr = [];
  for (var i = 0; i < arr.length; i++) narr.push(iterator(arr[i], i));
  return narr;
}
于 2013-04-05T13:50:42.037 に答える
2

それが実際にどのように機能するかを尋ねるなら、それは私がそれを読む方法です。これは単純な数学関数です。それを理解するには、ASCIIテーブルを見る必要があります。これは、各文字に数値を割り当てます。それを隠蔽するために、競争は単に論理ステートメントを使用して隠蔽します。たとえば、If(ChcrValue> 80 && charValue <106)//これは小文字のセットですthen charValue = charValue --38; //下部セットと上部セットの間の距離

それはとても簡単です、私は実際に正しい値を探すことを気にしませんでした、しかしこれは基本的にすべての小文字を大文字にシフトしています。

于 2013-04-02T20:35:08.697 に答える