[javascript] “this”키워드는 어떻게 작동합니까?

나는 무엇에 대한 명확한 설명이없는 것으로 나타났습니다 this키워드가 키워드가 스택 오버플로 사이트의 JavaScript에서 올바르게 (잘못) 사용되는 방법에 .

나는 그것에 대해 매우 이상한 행동을 목격했으며 왜 그런 일이 일어 났는지 이해하지 못했습니다.

어떻게 this작동하고 언제 사용해야합니까?



답변

Mike West 의 기사 Scope in JavaScript ( mirror )를 먼저 읽는 것이 좋습니다 . 그것은 개념에 대한 훌륭하고 친근한 소개입니다.thisJavaScript 과 범위 체인에 입니다.

에 익숙해지기 시작 this하면 규칙은 실제로 매우 간단합니다. 인 ECMAScript 5.1 표준 을 정의 this:

§11.1.1this 키워드

this현재 실행 컨텍스트의 ThisBinding의 값 키워드 평가됩니다

ThisBinding은 객체에 대한 참조를 보유하는 특수 CPU 레지스터와 같이 JavaScript 코드를 평가할 때 JavaScript 인터프리터가 유지 관리하는 것입니다. 인터프리터는 세 가지 경우 중 하나에서 실행 컨텍스트를 설정할 때마다 ThisBinding을 업데이트합니다.

1. 초기 전역 실행 컨텍스트

최상위 레벨에서 평가되는 JavaScript 코드의 경우입니다 (예 <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

초기 전역 실행 컨텍스트에서 코드를 평가할 때 ThisBinding은 전역 개체 window( §10.4.1.1 )로 설정됩니다.

평가 코드 입력

  • eval()
    ThisBinding 에 대한 직접 호출 은 변경되지 않습니다. 호출 실행 컨텍스트의 ThisBinding과 동일한 값입니다 ( §10.4.2 (2) (a)).

  • eval()
    ThisBinding을 직접 호출하지 않으면 초기 전역 실행 컨텍스트 ( §10.4.2 (1)) 에서 실행하는 것처럼 이 바인딩이 전역 개체 설정됩니다 .

§15.1.2.1.1은 직접 호출이 무엇인지 정의합니다 eval(). 기본적으로 eval(...)직접 전화를하는 반면에 (0, eval)(...)또는 var indirectEval = eval; indirectEval(...);에 대한 간접 전화를하는 것 eval()입니다. JavaScript에서 (1, eval) ( ‘this’) vs eval ( ‘this’)에 대한 chuckj의 답변 을 참조하십시오 . Dmitry Soshnikov의 ECMA-262-5에 대해 자세히 설명합니다. 2 장. 엄격한 모드. 간접 eval()통화를 사용할 수 있습니다 .

기능 코드 입력

이것은 함수를 호출 할 때 발생합니다. in obj.myMethod()또는 equivalent 과 같은 객체에서 함수가 호출되면 obj["myMethod"]()ThisBinding이 객체로 설정됩니다 ( obj예 : §13.2.1 ). 대부분의 경우이 바인딩은 전역 객체 ( §10.4.3 )로 설정됩니다 .

“대부분의 다른 경우”를 작성하는 이유는 인수 목록에 ThisBinding을 지정할 수있는 ECMAScript 5 내장 함수가 8 개 있기 때문입니다. 이러한 특수 함수는 소위 thisArg호출되어 함수를 호출 할 때 ThisBinding이됩니다 ( §10.4.3 ).

이러한 특수 내장 기능은 다음과 같습니다.

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Function.prototype함수 의 경우 함수 객체에서 호출되지만 ThisBinding을 함수 객체로 설정하지 않고 ThisBinding이thisArg .

의 경우에 Array.prototype기능이 지정된 callbackfnThisBinding로 설정 실행 컨텍스트에서 호출 thisArg공급하는 경우; 그렇지 않으면 전역 객체에.

이것들은 일반 JavaScript의 규칙입니다. JavaScript 라이브러리 (예 : jQuery)를 사용하기 시작하면 특정 라이브러리 함수가의 값을 조작 할 수 있습니다 this. JavaScript 라이브러리의 개발자는 가장 일반적인 사용 사례를 지원하는 경향이 있기 때문에이 작업을 수행하며 일반적으로 라이브러리 사용자는이 동작이 더 편리하다는 것을 알게됩니다. this라이브러리 함수를 참조하는 콜백 함수를 전달할 this때 함수가 호출 될 때의 값에 대한 보증은 설명서를 참조해야합니다 .

JavaScript 라이브러리가의 값을 조작하는 방법에 대해 궁금한 경우 this라이브러리는 단순히을 허용하는 내장 JavaScript 함수 중 하나를 사용합니다 thisArg. 콜백 함수를 사용하여 자신의 함수를 작성할 수도 있습니다 thisArg.

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

내가 아직 언급하지 않은 특별한 경우가 있습니다. new연산자 를 통해 새 객체를 구성 할 때 JavaScript 인터프리터는 비어 있는 새 객체를 만들고 내부 속성을 설정 한 다음 새 객체에서 생성자 함수를 호출합니다. 따라서 생성자 컨텍스트에서 함수가 호출되면 그 값은 this인터프리터가 만든 새 객체입니다.

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

화살표 기능

ECMA6에 도입 된 화살표 기능 은의 범위를 변경합니다 this. 기존의 표준 질문 인 화살표 함수 대 함수 선언 / 표현을 참조하십시오 . 자세한 내용은. 그러나 간단히 말하면 :

화살표 함수에는 자체 this…. 바인딩 이 없습니다 . 대신, 이러한 식별자는 다른 변수와 같이 어휘 범위에서 분석됩니다. 즉, 화살표 함수 내부 에서 화살표 함수가 정의 된 환경의 this값을 참조 this합니다.

재미를 위해 몇 가지 예를 통해 이해를 테스트하십시오.

답을 나타내려면 밝은 회색 상자 위로 마우스를 이동하십시오.

  1. 의 가치는 무엇입니까 this표시된 줄 얼마입니까? 왜?

    window — 표시된 행은 초기 전역 실행 컨텍스트에서 평가됩니다.

    if (true) {
        // What is `this` here?
    }
  2. this때 표시 줄에 값은 무엇입니까obj.staticFunction()실행될 얼마입니까? 왜?

    obj — 객체에서 함수를 호출 할 때 ThisBinding이 객체로 설정됩니다.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      

  3. this표시된 줄 의 값은 얼마입니까? 왜?

    window

    이 예제에서 JavaScript 인터프리터는 함수 코드를 입력하지만 myFunobj.myMethod 오브젝트에서 / 가 호출되지 ThisBinding이로 설정됩니다 window.

    이것은 메소드 ( obj.myMethod)에 액세스 하여 바인딩 된 메소드 객체를 만드는 Python과 다릅니다 .

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      

  4. this표시된 줄 의 값은 얼마입니까? 왜?

    window

    이건 까다로웠다. 평가 코드를 평가할 때는 this입니다 obj. 그러나 평가 코드에서는 myFun개체에서 호출되지 않으므로 ThisBinding이 window호출로 설정됩니다 .

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
  5. this표시된 줄 의 값은 얼마입니까? 왜?

    obj

    이 라인 myFun.call(obj);은 특수 내장 함수를 호출 하며, 첫 번째 인수로 Function.prototype.call()허용 thisArg됩니다.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      


답변

this다른 자바 스크립트의 키워드 동작합니다 다른 언어에 비해. 객체 지향 언어에서 this키워드는 클래스의 현재 인스턴스를 나타냅니다. JavaScript에서의 값 this은 함수의 호출 컨텍스트에 의해 결정됩니다 (context.function() ) .

1. 글로벌 맥락에서 사용될 때

this글로벌 컨텍스트에서 사용하면 글로벌 오브젝트에 바인딩됩니다 ( window브라우저에서)

document.write(this);  //[object Window]

this전역 컨텍스트에 정의 된 함수 내부에서 사용 하는 this경우 함수가 실제로 전역 컨텍스트의 메서드로 만들어지기 때문에 여전히 전역 개체에 바인딩됩니다.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

f1는 전역 객체의 방법입니다. 따라서 window다음과 같이 객체에서 호출 할 수도 있습니다.

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. 객체 메소드 내부에서 사용될 때

this객체 메소드 내에서 키워드 를 사용 this하면 “바로”둘러싸는 객체에 바인딩됩니다.

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

위의 단어를 즉시 큰 따옴표로 묶었습니다. 객체를 다른 객체 안에 중첩 this하면 바로 부모에 바인딩됩니다.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

메소드를 객체에 명시 적으로 함수를 추가하더라도 여전히 위의 규칙을 따르며 this이는 바로 상위 부모 객체를 가리 킵니다.

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. 문맥없는 기능을 호출 할 때

this컨텍스트없이 호출 된 내부 함수 를 사용하는 경우 (예 : 오브젝트가 아닌) 글로벌 window함수 (브라우저에서) (함수가 오브젝트 내부에 정의 된 경우에도)에 바인딩됩니다 .

var context = "global";

var obj = {
    context: "object",
    method: function () {
        function f() {
            var context = "function";
            return this + ":" +this.context;
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

기능으로 모든 것을 시도

함수로 위의 포인트를 시험해 볼 수도 있습니다. 그러나 약간의 차이가 있습니다.

  • 위에서 객체 리터럴 표기법을 사용하여 객체에 멤버를 추가했습니다. 를 사용하여 함수에 멤버를 추가 할 수 있습니다 this. 그들을 지정합니다.
  • 객체 리터럴 표기법은 즉시 사용할 수있는 객체 인스턴스를 만듭니다. 함수를 사용하면 먼저 new연산자 를 사용하여 인스턴스를 만들어야합니다 .
  • 또한 객체 리터럴 방식에서는 점 연산자를 사용하여 이미 정의 된 객체에 멤버를 명시 적으로 추가 할 수 있습니다. 이것은 특정 인스턴스에만 추가됩니다. 그러나 함수 프로토 타입에 변수를 추가하여 함수의 모든 인스턴스에 반영되도록했습니다.

아래에서는 Object this이상에서 수행 한 모든 작업을 시도 했지만 먼저 직접 객체를 작성하는 대신 함수를 작성했습니다.

/*********************************************************************
  1. When you add variable to the function using this keyword, it
     gets added to the function prototype, thus allowing all function
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){
        return this+":"+this.name;
    }
}

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/*********************************************************************
   2. Members explicitly added to the function protorype also behave
      as above: all function instances have their own copy of the
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/*********************************************************************
   3. Illustrating that the function variables added by both above
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/*********************************************************************
   4. `this` keyword refers to the immediate parent object. If you
       nest the object through function prototype, then `this` inside
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/*********************************************************************
   5. If the method is on an object's prototype chain, `this` refers
      to the object the method was called on, as if the method was on
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. 생성자 함수 안에서 사용될 때 .

함수가 생성자로 사용되면 (즉 new, 키워드 와 함께 호출 될 때 ) this함수 본문 내부는 생성중인 새 객체를 가리 킵니다.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. 프로토 타입 체인에 정의 된 함수 내부에서 사용될 때

메소드가 오브젝트의 프로토 타입 체인에있는 경우 해당 메소드 this내부에서 메소드가 오브젝트에 정의 된 것처럼 메소드가 호출 된 오브젝트를 참조합니다.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. 내부 call (), apply () 및 bind () 함수

  • 이 모든 방법은에 정의되어 Function.prototype있습니다.
  • 이 메소드는 함수를 한 번 작성하고 다른 컨텍스트에서 호출 할 수있게합니다. 즉, this함수가 실행되는 동안 사용될 값을 지정할 수 있습니다 . 또한 호출 될 때 원래 함수로 전달되는 매개 변수를 사용합니다.
  • fun.apply(obj1 [, argsArray])inside obj1의 값으로 설정 하고 인수로 전달되는 요소를 호출합니다 .thisfun()fun()argsArray
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])– 내부 obj1값으로 설정 하고 인수로 전달하는 호출 .thisfun()fun()arg1, arg2, arg3, ...
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])– 기능에 대한 참조를 반환 funthis내부에 결합 재미 obj1와의 매개 변수에 fun지정된 매개 변수에 바인딩을 arg1, arg2, arg3,....
  • 지금까지 사이의 차이 apply, call그리고 bind명확하게해야합니다. apply배열과 같은 객체, 즉 숫자 length속성과 해당하는 음이 아닌 정수 속성을 가진 객체로 작동하는 인수를 지정할 수 있습니다. 반면 call함수에 인수를 직접 지정할 수 있습니다. 모두 applycall즉시 지정된 컨텍스트에서 지정된 인수와 함께 함수를 호출합니다. 반면 bind에, 지정된 this값과 인수에 바인딩 된 함수를 반환합니다 . 이 반환 된 함수에 대한 참조를 변수에 지정하여 나중에 참조 할 수 있습니다.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. this내부 이벤트 핸들러

  • 함수를 요소의 이벤트 핸들러에 직접 지정하는 경우 this이벤트 처리 함수 내부 에서 직접 사용 하는 것은 해당 요소를 나타냅니다. 이러한 직접 기능 할당은 addeventListener방법을 사용 하거나와 같은 전통적인 이벤트 등록 방법을 통해 수행 할 수 있습니다 onclick.
  • 마찬가지로 요소 this의 이벤트 속성 (예 🙂 내에서 직접 사용 하는 경우 <button onclick="...this..." >요소를 나타냅니다.
  • 그러나 this이벤트 처리 함수 또는 이벤트 속성 내에서 호출 된 다른 함수를 통해 간접적으로 사용 하면 전역 객체로 해석됩니다 window.
  • Microsoft의 이벤트 등록 모델 방법을 사용하여 함수를 이벤트 핸들러에 첨부하면 위와 동일한 동작이 수행됩니다 attachEvent. 함수를 이벤트 핸들러에 할당하는 대신 (요소의 함수 메소드를 작성하는) 대신 이벤트에서 함수를 호출합니다 (글로벌 컨텍스트에서 효과적으로 호출).

JSFiddle 에서 더 잘 시도하는 것이 좋습니다 .

<script>
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    }
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

8. thisES6 화살표 기능

화살표 함수에서 this공통 변수처럼 동작합니다. 어휘 범위에서 상속됩니다. 함수의 this화살표 함수가 정의되고, 상기 화살표의 기능을 할 것이다 this.

따라서 다음과 같은 동작입니다.

(function(){}).bind(this)

다음 코드를 참조하십시오.

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 


답변

자바 스크립트 this

간단한 함수 호출

다음 기능을 고려하십시오.

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

우리는 이것을 일반 모드에서 실행하고 있습니다. 즉, 엄격 모드는 사용되지 않습니다.

브라우저에서 실행할 때의 값 this은로 기록됩니다 window. 이 때문입니다window 웹 브라우저 범위의 전역 변수 입니다.

node.js와 같은 환경에서 동일한 코드를 실행하면 this 앱의 전역 변수를 참조합니다.

이제 "use strict";함수 선언의 시작 부분에 명령문 을 추가하여 엄격 모드에서 이것을 실행하면 this더 이상 환경 중 하나에서 전역 변수를 참조하지 않습니다. 엄격 모드에서 혼동을 피하기 위해 수행됩니다. this이 경우에는 그냥 로그undefined 입니다. 그것이 정의 된 것이 아니기 때문입니다.

다음과 같은 경우에 우리는 this 있습니다.

객체에서 함수 호출

이를 수행하는 다른 방법이 있습니다. forEachand와 같은 Javascript에서 원시 메소드를 호출 한 경우, 해당 경우 변수가 해당 함수를 호출 한 것을 참조한다는 slice것을 이미 알고 있어야 합니다 (javascript에서는 거의 모든 것이 s 및 s를 포함하여 ). 예를 들어 다음 코드를 사용하십시오.thisObjectObjectArrayFunction

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

Object에 속성이 포함 된 속성이 포함되어 있으면 속성을 Function메소드라고합니다. 이 메소드는 호출 될 때 항상 연관된 this변수로 설정됩니다 Object. 이는 엄격 및 비 엄격 모드 모두에 해당됩니다.

메소드가 다른 변수에 저장되거나 복사되는 경우 참조 this는 더 이상 새 변수에 유지되지 않습니다. 예를 들면 다음과 같습니다.

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation

보다 일반적으로 실용적인 시나리오를 고려하십시오.

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

new키워드

Javascript에서 생성자 함수를 고려하십시오.

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

어떻게 작동합니까? new키워드를 사용할 때 어떤 일이 발생하는지 봅시다 .

  1. new키워드로 함수를 호출하면 Object의 유형 이 즉시 초기화 Person됩니다.
  2. 이 생성자는 Object생성자를로 설정했습니다 Person. 또한 typeof awal반환 Object만합니다.
  3. 이 새로운 것에 Object는의 프로토 타입이 할당됩니다 Person.prototype. Person이는를 Person포함하여의 모든 인스턴스 에서 프로토 타입의 모든 메소드 또는 속성을 사용할 수 있음을 의미합니다 awal.
  4. 함수 Person자체가 이제 호출됩니다. this새롭게 구성된 객체에 대한 참조 awal입니다.

아주 간단합니까?

공식 ECMAScript 사양에는 이러한 유형의 기능이 실제 constructor기능 이라고 명시되어 있지 않습니다. 그것들은 단지 정상적인 기능이며 new모든 기능에서 사용될 수 있습니다. 단지 우리가 그것들을 그대로 사용하는 것 뿐이므로, 그것들을 그렇게 만 부릅니다.

함수에서 함수 호출 : callapply

그래서 그래, 이후 function의도 있습니다Objects (그리고 실제로 Javascript의 첫 번째 클래스 변수이기 때문에) 함수조차도 함수 자체가 있습니다.

모든 기능은 세계에서 상속 Function, 그 많은 방법이 있습니다 callapply, 둘 다의 값을 조작하는 데 사용할 수있는 this가 호출되는 함수를.

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

사용하는 일반적인 예입니다 call. 기본적으로 첫 번째 매개 변수 this를 사용하고 함수 foo에 대한 참조로 설정 thisArg합니다. 전달 된 다른 모든 매개 변수는 인수로 call함수에 전달됩니다 foo.
따라서 위의 코드는 {myObj: "is cool"}, [1, 2, 3]콘솔에 로그인 합니다. 가치를 바꾸는 아주 좋은 방법this모든 함수에서 입니다.

applycall두 개의 매개 변수 만 사용한다는 점 과 거의 동일 thisArg합니다. 함수에 전달할 인수가 포함 된 배열입니다. 따라서 위의 call호출은 다음 apply과 같이 번역 될 수 있습니다 .

foo.apply(thisArg, [1,2,3])

그 주 callapply의 값을 대체 할 수 있습니다this 우리 번째 탄환에서 설명한 도트 메소드 호출에 의해 설정한다. 충분히 간단하다 🙂

발표 …. bind !

bind의 형제 callapply. 또한 FunctionJavascript 의 전역 생성자에서 모든 함수에 의해 상속되는 메소드 입니다. 차이 bindcall/ apply그 모두 인 callapply것 실제로 기능을 호출한다. bind반면에는 thisArgarguments사전 설정을 사용하여 새 함수를 반환합니다 . 이것을 더 잘 이해하기 위해 예를 들어 봅시다.

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

세 가지의 차이점을 보시겠습니까? 미묘하지만 다르게 사용됩니다. 같이 call하고 apply, bind또한 값 오버 탈 것 this도트 메소드 호출에 의해 설정합니다.

또한이 세 기능 중 어느 것도 원래 기능을 변경하지 않습니다. call그리고 apply갓 건설 기능에서 값을 반환하면서bind 준비가 갓 건설 기능 자체가, 호출 할 돌아갑니다.

추가 물건, 이것을 복사

때로는 this범위, 특히 중첩 범위에 따라 변경 되는 사실이 마음에 들지 않습니다 . 다음 예를 살펴보십시오.

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

위의 코드 this에서 중첩 범위로 값이 변경 되었음을 알지만 this원래 범위에서 값을 원했습니다 . 우리가 ‘복사’그래서 thisthat사용 된 대신의 복사this . 영리한가?

인덱스:

  1. 개최 내용 this기본적으로 됩니까?
  2. 객체 점 표기법을 사용하여 함수를 함수로 호출하면 어떻게됩니까?
  3. 우리가 new키워드를 어떻게 되나요?
  4. 우리는 어떻게 조작 할 thiscallapply?
  5. 사용 bind.
  6. this중첩 된 범위 문제를 해결하기위한 복사

답변

“이것”은 범위에 관한 것입니다. 모든 함수에는 고유 한 범위가 있으며 JS의 모든 것이 객체이므로 함수조차도 “this”를 사용하여 일부 값을 자체에 저장할 수 있습니다. OOP 101은 “this”는 인스턴스 에만 적용 할 수 있다고 가르칩니다. 객체의 . 따라서 함수가 실행될 때마다 해당 함수의 새로운 “인스턴스”는 “this”라는 새로운 의미를 갖습니다.

대부분의 사람들은 다음과 같은 익명 클로저 함수 내에서 “this”를 사용하려고 할 때 혼란스러워합니다.

(함수 (값) {
    this.value = 값;
    $ ( '. some-elements'). each (function (elt) {
        elt.innerHTML = this.value; // 어 오!! 아마도 정의되지 않은
    });
}) (2);

여기에서 each () 안에서 “this”는 “value”를 기대하지 않습니다.

this.value = 값;

그 위에). 따라서이 문제를 극복하기 위해 개발자는 다음을 수행 할 수 있습니다.

(함수 (값) {
    var self = this; // 작은 변화
    self.value = 가치;
    $ ( '. some-elements'). each (function (elt) {
        elt.innerHTML = self.value; // 휴 !! == 2
    });
}) (2);

사용해보십시오. 이 프로그래밍 패턴을 좋아하기 시작합니다


답변

이 글타래가 엉망이되어서, 나는 this주제를 처음 접하는 독자들을 위해 몇 가지 요점을 정리했습니다 .

가치는 어떻게 this결정됩니까?

우리는 우리가 영어 같은 자연 언어 대명사를 사용하는 방법과 유사한 사용 : “때문에 요한이 빠른 실행 그가 기차를 잡으려고 노력하고있다.” 대신에 우리는“… John 이 기차를 타려고 노력하고 있습니다 ”라고 쓸 수있었습니다 .

var person = {
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this 객체는 객체가 정의 된 함수를 호출 할 때까지 값이 할당되지 않습니다 . 전역 범위에서 모든 전역 변수와 함수는 window객체에 정의됩니다 . 그러므로, this전역 함수에서 전역 window객체 를 참조하고 그 값을 갖습니다 .

use strict, this세계에서 어떤 개체에 바인딩되지 않은 익명 함수에서하는의 값을 보유 undefined.

this키워드는 오해 1) 우리가 사용하는 그 방법 빌리 : this2)는 우리가 사용하는 방법을 지정 this변수, 3) 함수가 사용가 this4 콜백 함수로 전달되고,이) this클로저 내에서 사용된다 – 내부 기능. (2)

표

미래를 잡는 것

ECMA Script 6에 정의 된 화살표 기능 this은 둘러싸는 (기능 또는 전역) 범위 의 바인딩을 채택합니다 .

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

화살표 함수는을 사용하는 대안을 제공하지만 더 널리 이해되는 어휘 범위 지정을 위해 bind()전통적인 this메커니즘을 비활성화한다는 점에 유의해야합니다 . (1)


참고 문헌 :

  1. Kyle & Simpson의 this & Object Prototypes © 2014 Getify 솔루션.
  2. javascriptissexy.com- http : //goo.gl/pvl0GX
  3. 앵거스 크롤 – http://goo.gl/Z2RacU

답변

thisJavaScript에서 항상 실행중인 함수의 ‘소유자’를 나타냅니다 .

명시 적 소유자가 정의되지 않은 경우 최상위 소유자 인 창 개체가 참조됩니다.

내가 한 경우

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

this요소 객체를 참조합니다. 그러나 많은 사람들이이 실수를 저 지르십시오.

<element onclick="someKindOfFunction()">

후자의 경우, 함수를 요소에 넘기는 것이 아니라 함수를 참조 할뿐입니다. 따라서 this창 개체를 참조합니다.


답변

자바 스크립트의 모든 실행 컨텍스트 에는 다음에 의해 설정된 this 매개 변수가 있습니다.

  1. 함수 호출 방법 (오브젝트 메소드, 호출적용 사용, new 사용 포함 )
  2. 바인드 사용
  3. 어휘 화살표 기능 (그들이 채택 그 외측의 실행 컨텍스트를)
  4. 코드가 엄격 또는 비 엄격 모드인지 여부
  5. 코드를 사용하여 호출했는지 여부 eval

당신의 값을 설정할 수 있습니다 사용을 func.call, func.apply또는 func.bind.

기본적으로 대부분의 초보자를 혼란스럽게 만드는 요소는 DOM 요소에서 이벤트가 발생한 후 리스너가 호출 될 때 함수 의이 값은 DOM 요소입니다.

jQuery는 jQuery.proxy로이 사소한 변경을 만듭니다.