js 진급-this,call,apply 상세 설명

this의 지향

  • 많은 경우에this지향개념이 모호한 상황이 자주 나타난다!this 지향과 함수 작용역은 시간선상에서 완전히 상반되는 두 가지입니다. 함수 작용역은 당신이 정의할 때 이미 귀속을 결정하고this는 코드를 실행할 때 호출된'대상'이 결정됩니다!

  • this가 가리키는 대략적인 상황

  • this는 대상 내부의 함수 방법에서 호출한다.
  • 일반 함수의 내부 호출;
  • 구조기에서 호출하기;
  • call,apply에서 호출하기;

  • 대상 내부 함수의 방법에서 호출

  • 이때this는 이 대상을 가리킨다
  • 
    var obj = {
        name:"Wythe",
        getName:function(){
            console.log(this.name);
        }
    };
    
    obj.getName();   //Wythe
    

    일반 함수 내부에서 호출

  • 이때 가리키는 것은 전역, window입니다. 일반 함수는 등록할 때 window 아래에 마운트됩니다. window.fun(){}처럼
  • var name = "lucy"
    var norMal = function () {
        var name = "Wythe"
        console.log(this.name)
    }
    norMal();   //lucy
    // 
    var obj = {
        name:"Wythe",
        getName:function(){
            console.log(this.name);
        }
    };
    
    var getName = obj.getName
    getName();   //lucy    this obj !
    
  • 예를 들어 실제 응용에서 우리는 이런 상황을 만날 수 있다. 편의를 위해 나는 여기서 간략하게 썼다.
  • //
    //
    //  
    //  
    //      
    // // window.id = "haha"; document.getElementById("divEle").onclick = function () { console.log(this.id);//divEle //var that = this var callback = function () { console.log(this.id);//haha , , ; //that.id } callback() } // //

    만약 우리가 미리 하나의 변수로this를 수신하여 전달하면 이 문제를 해결할 수 있습니다!패키지를 닫는 것과 같이 하나의 변수로 작용역을 직렬로 연결합니다.

  • javascript에는 클래스가 없어요. 사람이 많아져서 클래스가 됐어요!신기한 것은 공식적으로 new 키워드, 하나의 종류의 구조기를 주었다!js에는 실제적인 의미의 클래스가 확실히 없지만 똑똑한 프로그래머들은 그 중에서 하나의 클래스의 길을 쌓을 수 있다!

  • 그래서 우리는 구조기를 이용하여 이렇게 대상의 실례를 만들었다.
    
    var theClass = function () {
        this.name = 'lucy'
    }
    var obj = new theClass();
    console.log(obj.name); //lucy
    
    
  • 모든 일에는 예외가 있다. 함수 반환 값의 특수한 원인 때문에 반환 값이 하나의 대상이거나 표시적으로 데이터를 반환하면 함수는 앞의 것을 무시하고 표현식에서 수신한 값의 변수에 대상을 직접 되돌려준다.
  • var theClass = function () {
        this.name = 'lucy'
        return {
            name: 'Bob'
        }
    }
    var obj = new theClass();
    console.log(obj.name); //Bob
    

    만약 return 'Bob' 이런 상황이 발생하지 않았을 것이다!

    Function.prototype.call Function.prototype.apply

  • call과 apply는 함수식 스타일의 프로그래밍에서this의 지향을 바꾸어 하늘을 훔치고 별을 돌리는 효과에 자주 사용된다!C클래스가 대상 언어를 대상으로 하는 것처럼 하위 클래스는 하위 클래스를 계승하고 하위 클래스를 사용할 수 있는 방법처럼 다시 정의할 필요가 없고 매우 편리하다.
  • 
    var obj1 = function () {
        this.name = 'lucy'
        this.getName = function () {
            return this.name
        }
    }
    var obj2 = function () {
        this.name = 'Bob'
    }
    var obj3 = {
        name: 'Tom'
    }
    var obj4 = {
        name: 'Assa',
        getName: function () {
            return this.name
        }
    }
    var obj1 = new obj1();
    var obj2 = new obj2();
    console.log(obj1.getName());            //lucy
    console.log(obj4.getName.call(obj3));   //Tom
    console.log(obj1.getName.call(obj2));   //Bob
    console.log(obj1.getName.call(obj3));   //Tom
    console.log(obj4.getName.call(obj2));   //Bob
    
    

    구조기든 대상 데이터든call은this의 지향을 순조롭게 바꿀 수 있다.call과apply는 물론 이렇게 간단할 뿐만 아니라 뒷부분은 상세하게 설명한다.

    this

  • 어떻게this를 잃어버릴까요?먼저this는 실행할 때 호출되는 대상을 가리키기 때문에 어떤 상황에서 실행할 때 대상이 무자비하게 바뀔까요?바로 일반 함수로 집행할 때!대상의 함수체에 새로운 변수를 부여하면 이 새로운 함수 지향은 다시 바뀐다. 일반적으로 전역을 가리키는 window이다. 엔진을 컴파일할 때 전역의 변수와 함수를 자신의 석류 치마 밑에 마운트하기 때문이다!
  • 
    var obj = {
        name: 'Assa',
        getName: function () {
            return this.name
        }
    }
    var myObjGetName = obj.getName;
    console.log(obj.getName()); //Assa
    console.log(myObjGetName()); //undefined
    
    

    obj의 getName 함수체가 myObjGetName에 부여되면 myObjGetName 자체가 전역 변수이기 때문에 전역 window 아래를 마운트합니다. 실행할 때this의 지향은 원래의obj 대상을 가리키지 않습니다.
  • 또 다른 문제는 js의 일부 원생 방법의 재정의 문제이다. 예를 들어document.getElementById 이것은 특수한 방법이라고 하는데 우리가 먼저 무슨 잘못이 생길지 보자.
  • //
    //
    //    
    //    
    //        
    // // var getId = document.getElementById; console.log(getId("divEle")); //Uncaught TypeError // //

    그 이유는 get ElementById라는 방법 내부에서this를 사용했기 때문이다. 원래 이this는 문서를 가리키며 문서 흐름을 정상적으로 연결할 수 있었지만 변수에 부여된 값이 일반 함수가 되었고this 지향이 바뀌었다!
    //
    //
    //    
    //    
    //        
    // // document.getElementById = (function (func) { return function () { return func.apply(document,arguments) } })(document.getElementById); var getId = document.getElementById; console.log(getId("divEle")); // // //

    함수 자체 실행document.getElementById을 매개 변수로 전달하고apply는 함수체 안의this를 매개 변수의document을 강제로 가리킨다.예를 들어 getId가 실행될 때 id는 파라미터를 통해 전달되고func가 수신하며 동시에 실행 함수document.getElementById를 수신하여 대상을 받는다. apply는 document를this로 getId에 전달하여 getId의this에 변화를 일으켜 수정할 수 있다!

    call apply

  • Function.prototype.bind: 이것은this를 연결하는 데 사용되는 원생 함수입니다. 대부분의 브라우저는 완벽하게 실현되었지만 만약에 우리가 스스로 하나를 만들려고 한다면?
  • Function.prototype.bind = function (params) {
        var self = this;
        return function () {
            return self.apply(params,arguments);
        }
    };
    
    var obj = {
        name:"Lucy"
    };
    
    var func = function () {
        console.log(this.name);
    }.bind(obj);
    
    func()//Lucy
    
  • 이 예는 사실 세 가지 과정이 있는데 첫 번째 과정은func가bind를 호출하고 전달 대상obj이다.bind가 호출되었을 때 bind의this는func를 가리키지만 func 자체가 일반 함수이기 때문에func를 가리키면 func의this는window를 가리킨다.두 번째 과정에서bind 함수에self로 이 지향func를 저장하고 window를 지향한this를 저장하여 대상obj를 수신하고return은 후속 내용을 호출자func 함수로 전달한다.세 번째 과정은 원래 함수체로 되돌아왔지만 내부에 실행된 apply 함수가 있다. 그래서 apply는this의 변수를 미리 저장한 self를 첫 번째 매개 변수인 params를 가리키고 params의 속성을 두루 훑어본 후에 생성된 클래스 그룹arguments를 func 함수에 되돌려주었다. 이 params는 바로obj이다.최종적으로func의this가obj대상을 가리키는 결과가 형성되었다.
  • 전체적으로 말하자면 콜과 apply는 모두 버전을 바꾸는 데 사용되는this의 지향이고 호출자의this는 첫 번째 파라미터가 전달되는 대상을 가리키며 뒤의 파라미터는 모두 데이터로 호출자에게 전달된다!콜의 데이터는 분리되어 전달되고 뒤에는 여러 개의 매개 변수가 가능하며 apply의 두 번째 매개 변수는 수조나 클래스 수조로 전달됩니다!
  • 
    obj.getName.call(obj2,1,2,3,4);
    obj.getName.apply(obj2,[1,2,3,4]);
    
    

    call apply

  • 콜과 apply가 다른 대상을 가리킬 수 있는 이상 우리 일부 대상이 이미 만들어진 방법을 사용하고 싶을 때 이 방법의this가 특정한 대상을 가리키면 된다. 계승처럼 자신이 없는 방법을 마음껏 누릴 수 있다
  • 
    var A = function (name) {
        this.name = name;
    }
    var B = function () {
        A.apply(this,arguments)
    }
    B.prototype.getName = function () {
        return this.name;
    }
    
    var b = new B('Lucy');
    console.log(b.getName())
    
    

    실례적으로 하나의 B의 대상은 변수 b가 수신하고 매개 변수'lucy'를 전달한다. 비록 B 함수체는 형삼 수신 매개 변수를 설정하지 않았지만arguments는 데이터를 받고 클래스 그룹을 만들 수 있다.그리고 A.apply는this를 apply의 첫 번째 매개 변수인this를 가리킨다. 이this는 구조기의this를 대표하고arguments의 데이터를 A에게 전달한다.이어서 A의this(arguments로 전달된this, 실례화된 후 대상 b를 가리키는 것)의name 속성은 매개 변수name의 데이터(arguments에서 전달된)를 수신하여 b로 하여금 하나의 속성name을 형성하고 값은'Lucy'이다.마지막으로, b는 getName 방법을 호출하여 자신의 속성name 값을 되돌려줍니다.

    Array

  • js에는 수조와 유사하지만 수조가 아닌 데이터가 많다. 예를 들어 위의arguments, 그리고 어떤 HtmlCollection 문서 요소의 집합 등이 있다. 예를 들어 귀상 등은 본질적으로 수조가 아니면 수조를 사용할 수 없는 방법이다!그래서 우리는 Array를 빌려 쓸 것이다.prototype 대상의 방법:
  • 
    (function () {
        Array.prototype.push.call(arguments,3);
        console.log(arguments);
    })(1,2)
    
    /* 
    Arguments(3)
        0: 1
        1: 2
        2: 3
        callee: ƒ ()
        length: 3
        Symbol(Symbol.iterator): ƒ values()
        __proto__: Object
    */
    
  • 그러나 주의해야 할 것은 대상이 그룹을 호출하는 방법은 대상 자체에length의 속성이 없기 때문에 브라우저의 차이로 인해 실패할 수 있다. 예를 들어IE 브라우저이다.
  • var a  = {};
    Array.prototype.push.call(a,'first');
    console.log(a.length,a[0])//1 'first'
    
    var a  = 1;
    Array.prototype.push.call(a,'first');
    console.log(a.length,a[0])//undefined undefined
    

    지원하지 않는 브라우저를 만났을 때, 대상 등에 표시된 값length 속성 obj.length 이 필요합니다.
    [1] 참고 문헌인 자바스크립트 디자인 모델과 개발 실천, 텐센트 AlloyTeam을 살펴보았다.

    좋은 웹페이지 즐겨찾기