JavaScript에서 'a'[ 'toUpperCase'] ()는 어떻게 그리고 왜 작동합니까?


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 함수의 기본 개념에 대한 진지한 이해가 누락되었다고 확신합니다. 이것을 이해하도록 도와주세요.


24
점의 표기법과 대괄호 표기법의 두 가지 방법으로 객체의 속성에 액세스 할 수 있습니다. 약간 관련됨 : stackoverflow.com/a/11922384/218196 . 배열 요소에 액세스 할 때 항상 괄호 표기법을 사용하기 때문에 괄호 표기법에 대해 이미 알고 arr[5]있습니다. 유효한 식별자 이름이 숫자 인 경우 점 표기법을 사용할 수 있습니다 arr.5.
Felix Kling

2
와 동일합니다 5['toString']().
0x499602D2


관련 읽기 : 1) 상속 및 프로토 타입 체인 : developer.mozilla.org/en-US/docs/JavaScript/Guide/… 2) JavaScript 기본 요소의 비밀 생활 : javascriptweblog.wordpress.com/2010/09/27/…
Theraot

21
처음에 나는 제목이 "어떻게 그리고 왜 JavaScript가 작동 하는가"라고 생각했습니다. 아 잘
문제의

답변:


293

그것을 분해합니다.

  • .toUpperCase() ~의 방법이다 String.prototype
  • 'a'기본 값이지만 객체 표현 으로 변환됩니다.
  • 객체 속성 / 메소드에 액세스하기위한 두 가지 표기법, 도트 및 괄호 표기법이 있습니다.

그래서

'a'['toUpperCase'];

에서 속성에 대괄호 표기법 을 통한 액세스 toUpperCase입니다 String.prototype. 이 프로퍼티는 메소드를 참조하므로 , 첨부하여 호출 할 수 있습니다()

'a'['toUpperCase']();

이것은 재미있는 인터뷰 질문이 될 것입니다
FluffyBeing

78

foo.bar그리고 foo['bar']당신이 게시 코드와 동일하므로 동일

alert('a'.toUpperCase())

사용할 때 foo[bar](따옴표없이) 리터럴 이름을 사용하지 않고 bar변수에 bar포함 된 값을 사용하십시오 . 따라서 foo[]대신 표기법 foo.을 사용하면 동적 속성 이름을 사용할 수 있습니다.


살펴 보자 callMethod:

우선, obj인수로 사용 되는 함수를 반환합니다 . 해당 기능이 실행되면 해당 method객체를 호출 합니다. 따라서 주어진 방법은 obj그 자체 또는 프로토 타입 체인에 존재할 필요가 있습니다 .

toUpperCase해당 메소드의 경우 String.prototype.toUpperCase-존재하는 모든 단일 문자열에 대해 별도의 메소드 사본을 갖는 것이 다소 어리 석습니다.


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

17

기본적으로 자바 스크립트는 모든 것을 객체로 취급하거나 모든 객체를 사전 / 연관 배열로 볼 수 있습니다. 그리고 함수 / 메소드는 객체와 똑같은 방식으로이 연관 배열의 항목으로 정의됩니다.

따라서 본질적으로 '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']();

10

anyObject['anyPropertyName']과 동일 anyObject.anyPropertyName할 때 anyPropertyName문제가 문자 않았습니다.

MDN에서 객체 작업을 참조하십시오 .

toUpperCase메소드는 문자열 유형에 첨부됩니다. 프리미티브 값에서 함수를 호출하면 here 'a', 자동으로 객체, 여기에서 String 으로 승격됩니다 .

기본 문자열에서 메소드가 호출되거나 특성 검색이 발생하는 상황에서 JavaScript는 자동으로 문자열 기본을 랩핑하고 메소드를 호출하거나 특성 검색을 수행합니다.

로깅을 통해 해당 기능이 존재하는지 확인할 수 있습니다 String.prototype.toUpperCase.


9

Javascript에서는 objects입니다 objects. 그것은 그들이 본성 {}입니다. 개체 속성 중 하나 이들의 사용하여 설정할 수 있습니다 : a.greeting = 'hello';a['greeting'] = 'hello';. 두 가지 방법 모두 작동합니다.

검색도 동일하게 작동합니다. a.greeting(따옴표없이)이다 'hello', a['greeting']입니다 'hello'. 예외 : 속성이 숫자 인 경우 대괄호 메서드 만 작동합니다. 도트 방법은 그렇지 않습니다.

실제로 함수 인 속성을 'a'가진 객체도 마찬가지 입니다 'toUpperCase'. 함수를 검색하여 나중에 다음과 같이 호출 할 수 있습니다 : 'a'.toUpperCase()또는 'a'['toUpperCase']().

그러나지도 기능을 작성하는 더 좋은 방법은

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

누가 기능이 필요 callMethod합니까?


아름답게 설명 :-)
Elisha Senoo 1

6

모든 JavaScript 객체는 해시 테이블이므로 키를 지정하여 해당 멤버에 액세스 할 수 있습니다. 예를 들어 변수가 문자열이면 toUpperCase 함수가 있어야합니다. 그래서, 당신은 그것을 호출 할 수 있습니다

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

따라서 인라인 str로 아래를 가질 수 있습니다.

"a"["toUpperCase"]()

6

toUpperCase는 표준 자바 스크립트 메소드입니다 : 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'속성을 참조한 다음이를 호출 함을 나타냅니다 ().


4

그러나 이것이 지정된 메소드가 이미 지정된 객체의 암시 적 멤버라는 것을 의미합니까?

아니요. 누군가가

  1. 이름이없는 속성이 없습니다 toUpperCase. 또는
  2. toUpperCase함수가 아닌 속성 이 있습니다

첫 번째 경우 존재하지 않는 속성에 액세스하면을 반환 하고 함수로 undefined호출 할 수 없으므로 오류가 발생 undefined합니다.

두 번째 경우 함수가 아닌 함수를 다시 호출 할 수 없기 때문에 오류가 발생합니다.

JavaScript는 매우 느슨하게 형식화 된 언어입니다. 필요하지 않을 때까지는 유형 검사가 거의 또는 전혀 이루어지지 않습니다. 표시 한 코드는 특정 경우에 작동합니다.이 경우 전달 된 객체에는이라는 속성 toUpperCase이 있는데 이는 함수입니다.

obj인수가 올바른 유형의 속성을 가지고 있다고 보장하지 않는다는 사실은 JavaScript를 전혀 방해하지 않습니다. "대기 및보기"자세를 취하고 런타임에 실제 문제가 발생할 때까지 오류를 발생시키지 않습니다.


4

자바 스크립트의 거의 모든 것을 객체로 취급 할 수 있습니다. 귀하의 경우 알파벳 자체는 문자열 객체 역할 toUpperCase을하며 메소드로 호출 할 수 있습니다. 대괄호 객체 속성 액세스에 불과하고 다른 방법은 이후 toUpperCase따라서 simplebracket이 방법 ()옆 필요 ['toUpperCase']형성 ['toUpperCase']().

'a'['toUpperCase']() 에 해당 'a'.toUpperCase()

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

3

여기서 주목할 점은 Javascript는 동적 언어이므로 모든 객체는 본질적으로 영광스러운 해시 맵입니다 ( 몇 가지 예외는 있음 ). 그리고 자바 스크립트 객체의 모든 것은 브라켓 표기법과 도트 표기법의 두 가지 방식으로 액세스 할 수 있습니다.

질문의 첫 번째 부분에 답하는 두 가지 표기법을 빠르게 살펴보고 두 번째 부분으로 넘어갑니다.

대괄호 표기법

이 모드는 다른 프로그래밍 언어로 해시 맵 및 배열에 액세스하는 것과 유사합니다. 이 구문을 사용하여 모든 구성 요소 (데이터 (다른 개체 포함) 또는 함수)에 액세스 수 있습니다 .

이것은 귀하의 예에서 정확히하는 일입니다. 당신은 'a'문자열입니다 ( C ++과 같은 언어에있는 것처럼 문자 리터럴은 아닙니다 ).

대괄호 표기법을 사용하여 해당 toUpperCase방법에 액세스합니다 . 그러나 액세스하는 것만으로는 충분하지 않습니다. alert예를 들어 Javascript로 간단히 입력 하면 메소드가 호출되지 않습니다. 간단한 진술 일뿐입니다. 함수를 호출하려면 괄호를 추가해야합니다 . 매개 변수가 alert()없으므로을 포함하는 간단한 대화 상자가 표시 undefined됩니다. 이제이 지식을 사용하여 코드를 해독 할 수 있습니다.

alert('a'.toUpperCase());

훨씬 더 읽기 쉽습니다.

실제로 이것을 조금 더 잘 이해하는 좋은 방법은 다음 Javascript를 실행하는 것입니다.

alert(alert)

이것은 또한 두 번째 경고를 실행하지 않고 alert함수 객체를 전달하여 호출 alert합니다. Chrome 26 이상에 표시되는 내용은 다음과 같습니다.

function alert() { [native code] } 

부름:

alert(alert())

를 포함하는 두 개의 연속 메시지 상자를 표시 undefined합니다. 이것은 설명하기 쉽습니다 : 내부 alert()가 먼저 실행되고 undefined(매개 변수가 없기 때문에) 표시되고 아무것도 반환하지 않습니다. 외부 경보는 내부 경보의 리턴 값을 수신합니다. 이는 아무것도 아니며 undefined메시지 상자 에도 표시 됩니다.

jsFiddle의 모든 사례를 사용해보십시오!

점 표기법

이것은 좀 더 표준적인 접근 방식으로 도트 ( .) 연산자를 사용하여 객체 멤버에 액세스 할 수 있습니다 . 다음은 점 표기법으로 코드가 표시되는 모습입니다.

alert('a'.toUpperCase())

훨씬 더 읽기 쉽습니다. 그러면 언제 점 표기법을 사용해야하고 언제 대괄호 표기법을 사용해야합니까?

비교

두 방법의 주요 차이점은 의미 론적입니다. 다른 세부 사항도 있지만 잠시 후에 설명하겠습니다. 가장 중요한 것은 실제로하고 싶은 것입니다. 경험상 규칙은 객체가 잘 확립 된 필드와 메소드에 도트 표기법 을 사용하고 실제로 객체를 해시 맵으로 사용할 때 의 괄호 표기법 을 사용한다는 것입니다 .

이 규칙이 왜 중요한지에 대한 훌륭한 예가 예제에 표시 될 수 있습니다. 코드는 점 표기법이 훨씬 현명한 장소에서 대괄호 표기법을 사용하기 때문에 코드를 읽기 어렵게 만듭니다. 코드가 작성된 것보다 여러 번 읽혀지기 때문에 이는 나쁜 일 입니다 .

점 표기법 을 사용하는 것이 더 합리적인 경우에도 대괄호 표기법 을 사용해야하는 경우 가 있습니다.

  • 개체의 구성원에 하나 이상의 공백이나 다른 특수 문자가 포함 된 이름이 있으면 점 표기법을 사용할 수 없습니다. foo.some method()작동하지 않지만 작동합니다 foo["some method"]().

  • 객체의 멤버에 동적으로 액세스해야하는 경우 대괄호 표기법도 사용됩니다.

예:

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

결론은 객체를 해시 맵 ( foods["burger"].eat()) 으로 사용할 때는 대괄호 구문을 사용하고 "실제"필드 및 메소드 ( enemy.kill())로 작업 할 때는 점 구문 을 사용해야한다는 것 입니다. 자바 스크립트가 동적 인 언어이기 때문에 객체의 "실제"필드와 메소드와 "기타"데이터 사이의 경계선이 매우 흐릿해질 수 있습니다. 그러나 혼란스러운 방식으로 혼합하지 않는 한 괜찮습니다.


이제 나머지 질문에 (최종! : P).

메소드가 항상 obj의 멤버인지 확인하는 방법

당신은 할 수 없습니다. 시도 해봐. derp문자열 을 불러보십시오 . 다음 줄에 오류가 발생합니다.

Uncaught TypeError: Object a has no method 'derp' 

ANY 객체에서 ANY 메소드를 호출하는 일반적인 함수입니다. 그러나 이것이 지정된 메소드가 이미 지정된 객체의 암시 적 멤버라는 것을 의미합니까?

예, 귀하의 경우에는 그렇습니다. 그렇지 않으면 위에서 언급 한 오류가 발생합니다. 그러나, 당신은하지 않습니다 사용하는 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)

링크 된 학습서의 코드는 부분 함수 를 사용 합니다 . 그들은 스스로 까다로운 개념입니다. 그 주제에 대해 더 많이 읽으면 내가 할 수있는 것보다 더 명확하게하는 데 도움이됩니다.


참고 : 이것은 질문의 코드에서 사용하는 map 함수의 코드입니다 . 소스 here .

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

2

그것이 실제로 어떻게 작동하는지 묻는다면 내가 읽는 방법입니다. 이것은 간단한 수학 함수입니다. 그것을 이해하려면 ascii 테이블을 봐야합니다. 각 문자에 숫자 값을 할당합니다. 그것을 은밀히하기 위해 경쟁자는 단순히 논리 문을 사용하여 은밀하게한다. // 하위 집합과 상위 집합 사이의 거리

그것은 간단합니다. 실제로 올바른 값을 찾는 것을 귀찮게하지는 않았지만 기본적으로 모든 소문자를 대문자로 바꿉니다.


이것은 질문과 어떤 관련이 있습니까?
Quasdunk

2
@glh, 그는 어떻게 그리고 왜 'a'['toUpperCase']()작동 하는지 물었다 . 그러나 누군가가 질문을 읽지 않았다면 오해는 이해할 수 있습니다.
LarsH

gr8 답변, 스타일 text-transform: uppercase이 추가 되지 않았기 때문에 JS가 사건을 변경하고 의심을 지우고 한두 가지를 배웠습니다. 고마워
dkjain
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.