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.