js 진급-this,call,apply 상세 설명
32921 단어 JavaScript 학습 노트
this의 지향
this가 가리키는 대략적인 상황
대상 내부 함수의 방법에서 호출
var obj = {
name:"Wythe",
getName:function(){
console.log(this.name);
}
};
obj.getName(); //Wythe
일반 함수 내부에서 호출
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을 살펴보았다.