背景

前两天在做小程序的需求的时候用到bind的时候才想起自己对这三的东西的了解比较浅薄,这个时候用的时候就有点怕。时候还是要好好学习下,理解下怎么玩。

正文

先说call 和 apply吧:
ECMAScript3给Function的原型定义了两个方法,他们是Function.prototype.call 和 Function.prototype.apply. 在实际开发中,特别是在一些函数式风格的代码编写中,call和apply方法尤为有用。

1、call和apply区别

其实他们的作用是一样的,只是传递的参数不一样而已。
apply: 接受2个参数,第一个参数指定了函数体内this对象的指向,第二个参数为数组或者一个类数组。apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。
举个栗子:

let obj1 = {
name: "copyes",
getName: function(){
return this.name;
}
}
let obj2 = {
name: 'Fanchao'
} console.log(obj1.getName()); // "copyes"
console.log(obj1.getName.call(obj2)); // "Fanchao"
console.log(obj1.getName.apply(obj2)); // "Fanchao"
function showArgs(a, b, c){
console.log(a,b,c);
} showArgs.call(this, 3,4,5);
showArgs.apply(this, [5,6,7]);

2、常见的call 和 apply 用法

  • 数组之间追加

let arr1 = [12, 'foo', {name: 'fanchao'}, -1024];
let arr2 = ['copyes', '22', 1024]; Array.prototype.push.apply(arr1, arr2);
console.log(arr1);
// [ 12, 'foo', { name: 'fanchao' }, -1024, 'copyes', '22', 1024 ]
  • 获取数组中的最大值和最小值

let numbers = [5,665,32,773,77,3,996];
let maxNum = Math.max.apply(Math, numbers);
let maxNum2 = Math.min.call(Math, 5,665,32,773,77,3,996); console.log(maxNum);
console.log(maxNum2);
  • 验证是否是数组(前提是toString()方法没有被重写过)

function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]';
} console.log(isArray(1));
console.log(isArray([1,2]));
  • 类(伪)数组使用数组方法

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

3、通过一个面试题去深入理解下apply 和 call

定义一个 log 方法,让它可以代理 console.log 方法:

// 常规做法
function log(msg){
console.log(msg);
}
log(12);
log(1,2)

上面能够基本解决打印输出问题,但是下面多参数的时候就gg了。换个更好的方式吧。

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

接下来是要在每一条打印信息前面都要加上一个特定字符串'fanchao`s'又怎么说呢?

function log(){

    let args = Array.prototype.slice.call(arguments);

    args.unshift('(fanchao`s)');

    console.log.apply(console, args);
}
log(12);
log(1,2)

4、说完了call和apply,接下来说说bind

bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
看个栗子:

var func = function(){
console.log(this.x);
console.log(arguments);
} func(); // undefined, {}
var obj = {
x: 2
}
var bar = func.bind(obj,1); bar(); // 2 , {'0':1}

一个有意思的事:

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

在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

5、这三个方法的异同点是什么呢?

还是先看个栗子:

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

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

总结

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind是返回对应函数,便于稍后调用;apply、call则是立即调用 。

前端基础:call,apply,bind的的理解的更多相关文章

  1. 学习前端的菜鸡对JS的call,apply,bind的通俗易懂理解

       call,apply,bind 在JavaScript中,call.apply和bind是Function对象自带的三个方法,都是为了改变函数体内部 this 的指向.            a ...

  2. js call apply bind简单的理解

    相同点:JS中call与apply方法可以改变某个函数执行的上下文环境,也就是可以改变函数内this的指向.区别:call与apply方法的参数中,第一个参数都是指定的上下文环境或者指定的对象,而ca ...

  3. 理解 JavaScript call()/apply()/bind()

    理解 JavaScript this 文章中已经比较全面的分析了 this 在 JavaScript 中的指向问题,用一句话来总结就是:this 的指向一定是在执行时决定的,指向被调用函数的对象.当然 ...

  4. 前端面试 js 你有多了解call,apply,bind?

    函数原型链中的 apply,call 和 bind 方法是 JavaScript 中相当重要的概念,与 this 关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础 ...

  5. call,apply,bind的理解

    2020-03-19 call,apply,bind的理解 先说区别call, apply基本上没什么不一样,唯一不一样的地方是传参方式不同 但是bind和call,apply有区别.bind是重新绑 ...

  6. 前端JS面试题汇总 Part 3 (宿主对象与原生对象/函数调用方式/call与apply/bind/document.write)

    原文:https://github.com/yangshun/front-end-interview-handbook/blob/master/questions/javascript-questio ...

  7. 前端基础面试题(JS部分)

    1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined.Null.Boolean.Number.String 值类型:数值.布尔值.null.und ...

  8. 前端基础进阶(五):全方位解读this

    https://segmentfault.com/a/1190000012646488  https://yangbo5207.github.io/wutongluo/ 说明:此处只是记录阅读前端基础 ...

  9. BAT 前端开发面经 —— 吐血总结 前端相关片段整理——持续更新 前端基础精简总结 Web Storage You don't know js

    BAT 前端开发面经 —— 吐血总结   目录 1. Tencent 2. 阿里 3. 百度 更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘, ...

随机推荐

  1. STM32 -- 故障记录

    1.串口2无法发送数据 1)串口2和串口1使用的时钟总线不同: usart1:RCC_APBPeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); usart2:R ...

  2. java流类、、、理解不够,流太多不知怎么用好?

    总结:输入流.输出流..子类多.需要加强: package com.da; import java.io.*; public class rtr { public static void main(S ...

  3. 数据校验(2)--demo1---bai

    input_score.jsp <%@ page language="java" import="java.util.*" pageEncoding=&q ...

  4. asp.net mysql 链接类

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Text;u ...

  5. LNMP 1.6 常见的502问题解决

    在nginx上跑discuz,先修改配置文件 cd /usr/local/nginx/conf/vhosts/ vim test.conf server { listen ; server_name ...

  6. Javascript面向对象(二):构造函数的继承

    这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个" ...

  7. lombok与spring的恩怨

    下面是lombok按照 Java Bean 的规范生成的 下面是spring mvc里jackson 需要的 xXxx问题还是顺势而为吧

  8. C程序设计语言(K&R) 笔记1

    当作复习... (1)将华氏度 换算成 摄氏度,公式: ℃=(5/9)(̧°F-32) #include <stdio.h> int transformTemprature(int F){ ...

  9. Servlet开发中注意的细节问题

    客户端访问服务器的时候是通过URL访问的,所以我们要想用浏览器访问我们的Servlet的时候,我们就需要将我们的Servlet映射到一个URL上(通过我们的web.xml文件中的<servler ...

  10. sys模块 进度条百分比

    用于提供对Python解释器相关的操作: sys.argv           命令行参数List,第一个元素是程序本身路径 sys.exit(n)        退出程序,正常退出时exit(0) ...