>웹 프론트엔드 >JS 튜토리얼 >Javascript_javascript 기술에서 적용, 호출 및 바인딩의 사용 둘러보기 모드를 켭니다.

Javascript_javascript 기술에서 적용, 호출 및 바인딩의 사용 둘러보기 모드를 켭니다.

WBOY
WBOY원래의
2016-05-16 15:34:461098검색

이 기사를 통해 Apply, Call 및 Bind에 대한 이해가 명확하게 향상되고 기억력이 깊어지는 데 도움이 되는 멋진 용도를 나열할 수 있기를 바랍니다.

신청,전화

JavaScript에서는 함수 실행 시 컨텍스트를 변경하기 위해 호출과 적용이 모두 존재합니다. 즉, 함수 본문 내에서 this의 포인터를 변경하는 것입니다.

JavaScript의 주요 특징은 함수에 "정의 컨텍스트"와 "런타임 컨텍스트"라는 개념이 있고 "컨텍스트가 변경될 수 있다"는 것입니다.

먼저 코드 예를 들어보겠습니다.

function fruits() {}
fruits.prototype = {
  color: "red",
  say: function() {
    console.log("My color is " + this.color);
  }
}
var apple = new fruits;
apple.say();  //My color is red

하지만 바나나 = {color : "yellow"} 객체가 있고 해당 say 메소드를 재정의하고 싶지 않은 경우 호출 또는 적용을 통해 Apple의 say 메소드를 사용할 수 있습니다.

banana = {
  color: "yellow"
}
apple.say.call(banana);   //My color is yellow
apple.say.apply(banana);  //My color is yellow

따라서 객체에 특정 메소드가 없지만(이 밤에 있는 바나나에는 say 메소드가 없음) 다른 객체에는 이를 동적으로 변경하는 호출 및 적용이 나타나는 것을 볼 수 있습니다. say 메소드) 호출 또는 적용을 사용하여 다른 객체의 메소드를 사용하여 작업할 수 있습니다.

신청과 전화의 차이

적용과 호출 모두 기능은 완전히 동일하지만 매개변수를 받아들이는 방식이 다릅니다. 예를 들어 다음과 같이 정의된 함수가 있습니다.

var func = function(arg1, arg2) { 
};

은 다음과 같이 호출할 수 있습니다.

func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])

지정하려는 컨텍스트는 임의의 JavaScript 객체(JavaScript의 모든 것은 객체임)일 수 있으며 호출은 매개변수를 순서대로 전달해야 하며 Apply는 매개변수를 배열에 넣습니다. ​

자바스크립트에서는 함수의 매개변수 개수가 정해져 있지 않으므로 조건을 적용하려면 매개변수 개수를 확실히 알 수 있을 때 호출을 사용하세요.

확실하지 않은 경우 적용을 사용한 다음 매개변수를 배열에 푸시하고 전달하세요. 매개변수 개수가 불확실한 경우 인수 배열을 통해 함수 내에서 모든 매개변수를 탐색할 수 있습니다.

기억을 통합하고 심화하기 위한 몇 가지 일반적인 용도는 다음과 같습니다.

1. 배열 사이에 추가

var array1 = [12 , "foo" , {name "Joe"} , -2458]; 
var array2 = ["Doe" , 555 , 100]; 
Array.prototype.push.apply(array1, array2); 
/* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

2. 배열의 최대값과 최소값을 가져옵니다

var numbers = [5, 458 , 120 , -215 ]; 
var maxInNumbers = Math.max.apply(Math, numbers),  //458
  maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

Number 자체에는 max 메소드가 없지만 Math에는 max 메소드가 있으므로 호출 또는 적용과 함께 해당 메소드를 사용할 수 있습니다.

3. 배열인지 확인합니다(toString() 메서드가 재정의되지 않은 경우)

functionisArray(obj){ 
  return Object.prototype.toString.call(obj) === '[object Array]' ;
}

4. 클래스(의사) 배열은 배열 방법을 사용합니다.

var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));

자바스크립트에는 의사 배열(Pseudo Array)이라는 객체 구조가 있습니다. 더 특별한 것은 인수 객체이며, NodeList 객체를 반환하는 getElementsByTagName, document.childNodes 등과 같은 호출은 의사 배열입니다. Array의 push, pop 등의 메소드는 적용할 수 없습니다.

그러나 Array.prototype.slice.call을 통해 length 속성을 갖는 실제 배열 객체로 변환할 수 있으므로 domNodes는 Array 아래의 모든 메소드를 적용할 수 있습니다.

신청 및 전화 사용법에 대한 깊은 이해

다음은 지원자에 대한 이해와 통화를 좀 더 깊이 있게 하기 위한 [면접 질문 빌려오기] 입니다.

console.log 메서드를 프록시할 수 있도록 로그 메서드를 정의합니다. 일반적인 해결 방법은 다음과 같습니다.

function log(msg) {
 console.log(msg);
}
log(1);  //1
log(1,2);  //1

위의 방법은 가장 기본적인 요구사항을 해결할 수 있지만 전달된 매개변수의 개수가 불확실한 경우 위의 방법은 유효하지 않습니다. 이때 전달되는 매개변수의 개수에 주의하세요. 여기서는 확실하지 않으므로 적용 방법을 사용하는 것이 가장 좋습니다.

function log(){
 console.log.apply(console, arguments);
};
log(1);  //1
log(1,2);  //1 2

다음 요구 사항은 다음과 같이 각 로그 메시지에 "(app)" 접두사를 추가하는 것입니다.

log("hello world");  //(app)hello world

어떻게 하면 좀 더 우아하게 할 수 있을까요? 이때 인수 매개변수가 의사 배열이라고 생각하고 Array.prototype.slice.call을 통해 표준 배열로 변환한 후 배열 메소드인 unshift를 사용하면 되는데, 이렇게:

function log(){
 var args = Array.prototype.slice.call(arguments);
 args.unshift('(app)');
 console.log.apply(console, args);
};

바인딩

신청과 전화에 대해 이야기한 후 바인드에 대해 이야기해보겠습니다. 바인딩() 메서드는 적용 및 호출과 매우 유사하며 함수 본문에서 this의 포인터를 변경할 수도 있습니다.

MDN의 설명은 다음과 같습니다. 바인딩() 메서드는 바인딩 함수라고 하는 새 함수를 생성합니다. 이 바인딩 함수가 호출되면 바인딩 함수는 바인딩 시 바인딩() 메서드에 전달된 첫 번째 값을 기반으로 합니다. 매개변수는 이것이며, 실행 시 바인딩된 함수 자체의 매개변수와 결합된 메소드에 전달된 두 번째 이후의 매개변수는 원래 함수의 매개변수로 순서대로 사용되어 원래 함수를 호출합니다.

공통 싱글톤 모드에서는 보통 _this, that, self 등을 사용하여 context를 변경한 후에도 계속 참조할 수 있도록 저장합니다. 이렇게:

var foo = {
  bar : 1,
  eventBind: function(){
    var _this = this;
    $('.someClass').on('click',function(event) {
      /* Act on the event */
      console.log(_this.bar);   //1
    });
  }
}

由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $('.someClass').on('click',function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:

var foo = {
  bar : 1,
  eventBind: function(){
    $('.someClass').on('click',function(event) {
      /* Act on the event */
      console.log(this.bar);   //1
    }.bind(this));
  }
}

在上述代码里,bind() 创建了一个函数,当这个click事件绑定在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。因此,这里我们传入想要的上下文 this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向 foo 对象。再来一个简单的栗子:

var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
bar(); // undefined
var func = bar.bind(foo);
func(); // 3

这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。

有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:

var bar = function(){
  console.log(this.x);
}
var foo = {
  x:3
}
var sed = {
  x:4
}
var func = bar.bind(foo).bind(sed);
func(); //?
 
var fiv = {
  x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?

答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

   apply、call、bind比较

那么 apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个栗子:

var obj = {
  x: 81,
};
var foo = {
  getX: function() {
    return this.x;
  }
}
console.log(foo.getX.bind(obj)()); //81
console.log(foo.getX.call(obj));  //81
console.log(foo.getX.apply(obj));  //81

三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。

也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。

再总结一下:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;

bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

好了,本文关于开启Javascript中apply、call、bind的用法之旅模式的相关教程,到此给大家介绍完了,希望大家喜欢。

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