>  기사  >  웹 프론트엔드  >  javascript_기본지식 중 호출 적용 및 바인드 방법에 대한 자세한 설명

javascript_기본지식 중 호출 적용 및 바인드 방법에 대한 자세한 설명

WBOY
WBOY원래의
2016-05-16 15:11:251653검색

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
     &#63; 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;
 };
}

兼容例子来源于:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility

应用场景:继承

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);

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.