apply는 두 개의 매개변수를 허용합니다. 첫 번째 매개변수는 함수 본문에서 이 객체의 포인터를 지정합니다. 두 번째 매개변수는 첨자가 있는 컬렉션입니다. 이 컬렉션은 배열이거나 배열과 유사한 배열일 수 있습니다. into 요소는 호출된 함수에 매개변수로 전달됩니다.
var func = function( a, b, c ){ alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ] }; func.apply( null, [ 1, 2, 3 ] );
이 코드에서 매개변수 1, 2, 3은 배열에 배치되고 func 함수에 전달됩니다. 함께, 이들은 각각 func 매개변수 목록의 a, b 및 c에 해당합니다.
호출 시 전달되는 매개변수의 개수는 고정되어 있지 않습니다. Apply와 유사하게 첫 번째 매개변수도 함수 본문의 this 포인터를 나타냅니다. 두 번째 매개변수부터 시작하여 각 매개변수가 차례로 함수에 전달됩니다. :
var func = function( a, b, c ){ alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ] }; func.call( null, 1, 2, 3 );
JavaScript 해석기는 함수 호출 시 형식 매개변수와 실제 매개변수의 수, 유형, 순서의 차이를 고려하지 않습니다. 배열로 표현됩니다. 이런 의미에서 Apply는 호출보다 사용률이 더 높습니다. 함수에 전달되는 매개변수 수에 신경 쓸 필요가 없으며 적용을 사용하여 모두 푸시하면 됩니다. call은 apply에 포함된 구문적 설탕입니다. 함수가 허용하는 매개변수의 수를 정확히 알고 형식 매개변수와 실제 매개변수 간의 대응 관계를 한눈에 표현하려는 경우 매개변수를 전송하기 위해 호출을 사용할 수도 있습니다.
호출 및 적용 사용
1. 이 포인터 변경
호출 및 적용의 가장 일반적인 용도는 함수 내에서 이 포인터를 변경하는 것입니다. 예:
var obj1 = { name: 'sven' }; var obj2 = { name: 'anne' }; window.name = 'window'; var getName = function(){ alert ( this.name ); }; getName(); // 输出: window getName.call( obj1 ); // 输出: sven getName.call( obj2 ); // 输出: anne
getName.call(obj1) 코드가 실행될 때 getName 함수 본문의 이 항목은 obj1 개체를 가리키므로 여기서는
var getName = function(){ alert ( this.name ); };
은 실제로 다음과 같습니다.
var getName = function(){ alert ( obj1.name ); // 输出: sven };
실제 개발에서는 div 노드, div와 같이 이 포인터가 실수로 변경되는 시나리오에 자주 직면합니다. 노드의 onclick 이벤트에서 이는 원래 다음 div를 가리킵니다.
document.getElementById( 'div1' ).onclick = function(){ alert( this.id ); // 输出:div1 };
이벤트 함수에 내부 함수 func가 있는 경우 func 함수가 이벤트 내에서 호출되면 func 함수 본문의 this는 예상한 div가 아닌 창을 가리킵니다. 다음 코드를 참조하세요.
document.getElementById( 'div1' ).onclick = function(){ alert( this.id ); // 输出:div1 var func = function(){ alert ( this.id ); // 输出:undefined } func(); };
이때 호출을 사용하여 func 함수가 div를 가리킴:
document.getElementById( 'div1' ).onclick = function(){ var func = function(){ alert ( this.id ); // 输出:div1 } func.call( this ); };
2. Function.prototype.bind
대부분의 고급 브라우저는 내장된 Function.prototype을 구현합니다. 함수 내부에 This 지점을 지정하기 위한 바인딩 네이티브 Function.prototype.bind 구현이 없더라도 코드는 다음과 같습니다.
Function.prototype.bind = function( context ){ var self = this; // 保存原函数 return function(){ // 返回一个新的函数 return self.apply( context, arguments ); // 执行新的函数的时候,会 把之前传入的context // 当作新函数体内的this } }; var obj = { name: 'sven' }; var func = function(){ alert ( this.name ); // 输出:sven }.bind( obj); func();
Function.prototype.bind를 사용하여 func 함수를 "래핑"하고 객체 컨텍스트를 매개변수로 전달합니다. 이 컨텍스트 객체는 우리가 수정하려는 this 객체입니다.
Function.prototype.bind의 내부 구현에서는 먼저 func 함수에 대한 참조를 저장한 다음 새 함수를 반환합니다. 나중에 func 함수를 실행하면 방금 반환된 새 함수가 실제로 먼저 실행됩니다. 새 함수 내에서 self.apply(context,args) 코드는 원래 func 함수를 실행하고 func 함수 본문에 컨텍스트 개체를 다음과 같이 지정합니다.
이것은 Function.prototype.bind 구현의 단순화된 버전입니다. 일반적으로 우리는 이를 좀 더 복잡하게 구현합니다.
을 사용하면 func 함수에 일부 매개변수를 미리 채울 수 있습니다. >
Function.prototype.bind = function(){ var self = this, // 保存原函数 context = [].shift.call( arguments ), // 需要绑定的this 上下文 args = [].slice.call( arguments ); // 剩余的参数转成数组 return function(){ // 返回一个新的函数 return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) ); // 执行新的函数的时候,会把之前传入的context 当作新函数体内的this // 并且组合两次分别传入的参数,作为新函数的参数 } }; var obj = { name: 'sven' }; var func = function( a, b, c, d ){ alert ( this.name ); // 输出:sven alert ( [ a, b, c, d ] ) // 输出:[ 1, 2, 3, 4 ] }.bind( obj, 1, 2 ); func( 3, 4 );