Jak i dlaczego działa „a” [„toUpperCase”] () w JavaScript?


209

JavaScript wciąż mnie zaskakuje, a to kolejna instancja. Właśnie natrafiłem na kod, którego na początku nie rozumiałem. Debugowałem go i doszedłem do tego wniosku:

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

To musi być oczywiste, jeśli toUpperCase()jest zdefiniowane jako element typu łańcuchowego, ale na początku nie miało to dla mnie sensu.

Tak czy siak,

  • czy to działa, ponieważ toUpperCasenależy do „a”? Czy dzieje się coś jeszcze za kulisami?
  • kod czytałem posiada funkcję w następujący sposób:

    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
    

    Jest to rodzajowa funkcja wywoływania DOWOLNYCH metod na DOWOLNYM obiekcie. Ale czy to oznacza, że ​​określona metoda będzie już niejawnym członkiem określonego obiektu?

Jestem pewien, że brakuje mi poważnego zrozumienia podstawowej koncepcji funkcji JavaScript. Pomóż mi to zrozumieć.


24
Istnieją dwa sposoby uzyskania dostępu do właściwości obiektu: notacja kropkowa i notacja nawiasowa. Nieznacznie powiązane: stackoverflow.com/a/11922384/218196 . Wiesz już o około notacji wspornika ponieważ zawsze używać go podczas uzyskiwania dostępu do elementów tablicy: arr[5]. Jeśli numery gdzie Nazwy identyfikatorów można użyć określenia: kropka arr.5.
Felix Kling

2
To jest tak samo jak 5['toString']().
0x499602D2


Literatura pokrewna: 1) Dziedziczenie i łańcuch prototypów: developer.mozilla.org/en-US/docs/JavaScript/Guide/… 2) Sekretne życie JavaScript Prymitywy: javascriptweblog.wordpress.com/2010/09/27/...
Theraot

21
Na początku przeczytałem, że tytuł brzmi „jak i dlaczego JavaScript działa?” Ach tak.
Problematyczne

Odpowiedzi:


293

Aby to rozbić.

  • .toUpperCase() jest metodą String.prototype
  • 'a'jest pierwotną wartością, ale zostaje przekonwertowana na jej reprezentację obiektu
  • Mamy dwie możliwe notacje, aby uzyskać dostęp do właściwości / metod obiektu, notację kropkową i nawiasową

Więc

'a'['toUpperCase'];

jest dostęp za pośrednictwem notacji nawiasowej na nieruchomości toUpperCase, z String.prototype. Ponieważ ta właściwość odwołuje się do metody , możemy ją wywołać, dołączając()

'a'['toUpperCase']();

To byłoby zabawne pytanie do wywiadu
FluffyBeing

78

foo.bari foo['bar']są równe, więc opublikowany kod jest taki sam jak

alert('a'.toUpperCase())

Podczas używania foo[bar](zwróć uwagę na brak cudzysłowów) nie używasz literalnej nazwy, barale jakąkolwiek wartość barzawiera zmienna . Zatem użycie foo[]notacji zamiast foo.pozwala na użycie nazwy właściwości dynamicznej.


Rzućmy okiem na callMethod:

Przede wszystkim zwraca funkcję, która przyjmuje objjako argument. Po wykonaniu tej funkcji wywoła methodten obiekt. Zatem dana metoda musi istnieć albo na objsobie, albo gdzieś w swoim łańcuchu prototypów.

W przypadku, gdy toUpperCaseta metoda pochodzi String.prototype.toUpperCase- byłoby głupotą mieć osobną kopię metody dla każdego istniejącego łańcucha.


25

Możesz uzyskać dostęp do elementów dowolnego obiektu za pomocą .propertyNamenotacji lub ["propertyName"]notacji. Taka jest funkcja języka JavaScript. Aby upewnić się, że element członkowski znajduje się w obiekcie, po prostu sprawdź, czy jest zdefiniowany:

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
    }
}

17

Zasadniczo javascript traktuje wszystko jak Obiekt, a raczej każdy obiekt może być postrzegany jako słownik / tablica asocjacyjna. Funkcje / metody są definiowane dokładnie tak samo dla obiektu - jako pozycja w tej tablicy asocjacyjnej.

Zasadniczo odwołujesz się / wywołujesz (zwróć uwagę na właściwość „ () ”) obiektu „toUpperCase” obiektu „a” (w tym przypadku jest to ciąg znaków).

Oto kod na czubku głowy:

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']();

10

anyObject['anyPropertyName']jest taki sam jak anyObject.anyPropertyNamewtedy, gdy anyPropertyNamenie ma problematycznych postaci.

Zobacz Praca z obiektami z MDN.

toUpperCaseMetoda jest dołączony do typu String. Kiedy wywołujesz funkcję na pierwotnej wartości, tutaj 'a'jest ona automatycznie promowana do obiektu, tutaj Ciąg :

W kontekstach, w których metoda ma być wywoływana na prymitywnym łańcuchu lub występuje wyszukiwanie właściwości, JavaScript automatycznie zawinie prymityw łańcucha i wywoła metodę lub wykona wyszukiwanie właściwości.

Możesz zobaczyć, że funkcja istnieje po zalogowaniu String.prototype.toUpperCase.


9

Więc w Javascript objectsobjects. To znaczy, że są tego rodzaju {}. Właściwości obiektu można ustawić za pomocą jednego z poniższych: a.greeting = 'hello';lub a['greeting'] = 'hello';. Oba sposoby działają.

Pobieranie działa tak samo. a.greeting(bez cudzysłowu) jest 'hello', a['greeting']jest 'hello'. Wyjątek: jeśli właściwość jest liczbą, działa tylko metoda nawiasu. Metoda punktowa nie.

Podobnie 'a'jest z 'toUpperCase'obiektem, który w rzeczywistości jest funkcją. Możesz pobrać funkcję i wywołać ją później w dowolny sposób: 'a'.toUpperCase()lub 'a'['toUpperCase']().

Ale imo lepszy sposób na napisanie funkcji mapy byłby taki,

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

kto potrzebuje tej callMethodfunkcji?


Pięknie wyjaśnione :-)
Elisha Senoo

6

Każdy obiekt JavaScript jest tabelą skrótów, dzięki czemu można uzyskać dostęp do jego członków, określając klucz. na przykład, jeśli zmienna jest łańcuchem, powinna mieć funkcję toUpperCase. Więc możesz to wywołać

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

więc, w wierszu in, możesz mieć poniżej

"a"["toUpperCase"]()

6

toUpperCase to standardowa metoda javascript: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase

Powodem tego 'a'['toUpperCase']()jest to, że funkcja toUpperCase jest właściwością obiektu typu string 'a'. Możesz odwoływać się do właściwości obiektu za pomocą object[property]lub object.property. Składnia „a” „ToUpperCase” wskazuje, że odwołujesz się do właściwości „ToUppercase” obiektu „a”, a następnie wywołujesz ją ().


4

Ale czy to oznacza, że ​​określona metoda będzie już niejawnym członkiem określonego obiektu?

Nie. Ktoś może przekazać przedmiot, który

  1. nie ma właściwości o nazwie toUpperCase; lub
  2. ma właściwość o nazwie, toUpperCasektóra nie jest funkcją

W pierwszym przypadku zostanie zgłoszony błąd, ponieważ dostęp do właściwości, która nie istnieje, zwraca undefinedi nie możemy wywoływać undefinedfunkcji.

W drugim przypadku zostanie zgłoszony błąd, ponieważ ponownie nie możemy wywoływać funkcji innej niż funkcja.

Pamiętaj, że JavaScript jest językiem bardzo luźno pisanym. Sprawdzanie typu jest niewielkie lub nie występuje, chyba że będzie to konieczne. Pokazany kod działa w niektórych przypadkach, ponieważ w takich przypadkach przekazany obiekt ma właściwość o nazwie toUpperCase, która jest funkcją.

Fakt, że objargument nie ma odpowiednich właściwości, wcale nie przeszkadza JavaScript, że tak powiem. Przyjmuje podejście „poczekaj i zobacz” i nie zgłasza błędu, dopóki nie pojawi się rzeczywisty problem w czasie wykonywania.


4

Prawie wszystko w javascript można traktować jako obiekt. W twoim przypadku sam alfabet działa jako obiekt łańcuchowy i toUpperCasemożna go wywoływać jako metodę. Nawiasy kwadratowe to tylko alternatywny sposób uzyskiwania dostępu do właściwości obiektu, a ponieważ toUpperCasejest to metoda, dlatego ()obok ['toUpperCase']formowania potrzebny jest prosty nawias kwadratowy ['toUpperCase']().

'a'['toUpperCase']() jest równa 'a'.toUpperCase()

'a'['toUpperCase']() // returns A
'a'.toUpperCase() // returns A

3

Należy tutaj zauważyć, że skoro Javascript jest językiem dynamicznym , każdy obiekt jest w zasadzie tylko uwielbioną mapą skrótu ( z kilkoma wyjątkami ). Do wszystkiego w obiekcie JavaScript można uzyskać dostęp na dwa sposoby - notację w nawiasach i notację kropkową.

Szybko przejrzę dwa zapisy odpowiadające na pierwszą część twojego pytania, a następnie przejdę do drugiej części.

Notacja w nawiasie

Ten tryb jest bardziej podobny do uzyskiwania skrótów i tablic w innych językach programowania. Możesz uzyskać dostęp do dowolnego komponentu (danych (w tym innych obiektów) lub funkcji) przy użyciu tej składni.

Właśnie to robisz w swoim przykładzie. Masz 'a', który jest ciągiem (a nie dosłownym znakiem, tak jak w języku takim jak C ++).

Za pomocą notacji nawiasowej uzyskuje się dostęp do jej toUpperCasemetody. Ale dostęp do niego wciąż nie wystarczy; po prostu wpisanie alert, na przykład w JavaScript, nie wywołuje tej metody. To tylko proste stwierdzenie. Aby wywołać funkcję, musisz dodać nawias: alert()pokazuje proste okno dialogowe zawierające undefined, ponieważ nie otrzymał żadnych parametrów. Możemy teraz wykorzystać tę wiedzę do odszyfrowania twojego kodu, który staje się:

alert('a'.toUpperCase());

Co jest znacznie bardziej czytelne.

Właściwie dobrym sposobem na zrozumienie tego nieco lepiej jest uruchomienie następującego Javascript:

alert(alert)

Wymaga to alertprzekazując mu obiekt funkcji, również alertbez również wykonanie drugiego wpisu. Pokazane (przynajmniej w Chrome 26) są następujące:

function alert() { [native code] } 

Powołanie:

alert(alert())

pokazuje dwa kolejne pola wiadomości zawierające undefined. Łatwo to wytłumaczyć: alert()najpierw wykonywane jest wnętrze , pokazuje undefined(ponieważ nie ma żadnych parametrów) i nic nie zwraca. Alarm zewnętrzny otrzymuje wartość zwracaną przez alert wewnętrzny - który jest niczym, a także pojawia się undefinedw oknie komunikatu.

Wypróbuj wszystkie skrzynki na jsFiddle!

Notacja kropkowa

Jest to bardziej standardowe podejście, które umożliwia dostęp do elementów obiektu za pomocą .operatora kropki ( ). Oto jak wyglądałby Twój kod w notacji kropkowej:

alert('a'.toUpperCase())

O wiele bardziej czytelny. Kiedy więc powinniśmy używać notacji kropkowej, a kiedy notacji nawiasowej?

Porównanie

Główna różnica między tymi dwiema metodami jest semantyczna. Są też inne szczegóły, ale zajmę się nimi za chwilę. Najważniejsze jest to, co naprawdę chcesz zrobić - ogólna zasada polega na tym, że używasz notacji kropkowej dla dobrze ustalonych pól i metod, jakie posiada obiekt, oraz notacji nawiasowej, gdy faktycznie używasz swojego obiektu jako mapy hash .

Świetny przykład, dlaczego ta reguła jest tak ważna, można pokazać na przykładzie - ponieważ kod używa notacji nawiasowej w miejscu, w którym notacja kropkowa byłaby znacznie bardziej sensowna, utrudnia to odczytanie kodu. A to zła rzecz, ponieważ kod jest odczytywany wiele razy więcej niż jest napisany .

W niektórych przypadkach musisz użyć notacji nawiasowej, nawet jeśli bardziej sensowne jest użycie notacji kropkowej :

  • jeśli członek obiektu ma nazwę zawierającą co najmniej jedną spację lub dowolne inne znaki specjalne, nie można użyć notacji kropkowej: foo.some method()nie działa, ale foo["some method"]()działa;

  • jeśli potrzebujesz dynamicznie uzyskać dostęp do elementów obiektu, utkniesz także przy użyciu notacji nawiasowej;

Przykład:

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

Najważniejsze jest to, że powinieneś używać składni nawiasów, gdy używasz obiektu jako mapy skrótów ( foods["burger"].eat()), a składni kropek, gdy pracujesz z „rzeczywistymi” polami i metodami ( enemy.kill()). Ponieważ Javascript jest językiem dynamicznym, granica między „rzeczywistymi” polami i metodami obiektu a „innymi” przechowywanymi danymi może być dość rozmyta. Ale dopóki nie pomieszacie ich w mylący sposób, wszystko powinno być w porządku.


Teraz na resztę pytania (wreszcie!: P).

jak mogę być pewien, że metoda zawsze będzie członkiem obj

Nie możesz Spróbuj. Spróbuj wywołać derpciąg. Pojawi się błąd w wierszach:

Uncaught TypeError: Object a has no method 'derp' 

Jest to rodzajowa funkcja wywoływania DOWOLNYCH metod na DOWOLNYM obiekcie. Ale czy to oznacza, że ​​określona metoda będzie już niejawnym członkiem określonego obiektu?

Tak, w twoim przypadku musiałoby tak być. W przeciwnym razie kończy się błąd, o którym wspomniałem powyżej. Jednak nie mają do wykorzystania return obj[method]();w callMethod()funkcji. Możesz dodać własną funkcjonalność, która następnie zostanie użyta przez funkcję mapy. Oto zakodowana metoda, która zamienia wszystkie litery na wielkie:

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

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

Kod w samouczku, który łączysz, używa funkcji częściowych . Same w sobie są trudną koncepcją. Czytanie więcej na ten temat powinno pomóc w wyjaśnieniu, niż mógłbym to uczynić.


Uwaga: jest to kod funkcji mapy używanej przez kod w pytaniu, źródło tutaj .

function map(arr, iterator) {
  var narr = [];
  for (var i = 0; i < arr.length; i++) narr.push(iterator(arr[i], i));
  return narr;
}

2

Jeśli pytasz, jak to naprawdę działa, tak to czytam. Ok, to jest prosta funkcja matematyczna. Aby to zrozumieć, musisz spojrzeć na tabelę ascii. Co przypisuje wartość liczbową każdej literze. Aby to ukryć, konkurencja używa po prostu instrukcji logicznej do ukrywania, więc na przykład Jeśli (ChcrValue> 80 && charValue <106) // Jest to zestaw małych liter, a następnie charValue = charValue - 38; // odległość między dolnym zestawem a górnym zestawem

to takie proste, tak naprawdę nie zadałem sobie trudu, aby wyszukać prawidłowe wartości, ale w zasadzie przenosiłem wszystkie małe litery na wielkie.


Jak to się ma do pytania?
Quasdunk

2
@glh, zapytał, jak i dlaczego 'a'['toUpperCase']()działa. Ale nieporozumienie jest zrozumiałe, jeśli ktoś nie przeczytał pytania.
LarsH

odpowiedź gr8, ponieważ nie text-transform: uppercasedodano żadnych stylów , byłem na samym końcu, jak JS zdołał zmienić sprawę, wyjaśnił wątpliwości i nauczył się jednej lub dwóch rzeczy. wielkie dzięki.
dkjain
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.