레이블이 Javascript인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Javascript인 게시물을 표시합니다. 모든 게시물 표시

2015년 6월 29일 월요일

javascript bind는 무엇인가?

아래의 질문에 대해 답해보자!
function foo() {};
foo.bind(this) !== foo.bind(this);
false
왜일까? 문제를 좀더 간단하게 바꾼 후 생각해보자
var a = {};
var b = {};
//묵시적으로 인터프리터에서 아래 문장으로 변환후 처리
//var a = new Object();
//var b = new Object();
a === b (a == b) 인가?
아니다 왜냐하면 a 와 b 는 다른 object 이기 떄문이다.
아래 주석처리된 부분을 보면 명확해 진다.
하나의 클래스에서 populate 된 두개의 다른 instance 이기 때문이다.(각기 다른 메모리 주소를 레퍼런스로 가지고 있다.)
Features of comparisons:
If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory
(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
위의 문장이 이해가 되었다면 아래 문장을 생각해보자
function foo() { console.log(this); console.log(arguments)};
var obj = {};
var a = foo.bind(obj,1);
var b = foo.bind(obj,1);
a(2,3);//1,2,3
b(2,3);//1,2,3
a === b
즉 2개의 새로운 함수를 생성한 후 위와 같이 두개의 래퍼런스가 같니라고 물어보는 상황인 것이다.
즉 false 가 나와야 함이 명확하다.
하지만 bind가 조금 애매하다.. 머하는 놈이었는지….
그럼 좀더 bind가 머하는 애인지 살펴보자!
Function.prototype.bind()
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
즉 새로운 함수를 생성하는대 해당 함수의 this 키워드를 주어진 argument의 첫번째 값으로 설정한 함수를 돌려 준다.
그후에 정의된 파라미터가 있으면 이후 호출시 해당 value를 미리 채워서 넘겨준다 라고 설명되어있다.
위의 설명을 확인하면 Function.prototype.bind 라는 함수는 아래처럼 정의 될수있다.
Function.prototype.bind = function() {  
  var _this = this;
  var outArg = Array.prototype.slice.call(arguments,0);
  return function() {
      var inArg = Array.prototype.slice.call(arguments,0);
    return _this.apply(outArg[0], outArg.slice(1).concat(inArg));
  }
}
var obj = {};
var a = foo.bind(obj,1);
var b = foo.bind(obj,1);
a(2,3);//1,2,3
b(2,3);//1,2,3
실재로 실행해보면 두개의 결과가 동일하다는걸 알 수 있다.
그렇다면 이제 처음 질문으로 돌아가 보자
function foo() {};
foo.bind(this) !== foo.bind(this);
여기서 this는 global object이기 때문에 host의 최상위 객체를 집어넣는다.
브라우저의 경우 window 이다.
즉 같은 파라미터를같는 두개의 펑션의 인스턴스를 생성한 후 두개의 인스턴스가 같니?
라는 질문이기 때문에 false 가 나와야 함이 자명하다!

2015년 3월 1일 일요일

javascript closer

클로저 정리

오브젝트에 종속된 속성들의 이름 해석

속성 이름에는 다른 오브젝트의 포인터 또는 primitive 타입을 할당 할수 있다.(undefined 도 primitive type)
var objectRef = new Object(); //일반적인 오브젝트 생성
objectRef.testNumber = 5;
//or
objectRef['testNumber'] = 5;
이름이 testNumber인 속성을 생성 , 속성 이름을 생성하고 나서 해당 속성에 값을 재 할당할 경우에는 존재하는 속성 값을 오버라이트 한다.
objectRef.testNumber = 8;
//or
objectRef['testNumber'] = 8;

오브젝트에서 값 읽기

오브젝트에 값을 읽을려고 할때는 prototypes도 고려해야한다. 만약 속성 접근자가 사용한 속성 이름을 오브젝트가 가지고 있다면 해당 속성 값을 리턴한다.
objectRef.testNumber = 8;
var val = objectRef.testNumber;
  • 오브젝트에 속성이름에 값을 할당하고
  • 오브젝트에서 해당 속성 이름으로 값을 읽어와
  • val 이라는 변수에 할당
    오브젝트는 prototype을 가질수 있다 . 해당 prototype은 오브젝트 이기 때문에 해당 prototype은 또다른 prototype을 가질수있다. 위의 식이 반복되어 prototype chain을 생성한다. prototype chain의 마지막 오브젝트는 prototype 으로 null값을 같는다.
    function MyObj1(num){
      this.testNumnber = num;
    }
    //MyObj1.prototype = new Object(); 프로토타입을 할당하지 않으면 디폴트로 할당됨
    function MyObj2(str){
      this.testStr = str;
    }
    MyObj2.prototype = new MyObj1(8);
    var obj = new MyObj2('test');
    
    위의 식을 보면 MyObj1을 new 로 생성해 인스턴스를 MyObj2의 프로토타입에 할당한다 그후 MyObj2를 new 로 생성해 obj에 할당한다.
  • obj 변수에 할당된 인스턴스는 프로토 타입 체인을 가지고 있다. (MyObj1 -> Object -> null)
  • var obj == MyObj2 의 인스턴스이며 MyObj2.prototype == MyObj1 -> Object -> null 과 같다.
    var val = obj.testStr;
    
    위와 같이 오브젝트의 값을 읽으려 할때 우선적으로 인스턴스의 값을 읽고 없으면 프로토타입 체인을 대상으로 읽기를 시도한다.위의 경우에서 testStr이 인스턴스에 존재함으로 ‘test’가 리턴된다 하지만 없으면 어떻게 될까?
    var val = obj.testNum;
    
    최초 인스턴스에 접근하지만 속성이 없음으로 prototype 체인을 확인한다. (javascript interpreter 가 instacne에서 값을 찾아 undefined가 리턴되야될 상황이라면 해당 instance 의 prototype chian 을 조사한다.) MyObj1이 해당 속성을 가지고 있음으로 8을 리턴한다.
    var val = obj.toString
    
    MyObj2 instacne가 값이 없음으로 prototype chain을 조사한다. MyObj1 이 값이 없음으로 MyObj1의 prototype chain을 조사한다 Object가 toString 속성이름을 가지고 있음으로 해당값을 리턴한다.(함수도 이런맥락에서는 속성값(오브젝트)으로 볼수있다.)
    var val = obj.isExist
    
    인스턴스와 모든 프로토 타입 체인을 조사해도 해당 속성 이름이 존재하지 않음으로 undefined를 리턴한다.
  • 위의 결과를 종합해 보자
  • 속성이름을 읽을때는 첫번째로 발견하는값을 리턴한다(읽는 순서 1.인스턴스, 2.프로토타입 체인)
  • 속성에 값을 할당할때는 해당 인스턴스에 할당된다(없으면 생성,있으면 재할당)
    MyObj2.testNumber = 100;
    
    위의 경우 어떻게 될까?
  • 위의 공식을 따르면 값을 할당함으로 MyObj2 인스턴스에 testNumber라는 속성을 만들고 100이라는 값을 할당한다. 이때
  • MyObj2의 프로토타입인 MyObj1의 인스턴스의 testNumber는 어떻게 될까? 당연이 아무런 일도 일어 나지 않는다.
  • 다시 MyObj2에 접근하면 읽는 순서에따라 인스턴스를 먼저 읽기 때문에 100 이 리턴된다.(해당속성이 mask되었다는 표현을쓴다.)

식별자 해석, 실행 환경, 스코프 체인(indetifier resolution, execution contexts and scope chain)

  1. 실행 환경 객체
    ECMA 스펙에서는 추상적으로 정의되어 있고 구현 명세가 있지 않다. execution context는 특정 속성들과 그 속성들이 정의된 구조를 가지고 있으면 됨으로 자바스크립의 object로도 구현될수 있다.
    모든 자바스크립트의 코드는 실행 환경 안에서 실행된다. 글로벌 코드의 경우 글로벌 실행 환경에서 실행되며 모든 함수 호출은 각각의 실행 환경을 가지고 실행된다. eval 의 경우는 조금 다른 실행 환경을 같지만 이문서에서는 다루지 않는다.
    함수가 호출되면 해당 함수의 실행 환경에서 실행이 된다 그 후 또 다른 펑션을 호출하면(재귀도 동일) 새로운 실행 환경이 형성되고 좀전의 실행 환경 위에 쌓고 거기 에서 실행한다. 리턴 되면 이전의 실행 환경에서 실행 된다. (스택구조이다.)
    그렇며 어떻게 실행 환경이 어떤 순서로 형성되는지 알아보자
    • 1.Actiavation 객체를 생성한다. 해당 객체는 속성값을 가지는 오브젝트이다. 하지만 prototype을 가지지 않으며 자바스크립트 코드에서 접근 할수없다.
    • 2.arguments 오브젝트를 생성한다. (어래이 비슷한 객체이다 *어레이는 아니다. 함수의 파라미터들과 callee를가지고 있다.))그후 Activation.arguments 속성에 생성한 arguments를 할당한다.
      1. 실행환경에 스코프를 할당한다. 스코프는 객체로 이루어진 리스트(체인)이다. (모든 함수 객체는 내부적으로 [[scope]] 속성을 가지고 있다) 호출된 함수의 [[scope]]속성 앞에 Activation object 를 더한 후 실행 환경에 스코프를 할당한다.
      1. variable instantiation 이라는 단계가 실행된다. Activation 오브젝트가 Variable object로 동시에 사용된다. 해당 단계에서는 함수의 모든 파라미터들에 대해 Varaible object에 속성을 생성하고 만약 값이 넘어왔다면 할당한다.(없다면 undefined로 할당), 내부에 정의된 함수 정의의 이름을 Variable object에 만들고 해당 함수를 해당 속성에 할당한다. 로컬 변수들을 Varaible object의 속성으로 이름을 할당한다.(이떄 값은 undefined임, 실제 값은 함수가 실행될때 할당됨)
      • Ativation object 와 variable object는 같기 때문에 arguments 속성을 로컬 변수처럼 사용 할수 있다.
      1. this 키워드에 값을 할당한다 만약 이미 할당된 값이 오브젝트라면 해당 오브젝트를 사용하고 아니라면 글로벌 오브젝트를 사용한다.
    글로벌 오브젝트의 경우 파라미터가 없음으로 arguments속성이 없으며 scope의 체인은 글로벌오브젝트 객체 하나로 구성되어져 있다. 그후 변수 초기화 단계를 하는대 이때 글로벌에 정의된 함수들이 모두 글로벌 함수가 된다. 글로벌에 정의된 변수도 마찬 가지이다.
  2. scope chain and [[scope]]
    실행 되는 함수의 [[scope]] 속성앞에 Activation/Variable 객체를 추가해서 스코프 체인을 만들고
    실행 환경의 스코프 속성에 위의 스코프 체인을 할당한다.
    ECMA 스펙에서는 함수를 오브젝트로 정의하며 함수는 1. 정의된 함수는 변수 초기화 단계에서 생성된고 2. 함수 표현식은 실행될때 생성된다 3. 또는 함수 생성자를 호출해 생성할수도 있다.(생성자로 형성된 함수는 [[scope]]속성에 글로벌 오브젝트만 할당되어 있다.)
    함수 정의, 또는 함수 표현식으로 생성되는 함수들은 해당 함수를 생성한 실행 환경 객체의 스코프 속성의 값을 [[scope]]에 할당받는다.(재귀적 정의라는걸 알 수 있다.)
    글로벌에서 정의된 함수를 보자
     function exampleFunction(a1){
         //code
     }
    
    위의 함수는 글로벌 실행 환경 객체의 변수 초기화 단계에서 생성된다.(글로벌 실행 환경 객체는 Activation 단계가 없으며 variable object를 글로벌 실행 환경 객체와 동일한 오브젝트를 사용한다.) 글로벌 실행 환경의 스코프 속성은 글로벌 객체로 만 구성되어 있다.
    즉 exampleFunction 의 [[scope]]깂은 글로벌 객체 하나이다.(실행 환경 객체의 스코프 체인을 함수의 [[scope]]속성에 할당함으로)
     var exmpleFunctionRef = function(){
         //code
     }
    
    위의 식의 경우 함수 표현식임으로 글로벌 환경 객체의 변수 초기화 단계에서 실행되지 않는다. 하지만 함수의 생성이 글로벌 실행 위에서 실행됨으로 [[scope]] 값으로 글로벌 객체를 같는다.
    자 이번에는 재귀적 정의에의해서 할당되는 모습을 확인해보자
     function exampleOuterFunction(a1){
         function exmpaleInnerFunction(){};
     }
     exmpaleOuterFunction(999);
    
    1.exampleOuterFunction 의 [[scope]]속성은 글로벌 오브젝트이다(글로벌 실행 환경의 스코프값)
    1. 이제 글로벌 실행 환경에서 exampleOuterFunction(999)을 호출하면 새로운 실행 환경이 생성된다 이때 실행 환경의 스코프는 방금 생성된 Activation/Variable object + 함수의 [[scope]] 체인이 할당된다.
      도식화 한다면 아래의 그림과 같다. 번호는 할당되는 순서이다.
      @@@@@@스택(exmpaleOuterFunction)@@@@@@@@
      신규 실행환경(== actiavtion/variable) = {
       scope : 3.activation/variable -> exmpaleOuterFunction.[[scope]]
       a1:999
       exmpaleInnerFunction:{
           4.[[scope]] : activation/variable -> exmpaleOuterFunction.[[scope]]
       }
      }
      @@@@@@스택(global)@@@@@@@@
      글로벌 실행 환경( == variable) = {
       scope : 1.글로벌 오브젝트
       exmpaleOuterFunction:{
           2.[[scope]] : 글로벌 오브젝트
       }
      }
      @@@@@@스택@@@@@@@@
      
      with 문의 경우 해당 블럭안에서는 실행환경의 스코프 앞부분에 해당 오브젝트를 붙인다 그후 불락이 끝나면 오브젝트를 없앤다. 만약 함수 표현식이 with {}안에서 실행된다면 조금 다른 [[scope]]속성을 가지게 된다.
      var y = {x:5}; // object literal with an - x - property
      function exampleFuncWith(){
       var z;
       /* Add the object referred to by the global variable - y - to the
          front of he scope chain:-
       */
       with(y){
           /* evaluate a function expression to create a function object
              and assign a reference to that function object to the local
              variable - z - :-
           */
           z = function(){
               ... // inner function expression body;
           }
       }
       z()
       ... 
      }
      /* execute the - exampleFuncWith - function:- */
      exampleFuncWith();
      
      위에서 z는 with문 밖에서 실행되지만 이미 생성될때 [[scope]] {x:5} -> actiavation/variable -> 글로벌 오브젝트 를 할당 받았기 때문에 실행될때는 x변수에 접근이 가능하다.
  3. Identifier Resolution
    식별자 해석은 스코프 체인을 상대로 실행된다. ECMA262 스펙에서는 this 를 키워드로 구분한다 왜냐하면 스코프 체인과 상관없이 늘 실행 환경 객체에 의존해 해석되기 때문이다.
    식별자 해석은 최초 스코프 체인의 첫번째 오브젝트를 확인다 만약 해당 오브젝트에 존재하지 않는다면 해당 오브젝트의 모든 프로토타입을 확인한다. 만약 첫번째 찾지 못하면 체인의 2번째 오브젝트에 접근하고 식별자의 값이 리턴되거나 스코프 체인에서 null이 발견될때 까지 조사한다. 모든 스코프 체인의 마지막은 글로벌 오브젝트이고 글로벌 오브젝트의 프로토타입은 null이기 때문에 식별자 해석은 반드시 종료 된다.
     var c = {
         val3:3
     }
     function example(){
         var a = {val2:2};
         var val1 = a.toString;
         var val2 = a.val2;
         var val3 = c.val3;
         var val4 = c.val4;    
         console.log(val1);//function() toString{}
         console.log(val2);//2
         console.log(val3);//3
         console.log(val4);//undefined
     }
     example();
     신규 실행환경 객체 = {
         scope : activation/variable[a{val2:2}->Object{},...] -> 글로벌 오브젝트[c{val3:1},...]
     }
    
    위의 example함수의 신규 실행환경 객체위에서 실행되고 이때의 scope chain 은 위와 같이 구성되기 때문에 주석의 결과가 나온다.

원본
http://jibbering.com/faq/notes/closures/#clIdRes

2014년 11월 20일 목요일

Javascript Closures

원문 : http://jibbering.com/faq/notes/closures/

Introduction

Closure
 클로저는 자유 변수 와 그 변수들을 묶을수 있는 환경을 가지는 표현식(특히 함수)을 의미한다.

클로저는 ECMA 스크립트 중에서 가장 강력한 부분이다. 하지만 정확이 이해하지 않고서는 적절하게 사용하기 힘들다.
하지만 반대로 쉽게 생성할수 있으며 심지어 의도하지 않았을때도 사용될수 있다.(실수로)
그리고 클로저 사용은 잠재적으로 브라우저 실행 환경에서 좋지 않은 영향을 줄수있다.

그들의 단점을 커버하고 장점을 사용하기 위해서는 클로저 메커니즘에(작동하는 방) 대한 이해가 필요하다
클로저는 scope 의 identifier resolution(식별자 해석 후 선택) 에 많이 의존하는대 그말은 object 의 property resoultion(속성 해석 후 선택)에 의존한다는 말과 동일하다.

클로저를 간단이 설명해보면 ECMAscript 는 inner functions 을 사용할수 있다.
inner function 이란 다른 function안에 정의(function definition) 되거나 표현식(function express)으로 표현된 function 을 의미한다.

inner functions은 바깥 펑션(outer funciton)의 파라미터와 로컬 변수에 접근 할 수 있다.
클로저는 inner function 들이 outer function에 접근할수 있다는 것으로 구현된다.
그말은 outer fuction 이 리턴된 후에도 실행 될수 있음을 의미한다. 즉 outer function의 리턴후에도 로컬 변수와 파라미터에 접근 할수 있음을 의미한다. 이 로컬 변수와 파라미터들은 outer function이 리턴될 떄믜 값을
가지고 있으며 inner function 으로 조작할수있다.

불행이도 클로저를 이해하기 위해서는 클로저가 내부적으로 어떤 메커니즘을 사용하는지를 이해해야 한다.
기술적으로 꽤 복잡하다. ECMA 262 명세의 알고리즘은 조금전에 설명한 부분을 조금 이해하기 힘들게 할수도 있지만
쉽게 단순화 시켜 설명할수 없다.

객체 속성 해석(object property name resoultion)에 대해 잘알고 있는 사람은 아래 섹션을 넘어가고 밑에 부분의 보면된다.

오브젝트 속성 이름 해석
(The resolution of property names on objects)

Ecmap Script 는 크게 Native object 와 Host Object 2가지로 구성되어 있다.
native object 의 하위 카테고리에는 Built-in object(이미 구현되어 있는 객체)다

Native object 는 언어에 종속되어 있으며 host object는 환경에의해(브라우저, node.js) 제공된다. 예를 들면 (doc obj or Dom node 같은 애들)

Native object 는 이미 정의된 속성들을 가지고 있으며 필요시 동적으로 정의할수 있다.(구현체에 따라 동적으로 정의 할수 없을수도 있다. 하지만 별 상관없다.);

object 에 정의된 속성들은 value 을 가질수도 있다. 값은 다른 객체의 reference 일수도 있고 primitive 값일수도 있다.
(primitive type 은 String, number, Boolean, Null, Undefiend 가 있고 Undefiend가 값이라면 속성은 정의 되었지만 값은 아직 할당되지 않은 상태를 의미한다. )

아래는 object 에 속성이 어떻게 정의 될수 있는지를 표현한다.

Assignment of values
객체의 속성들은 새로 생성될수도 있고 이미 존재하는 속성에 값을 할당할수도 있다.

var objectRef = new Object(); //javascript object 객체를 생성하고

testNumber 속성을 생성해보자

objectRef.testNumber = 5;
// 또는
objectRef["testNumber"] = 5;

javascript object 는 prototype 을 가지고 있으면 그들은 object 일수도 있다 또한 그 오브젝트안에 속성들이 존재할수도 있다 하지만 이부분은 변수 배정에는 아무런 영향을 끼치지 못한다.

속성에 값을 배정할때 실제 객체에 해당 속성이 존재하지 않는다면 속성이 생성되고 값이 배정된다.
만약 존재한다면 해당 속성의 값을 재설정한다.

Reading of Values

속성의 값을 읽을때 prototype이 영향을 미친다.
만약 속성 접근자에서 사용된 속성의 이름이 객체에 존재한다면 그값이 리턴된다.

/* 객체의 속성값에 값을 할당할때 만약 해당 속성이 존재하지 않는다면 생성하고 배정한다.
그러므로 값을 할당 후에는 해당 속성이 생성되어 있다 */
objectRef.testNumber = 8;

/*속성에서 값읽기*/
var val = objectRef.testNumber;
/* val은 객체 속성에서 읽어드린 8 값을 가지고 있다. */

하지만 모든 객체들은 prototype 을 가지고 있으며 prototype에 할당된 객체들도 prototype을 가지고 있을수 있다
그러므로 prototype chian 이라는걸을 구현한다.
prototype chain은 체인의 마지막의 객체가 null을 prototype으로 가지고 있으면 종료된다.
Object 생성자는(constructor) 기본적으로 null prototype을 가지고 있다 .


var objectRef = new Object(); //javascript object 만들기

위의 오브젝트는 Object.prototype을 prototype 으로 가지고 생성되었다
Object.prototype 의 prototype은 null임으로 ObjectRef 의 prototype chain 은 오직하나의 Object(Object.prototype)를 가지고 있다

하지만 아래를 보자

/*MyObject1 type의 object를 만드는대 사용하는 생성자 함수*/
function MyObject1(formalParameter){
 /*생성된 오브젝트에 - testNumber - 라는 속성을 할당하고 생성자에 넘겨진 첫번째 arg로 값을 할당함
 */

 this..testNumber = formalParameter;
}

/* MyObject2 type의 object 를 만드는대 사용하는 생성자 함수*/
function MyObject2(formalParameter){
 /* 생성된 오브젝트에 -testString -라는 속성을 할당하고 생성자에 넘겨진 첫번째 arg로 값을 할당함
 this.testString = formalParameter;
}

/* MyObject2의 default prototype 에 MyObject1을 할당하며 이때 MyObject에 8을 arg로 넘겨
   testNumber 를 8로 할당
*/

MyObject2.prototype = new MyObject1(8);

/* MyObject 를 생성하고 해당 오브젝트를 objectRef 에 넘긴다 이때 MyObject2 의 "String_value"를 넘겨
   testString 을 "String_value"로할당
*/

var objectRef = new MyObject2("String_Value");

objectRef 에 할당된 MyObject2 instance는 prototype chain 을 가지고있다
chain 의 첫번째는 MyObject1 instance다
MyObject 1 의 prototype 은 기본적으로 Object.prototype 이며
Object.prototype 의 prototyp은 null prototype을 가지고 있다
즉 MyObject2 아래와 같은 prototype chain 이 만들어진다.
MyObject1->Object->null

property accesor(프로퍼티 접근자)가 objectRef 의 속성에 접근할때는 모든 prototype chian 이 process에
들어옴니다.
var val = objectRef.testString;

위의 경우 MyObject2 가 testString 을 가지고 있음으로 val 에 "Sring_Value"가 할당됨니다.
하지만

var val = objectRef.testNumber;

를 하게 될경우 MyObject2에는 해당 속성이 없음으로 객체의 prototype 을 검삼합니다. MyObject1 에 testNumber가 있음으로 찾아서 8로 변수를 할당함니다.

var val = objectRef.toString;
의 경우 MyObject1, MyObject2 모두 속성값을 가지고 있지 않으면 prototype chain을 따라 올라감니다. Object 가 toString 을 가지고 있음으로 해당 함수고 리턴됨니다.


var val = objectRef.madeUpProperty
undefiend 가 할당됩니다. 왜냐하면 모든 prototype chian 을 조사해도 존재하지 않기 때문입니다.(순서대로 조사하다 마지막 null 에 도착하면 찾기가 종료됩니다.)

값을 읽을때는 첫번째로 찾은 값이 리턴됩니다.(체인에서 앞쪽에 있는 객체의 속성값)
하지만 값을 할당할때 해당 속성이 해당객체(prototype chain 제외)존재하지않는다면 해당 속성을 생성합니다.

즉 objectRef.testNumber = 3 를 하게 될경우 MyObject2의 인스턴스에 testNumber 가 만들어지고 값이 3으로 설정됩니다

추후의 접근 모두 My object2에 접근하게 되고  prototype chain은 더이상 검사되지 않습니다.
하지만 MyObject1.testNumber 는 8로 변경되지 않은체 존재하고 있습니다.
위와 같은 상황을 mask 라고 합니다.

ECMAScript 는 내부적  [[prototype]]을 Object type의 property로 할당합니다.
이 내부적 [[prototype]]은 script에서 접근할수 없습니다. 하지만  property accessor resoultion을 할경우
사용됩니다. 또한 object.prototype은 변경 할수 있으며 prototype 관련 접근 문제에는 object.prototype 과
object.[[prototype]]이 두개가 사용됩니다.

Identifier Resolution, Execution Contexts and scope chains
(식별자 해석, 실행 Contexts 그리고 scope chain)

The Execution Context
An executin context 는 ECMAScript의 구현체에 필요해서 사용되는 추상 사상이다(abstract concept).
명세서는 execution context 가 어떻게 구현되어 있어야 된다는 정의 되어 있지 않다. 하지만 execution context 는
명세에서 정의된 구현체(structure)를 위해서 몇개의 속성을 가져야한다.
그러므로 execution context 는 몇개의 공개되지 않는 속성을 가진 object 로 구현된다.

모든 javascript 코드는 execution context에서 실행된다. Global code는 globla execution context 에서 실행된다. 또한 호출되는 모둔 함수들은(constructor 포함)연관된 execution context 를 가진다.
eval 함수의 경우 다른 execution context 를 가진다. 하지만 일반적으로 사용하지 않음으로 여기에서는 다루지 않는다.
ECMS 262(3rd edition)의 10.2 절에  execution context 에 대한 정의가 있다.

javascript 함수가 호출되면 execution cotext 안에 들어온다. 만약 새로운 함수가 호출되면(같은 함수가 재귀적으로 호출되어도) 새로운 execution context 가 만들어지고 함수가 호출되는 동안 새로이 생성된 execution context 안에 들어온다. 그러므로 javascript  code 의 실행은 execution context stack 형태로 구현된다.

execution context 가 생성될때 정해진 순서대로 여러가지가 일이 이루어진다.
첫번쨰로 function 의 exectution context 에 Activation object가 생성된다.  activation object 의 매커님즘은 아래와 같다. 이건 몇개의 속성을 가진 오브젝트다 하지만 prototype을 가지지않는다(at least not a defiend prototype) 또한 javascript 코드에서 직접적으로 접근할수 없다.

두번째로 arguments를 만든다. 해당 함수 호출에 같이 넘겨진 arg들을 array 비슷한 객체에(integer index)로 접근가게 하여 만든다. 이것은 length 와 callee 속성을 가지고 있다

Activation object 는 arguments 속성을 만들고 좀전에 만들어진 arguments 를 속성의 값으로 할당한다

세번째로 execution context가 scope에 할당된다.
scope란 object 들이 연결된 리스트이다. 모든 function object 는 내부적으로 [[scope]] 속성을 가지고 있
다 [[scope]]속성또한 object들이 연결된 리스트로 구현되어 있다 execution context 에 할당된 스코프는
호출된 fuction이 가지고 있는 [[scope]] 의 속성 objects 리스트 맨앞에 activation object를 더한 거다

그후 variable instantation 이 ECMA262에서 "Varible" Object 라고 지칭하는 Object 를 사용해서 일어난다.
하지만 Activation object 가 Variable object 로 사용된다(Actiovation object 와 Variable Object는 동일한 Object 이다.)

함수에 넘겨진 parameter 별로 variable object에 속성을 만든다. 그후 argumnets 의 값을 동일한 해당 속성에 할당한다.
(없을 경우 undefiend 로 할당한다.)

ex) function aa(arg1, arg2, arg3) -> called aa(1,2) -> parameter arg1 = 1, arg = 2, arg3 = undefiend

그후 innerfunction definition으로 fuction object 를 생성하고 fuction 이름을 속성으로 하여 생성된 function object 를 할당한다. 마지막으로 함수안에 정의된 로컬 변수들을 variable object의 속성 이름을을 생성한다.
(이떄 로컬변수들은 undefiend 값이 할당된다.. 실제적인 로컬변수의 값은 함수의 body code 가 실행될때 변수에 할당된 expresstion 을 evaultion(평가)해서 할당된다. )

arguments 속성이 정의된 Activation Object가  함수의 로컬 변수가 정의된 Varaible Object 가 같은 객체이기 때문에 argumnets 식별자를 함수의 로컬 변수처럼 사용 할수 있다.

마지막으로 this keyword에 value 가 할당된다. 만약 object 가 할당된다면 this는 그 object 를 지징하며 null이라면
Global object 를 지칭하게 된다.

Global execution context 의 경우는 조금 다르다 외냐하면 argumnets가 없기 때문에 activation object를 정의할 필요가 없다 또한 scope chain은 정확이 하나의 global object 로 구성되어있다 그후 variable instantiation 단계를 실행한다. Global object를 Variable Object 로 사용한다  이렇기 때문에 global 에 선언한 함수들이 Global object 의 속성이 되는 이유이다. 또한 속성도 마찬가지이다.

도한 global execution context 에서 this 키워드는 global object 를 가리킨다.

scope chains and [[scope]]
execution context 에 할당되는 scope chain은 호출된 함수의 [[scope]]속성 맨앞에 execution context의 Activation /variable object 를 더해서 만들어진다.
그러므로 함수의 [[scope]] 속성이 어떻게 정의 되었는지 아는 부분이 중요하다.

ECMAScript 에서 함수는 object 이다. function object 는 variable instantiation 단계에서 만들어지거나
함수 표현식을 평가(evalution) 또는 Fuction 생성자를 호출할때 만들어 진다.

Function construcotr 로 만들어진 Fuction object의 [[scope]] 속성은 global object 로만 구성되어 있다.

execution context 의 scope chain 을 가진 function declaration 또는 function expresssion 안에서 생성된 함수들은 그들의 [[scope]]  속성에 부모의 scope chain 을 할당 받는다.

global function declaraion 으로 간단한 예를 들어보자
function exampleFunction(formalParameter){
 // function body code
}

해당 함수는 globle execution context 의 variabl instantiation 단계에서 생성된다. global execution context 는 global object 로만 이루어진 scope chain 을 가지고 있음으로 해당함수의 [[scope]]속성에는
glbal object 로 만 이루어진 scope chain을 가지게 된다.

비슷하게 global 에 정의된 fuction expression 을 보자
var exampleRuncRef = function(){
 // functio body code
}

위와 같은 경우 global object 의 named property 가 vaiable instantiation 단계에서 만들어지지만
function object의 경우 생성되지 않고 해당 속성이 사용될때 만들어진다.

?하지만 함수의 생성이 global executio contxt 에서 일어나므로 [[scope]] 속성은 하나의 global object 로 구성된다.

아래는 inner function declaration 과 express 이 function object 내부에서 만들어지기 때문에 조금 상향된 scope chain 을 같는다. 아래의 코드를 생각해보자
내부에 innerfunciton 을 정의하고 outer function 을 실행하는 예제이다

function exampleOuterFunction(formalparamter){
 function exampleInterFunctionDec(){
  // inner function body
 }
 // the rest of the outer funciton body
}

exampleOuterFunction(5)

outerfuncion 의 경우 gloabl execution context 의 vairable instantiation 단계에서 생성되가 이때문에
[[scope]] 속성에 glolbal object 가 할당된다.

그후 글로벌에서 exampleOuterFunction 을 실행 시키면 새로운 execution context 가 생성된다.
그리고 Activaion/Variable object 순서가 차례로 실행된다. 이때 exampleOuterFuntion 의 scope 는 new Activiation object 를 exampleOuterFunction 의 [[scope]](global object 만존재) chain 앞에더해서 할당된다.

이때 outer funciton 의 varaible instatiation 단계에서 inner function definion 을 실행하게 되는대 이때
inner function의 [[scope]] 에 해당 execution context 의 scope 가 할당된다.

이때의 scope 는 outerfunciton 의 activation object -> global object 로 구성되어 있다.

위에 기술된 부분은 소스 코드를 실행할때 자동으로 실행된다.

execution context 의 scope chian 은 함수를 생성할때 [[scope]] 속성에 할당되며 함수의 [[scope]]속성은 execution context 의 scope 를 정의하게 된다. (물런 [[scope]] 속성앞에 activation object 를 함쳐서 )

하지만 ECMAScript 의 with 문은 scope chain 을 변경할수 있다.

with 문은 expression 을 실행시킨다. 만약 expression 이 object 라면 현재 execution context 의 맨압부분에
(Activaion/Variable Object 앞에) 해당 오브젝트를 추가한다.
with 문 블락이 실행된 후에는 좀전에 변경된 execution context를 원래대로 복원한다.

function declartion 의 경우 variable instantiaion 단계에서 생성되기 때문에 영향을 받지 않을수 있지만
function express 의 경우 with statement 안에서 evaution 되기때문에 영향을 받을수 있다.

/ obcjet 를 가리키는 y를 만든다.)
var y =  {x:5};
function exampleFuncWith(){
 var z;
 /* 좀전의 y object 를 context scope chain 앞에 붙인다.)
 with(y){
  /* function expression 을 실행 시켜 funciton object 를 만들고 local 변수 z에 할당한다.
  */

  z = function(){
   // inner function expression body
  }

 }
 ....
}

/*execute the exampleFuncWith */
exampleFuncWith();

exampleFUncWith 는 [[scope]] 로 global object 를 가지고 있다 이때 해당 함수를 실해하면 [[scope]]에 해당 Activation object 를 만들어서 앞에 붙이고 execute context 에 scope 를 할당한다
wish 문을 실행시키면 글로벌 object y를 scope chain 앞에 붙이고 안에 바디문을 실행한다.
그러므로 안에서 실행된 function expressein 의 [[scope]] 에는 y->outer activation obj->global obj가 할당된다.

그후 with 문의 블락이 끝나면 원래대로 scope chain 을 복귀한다 하지만 with 문의 블락안에서 생성된 함수 객체의 [[scope]]속성에는 y object 가 맨앞에 있다.

Idetifier Resolution
(식별자 해석)

식별자는 scope chain 에 대항해서 resolve 된다. ECMA 262 에서는 this 를 속성보다는 keyword 로 분류한다.
이말은 this 가 scope chain 을 참조하지 않고 실행되는 execution context에 따라 정의 됨을 의미한다.

식별자 해석은 scope chain 의 맨 앞부분에서 시작된다. 일단 식별자에 대응하는 해당 이름 속성이 정의되어있는 확인한다.
왜냐하면 scope chain 은 object의 chain 이기 때문이다. 일단 object 의 prototype chain 을 포함해서 확인한다.
만약 scope chain 의 첫번째 object 에서 해당 값을 찾지 못하면 다음 chain 의 object 로 넘어간다.
넘어가면서 찾거나 아니면 scope chain 이 끝날때까지 찾는다.

identifier opertaion 은 위에서 언급한 propery acessor  와 동일하다.
만약 object 가 scope chain 에서 식별 되었다는 것은 해당 속성이 오브젝트를 가지고 있다 property accesor 에서 그리고 식별자는 그 오브젝트의 속성처럼 행동한다.  글로벌 오브젝튼 언제나 scope chain 의 끝이다.


functio 호출과 연관된 exection contexts 는 chain 맨앞에 Activation/Varaible object 를 가지고 있을것이다.

funcito body 에서 사용된 식별자들은 효과적으로 파라미터와 내부 함수 정의 이름 또는 로컬 변수에 대해서 효과적으로 첫번째로 체크할수있다. 그것을 아마도 Activation/Varaible object 로 쉽게 resolve 될수도 있을것이다.

... 뒷부분은 그냥 읽었습니다. :)

다른 분의 번역 http://nodejs-kr.org/insidejs/archives/508