JavaScript에서 Call, Apply, Bind는 Function 개체와 함께 제공되는 세 가지 메서드입니다. 이 기사에서는 여러 시나리오를 적용하여 세 가지 메서드를 자세히 이해할 것입니다.
콜()
call() 메소드는 지정된 this 값과 지정된 여러 매개변수 값을 사용하여 함수 또는 메소드를 호출합니다.
함수를 호출할 때 다른 this 개체를 할당할 수 있습니다. 이는 호출 메소드의 첫 번째 매개변수인 현재 객체를 나타냅니다.
call 메서드를 통해 Object.prototype.toString.call([])과 같이 한 개체의 메서드를 다른 개체에서 빌릴 수 있습니다. 이는 Object 개체의 메서드를 차용하는 Array 개체입니다.
구문 fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg
fun 함수가 실행될 때 지정되는 this 값입니다. 주의하셔야 할 사항은 다음과 같은 상황입니다
(1) 전달하지 않거나 null 또는 정의되지 않은 값을 전달합니다. 이는 함수에서 창 개체를 가리킵니다.
(2) 다른 함수의 함수 이름을 전달합니다. 함수에서 이 함수에 대한 참조를 가리키며, 함수가 실행될 때 반드시 실제 this 값은 아닙니다.
(3) 값이 기본 값(숫자, 문자열, 부울 값)인 이는 문자열, 숫자, 부울과 같은 기본 값의 자동 패키징 개체를 가리킵니다
(4) 객체를 전달하고 함수의 this가 이 객체를 가리킵니다.
arg1, arg2, ...
지정된 매개변수 목록입니다.
예
초등 응용예
function a(){ //输出函数a中的this对象 console.log(this); } //定义函数b function b(){} var obj = {name:'这是一个屌丝'}; //定义对象obj a.call(); //window a.call(null); //window a.call(undefined);//window a.call(1); //Number a.call(''); //String a.call(true); //Boolean a.call(b);// function b(){} a.call(obj); //Object
call 메소드를 사용하여 익명 함수를 호출하고 컨텍스트를 지정하세요
다음 예에서는 Greeting 메소드가 호출되면 메소드의 this 값이 i 객체에 바인딩됩니다.
function greet() { var reply = [this.person, '是一个轻量的', this.role].join(' '); console.log(reply); } var i = {function greet() { var reply = [this.person, '是一个轻量的', this.role].join(' '); console.log(reply); } var i = { person: 'JSLite.io', role: 'Javascript 库。' }; greet.call(i); // JSLite.io 是一个轻量的 Javascript 库。 person: 'JSLite.io', role: 'Javascript 库。' }; greet.call(i); // JSLite.io 是一个轻量的 Javascript 库。
call 메서드를 사용하여 익명 함수 호출
다음 예의 for 루프 본문에서는 익명 함수를 생성한 다음 각 배열 요소를 지정된 this 값으로 사용하여 함수의 호출 메서드를 호출하여 익명 함수를 실행합니다. 이 익명 함수의 주요 목적은 각 배열 요소 개체에 인쇄 메서드를 추가하는 것입니다. 이 인쇄 메서드는 배열에 있는 각 요소의 올바른 인덱스 번호를 인쇄할 수 있습니다. 물론 배열 요소를 이 값으로 익명 함수에 전달할 필요는 없습니다(일반 매개변수이면 충분합니다). 호출 사용법을 보여주기 위한 것입니다.
var animals = [ {species: 'Lion', name: 'King'}, {species: 'Whale', name: 'Fail'} ]; for (var i = 0; i < animals.length; i++) { (function (i) { this.print = function () { console.log('#' + i + ' ' + this.species + ': ' + this.name); } this.print(); }).call(animals[i], i); } //#0 Lion: King //#1 Whale: Fail
call 메서드를 사용하여 함수를 호출하고 매개변수를 전달합니다
var a = { name:'JSLite.io', //定义a的属性 say:function(){ //定义a的方法 console.log("Hi,I'm function a!"); } }; function b(name){ console.log("Post params: "+ name); console.log("I'm "+ this.name); this.say(); } b.call(a,'test'); //Post params: test //I'm onepixel //I'm function a!
적용()
구문은 call() 메서드의 구문과 거의 동일하지만 유일한 차이점은 Apply의 두 번째 매개 변수가 여러 매개 변수를 포함하는 배열(또는 배열 유사 객체)이어야 한다는 것입니다. 이 적용 기능은 매우 중요합니다.
기존 함수를 호출할 때 해당 함수에 대해 this 개체를 지정할 수 있습니다. this는 이 함수를 호출하는 객체인 현재 객체를 나타냅니다. 적용을 사용하면 새 개체에 메서드를 반복해서 작성할 필요 없이 메서드를 한 번 작성한 다음 다른 개체에 상속할 수 있습니다.
구문: fun.apply(thisArg[, argsArray])
참고: Chrome 14 및 Internet Explorer 9에서는 여전히 배열과 유사한 개체를 허용하지 않는다는 점에 유의하는 것이 중요합니다. 배열과 유사한 객체가 전달되면 예외가 발생합니다.
매개변수
thisArg
위 호출의 thisArg 매개변수와 동일합니다.
argsArray
배열 또는 배열 유사 객체로, 배열 요소는 fun 함수에 별도의 매개변수로 전달됩니다. 이 매개변수의 값이 null이거나 정의되지 않은 경우 매개변수를 전달할 필요가 없음을 의미합니다. ECMAScript 5부터 배열과 유사한 객체를 사용할 수 있습니다.
예
function jsy(x,y,z){ console.log(x,y,z); } jsy.apply(null,[1,2,3]); // 1 2 3
링크 생성자에 적용 사용 예
적용을 사용하면 Java와 유사하게 생성자를 객체에 연결할 수 있습니다. 다음 예에서는 생성자에서 매개변수 목록 대신 배열과 유사한 객체를 사용할 수 있도록 생성이라는 전역 함수 함수를 생성합니다. .
Function.prototype.construct = function(aArgs) { var fConstructor = this, fNewConstr = function() { fConstructor.apply(this, aArgs); }; fNewConstr.prototype = fConstructor.prototype; return new fNewConstr(); }; function MyConstructor () { for (var nProp = 0; nProp < arguments.length; nProp++) { console.log(arguments,this) this["property" + nProp] = arguments[nProp]; } } var myArray = [4, "Hello world!", false]; var myInstance = MyConstructor.construct(myArray); console.log(myInstance.property1); // logs "Hello world!" console.log(myInstance instanceof MyConstructor); // logs "true" console.log(myInstance.constructor); // logs "MyConstructor"
적용 및 내장 기능 사용
스마트 적용을 사용하면 배열 변수에 대한 반복으로 작성될 특정 작업에서 내장 함수를 사용할 수 있습니다. 다음 예에서는 Math.max/Math.min을 사용하여 배열의 최대/최소값을 찾습니다.
//里面有最大最小数字值的一个数组对象 var numbers = [5, 6, 2, 3, 7]; /* 使用 Math.min/Math.max 在 apply 中应用 */ var max = Math.max.apply(null, numbers); // 一般情况是用 Math.max(5, 6, ..) 或者 Math.max(numbers[0], ...) 来找最大值 var min = Math.min.apply(null, numbers); //通常情况我们会这样来找到数字的最大或者最小值 //比对上面的栗子,是不是下面的看起来没有上面的舒服呢? max = -Infinity, min = +Infinity; for (var i = 0; i < numbers.length; i++) { if (numbers[i] > max) max = numbers[i]; if (numbers[i] < min) min = numbers[i]; }
매개변수 배열을 여러 조각으로 잘라 루프를 통해 전달합니다
function minOfArray(arr) { var min = Infinity; var QUANTUM = 32768; for (var i = 0, len = arr.length; i < len; i += QUANTUM) { var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len))); console.log(submin, min) min = Math.min(submin, min); } return min; } var min = minOfArray([5, 6, 2, 3, 7]);
바인딩
bind() 함수는 새로운 함수(바운드 함수라고 함)를 생성합니다.
바인드는 ES5의 새로운 방법입니다
매개변수 전달은 호출 또는 적용과 유사합니다
해당 기능이 실행되지 않으며, 호출 또는 적용 시 해당 기능이 자동으로 실행됩니다
함수에 대한 참조를 반환합니다
구문 fun.bind(thisArg[, arg1[, arg2[, ...]]])
다음 예: 웹 페이지를 클릭하면 EventClick이 트리거되어 실행되고 JSLite.io p1 p2가 출력되는데 이는 EventClick에서 바인딩에 의해 obj 개체로 변경되었음을 나타냅니다. EventClick.bind(obj,'p1','p2')를 EventClick.call(obj,'p1','p2')로 변경하면 페이지에 JSLite.io p1 p2가 직접 출력됩니다
var obj = {name:'JSLite.io'}; /** * 给document添加click事件监听,并绑定EventClick函数 * 通过bind方法设置EventClick的this为obj,并传递参数p1,p2 */ document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false); //当点击网页时触发并执行 function EventClick(a,b){ console.log( this.name, //JSLite.io a, //p1 b //p2 ) } // JSLite.io p1 p2
호환
if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, // this在这里指向的是目标函数 fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP ? this //此时的this就是new出的obj : oThis || this,//如果传递的oThis无效,就将fBound的调用者作为this //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递 aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用 fBound.prototype = new fNOP(); //返回fBond的引用,由外部按需调用 return fBound; }; }
应用场景:继承
function Animal(name,weight){ this.name = name; this.weight = weight; } function Cat(){ // 在call中将this作为thisArgs参数传递 // Animal方法中的this就指向了Cat中的this // 所以Animal中的this指向的就是cat对象 // 在Animal中定义了name和weight属性,就相当于在cat中定义了这些属性 // cat对象便拥有了Animal中定义的属性,从而达到了继承的目的 Animal.call(this,'cat','50'); //Animal.apply(this,['cat','50']); this.say = function(){ console.log("I am " + this.name+",my weight is " + this.weight); } } //当通过new运算符产生了cat时,Cat中的this就指向了cat对象 var cat = new Cat(); cat.say(); //输出=> I am cat,my weight is 50
原型扩展
在原型函数上扩展和自定义方法,从而不污染原生函数。例如:我们在 Array 上扩展一个 forEach
function test(){ // 检测arguments是否为Array的实例 console.log( arguments instanceof Array, //false Array.isArray(arguments) //false ); // 判断arguments是否有forEach方法 console.log(arguments.forEach); // undefined // 将数组中的forEach应用到arguments上 Array.prototype.forEach.call(arguments,function(item){ console.log(item); // 1 2 3 4 }); } test(1,2,3,4);