前言

回想起之前的一些面试,几乎每次都会问到一个js中关于call、apply、bind的问题,比如…

  1. 怎么利用call、apply来求一个数组中最大或者最小值
  2. 如何利用call、apply来做继承
  3. apply、call、bind的区别和主要应用场景

虽然网上有很多关于这方面的博客和文章,但还是决定写一篇自己对这方面知识的理解。

作用

首先问个问题,这三个函数的存在意义是什么?答案是改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向。有了这个认识,接下来我们来看一下,怎么使用这三个函数。

举个栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name){
this.name = name;
}
 
Person.prototype = {
constructor: Person,
showName: function(){
console.log(this.name);
}
}
 
var person = new Person('qianlong');
person.showName();

上面的代码中person调用showName方法后会在浏览器的控制台输出qianlong

接下来

1
2
3
var animal = {
name: 'cat'
}

上面代码中有一个对象字面量,他没有所谓的showName方法,但是我还是想用?怎么办?(坑爹了,这好像在让巧媳妇去做无米之炊),不过没关系,call、apply、bind可以帮我们干这件事。

1
2
3
4
5
6
// 1 call
person.showName.call(animal);
// 2 apply
person.showName.apply(animal);
// 3 bind
person.showName.bind(animal)();

啦啦啦,有木有很神奇,控制台输出了三次cat

我们拿别人的showName方法,并动态改变其上下文帮自己输出了信息,说到底就是实现了复用

区别

上面看起来三个函数的作用差不多,干的事几乎是一样的,那为什么要存在3个家伙呢,留一个不就可以。所以其实他们干的事从本质上讲都是一样的动态的改变this上下文,但是多少还是有一些差别的..

call、apply与bind的差别

call和apply改变了函数的this上下文后便执行该函数,而bind则是返回改变了上下文后的一个函数。

call、apply的区别

他们俩之间的差别在于参数的区别,call和aplly的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。

1
2
3
 
fn.call(obj, arg1, arg2, arg3...);
fn.apply(obj, [arg1, arg2, arg3...]);

应用

知道了怎么使用和他们之间的区别,接下来我们来了解一下通过call、apply、bind的常见应用场景。

  • 求数组中的最大和最小值
1
2
3
4
5
6
7
var arr = [34,5,3,6,54,6,-67,5,7,6,-8,687];
 
Math.max.apply(Math, arr);
Math.max.call(Math, 34,5,3,6,54,6,-67,5,7,6,-8,687);
 
Math.min.apply(Math, arr);
Math.min.call(Math, 34,5,3,6,54,6,-67,5,7,6,-8,687);
  • 将伪数组转化为数组

js中的伪数组(例如通过document.getElementsByTagName获取的元素)具有length属性,并且可以通过0、1、2…下标来访问其中的元素,但是没有Array中的push、pop等方法。我们可以利用call、apply来将其转化为真正的数组这样便可以方便地使用数组方法了。

1
2
3
4
5
6
var arrayLike = {
0: 'qianlong',
1: 'ziqi',
2: 'qianduan',
length: 3
}

上面就是一个普通的对象字面量,怎么把它变成一个数组呢?最简单的方法就是

1
var arr = Array.prototype.slice.call(arrayLike);

上面arr便是一个包含arrayLike元素的真正的数组啦( 注意数据结构必须是以数字为下标而且一定要有length属性 )

  • 数组追加

在js中要往数组中添加元素,可以直接用push方法,

1
2
3
4
5
6
7
var arr1 = [1,2,3];
var arr2 = [4,5,6];
 
[].push.apply(arr1, arr2);
 
// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]

判断变量类型

对于对象型的数据类型,我们可以借助call来得知他的具体类型,例如数组

1
2
3
4
5
6
function isArray(obj){
return Object.prototype.toString.call(obj) == '[object Array]';
}
 
isArray([]) // true
isArray('qianlong') // false

2016.12.31日更新,有些读者对文章提了一些意见,觉得还是蛮好的,现在就其中部分进行更新。

利用call和apply做继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Person = function (name, age) {
this.name = name;
this.age = age;
};
 
var Girl = function (name) {
Person.call(this, name);
};
 
var Boy = function (name, age) {
Person.apply(this, arguments);
}
 
var g1 = new Girl ('qing');
var b1 = new Boy('qianlong', 100);
 
 

js中call、apply、bind那些事的更多相关文章

  1. js 中call,apply,bind的区别

    call.apply.bind方法的共同点与区别: apply.call.bind 三者都是用来改变函数的this对象的指向: apply.call.bind 三者都可以利用后续参数传参: bind ...

  2. JS中call,apply,bind方法的总结

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...

  3. JS中call,apply,bind的区别

    1.关于this对象的指向,请看如下代码 var name = 'jack'; var age = 18; var obj = { name:'mary', objAge:this.age, myFu ...

  4. 深入理解js中的apply、call、bind

    概述 js中的apply,call都是为了改变某个函数运行时的上下文环境而存在的,即改变函数内部的this指向. apply() apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作 ...

  5. JS 的 call apply bind 方法

    js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[,   [,.argN]]]] ...

  6. javascript中call,apply,bind的用法对比分析

    这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们.   关于call,apply,bind这三个函数的用法,是学习java ...

  7. JavaScript中call,apply,bind方法的总结。

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...

  8. js: this,call,apply,bind 总结

    对js中的一些基本的很重要的概念做一些总结,对进一步学习js很重. 一.this JavaScript 中的 this 总是指向一个对象,而具体指向那个对象是在运行时基于函数的执行环境动态绑定的,而非 ...

  9. JavaScript中call,apply,bind方法的总结

    原文链接:http://www.cnblogs.com/pssp/p/5215621.html why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之 ...

  10. JavaScript中call,apply,bind方法的区别

    call,apply,bind方法一般用来指定this的环境. var a = { user:"hahaha", fn:function(){ console.log(this.u ...

随机推荐

  1. 在DataTable数据类型最后增加一列,列名为“Column”,内容都为“AAA”

    DataTable dt = new DataTable(); dt.Columns.Add("Column", typeof(string)); foreach (DataRow ...

  2. Java中泛型数组的使用

    package com.srie.testjava; import java.util.ArrayList; import java.util.List; public class TestClass ...

  3. Ubuntu14.04 安装Oracle JDK

    在Ubuntu 14.04 中安装 Oracle JDK6,7 或 8. 准备:添加add-apt-repository工具 #apt-get install python-software-prop ...

  4. MyEclipse+Tomcat开发Web项目时修改内容不能及时显示问题解决方法

    问题描述:MyEclipse+Tomcat开发Web项目时,修改的内容不能从浏览器即时显示 原因:缓存问题 解决方法:开启Tomcat的Debug模式 点击如下图红色标记中的图标(Restart th ...

  5. ubuntu下编译java程序

    ubuntu下编译java程序 首先需要安装jdk,并配置好相应环境变量 下面以简单的HelloWorld为例 文件名为HelloWorld.java java代码: public class Hel ...

  6. 说说 bash 的 if 语句

    说说 bash 的 if 语句 在开始先给大家列出几个术语,不做解释,不懂的可以参考其它资料. 术语和符号: 退出状态码 $? [...] (中括号,方括号) [[...]] (双中括号,双方括号) ...

  7. 详解Google Chrome浏览器(操作篇)(一)

    开篇概述 在上篇博客中详解Google Chrome浏览器(理论篇)一文中,主要讲解了Chrome 搜索引擎使用.Chrome安装和基本操作.Chrome 基本架构.多线程等原理性问题,这篇将重点讲解 ...

  8. 转: 尽己力,无愧于心 FastReport.Net 常用功能总汇

    FastReport.Net 常用功能总汇   一.常用控件 文本框:输入文字或表达式 表格:设置表格的行列数,输入数字或表达式 子报表:放置子报表后,系统会自动增加一个页面,你可以在此页面上设计需要 ...

  9. 浅谈Activiti Modeler 的扩展

    为什么要扩展         最近项目打算用activiti工作流中activiti modeler来做模块的可视化订阅,但是原生的activiti任务节点,有一些不符合业务需要,比如 配置项多,属性 ...

  10. 一个Python小白5个小时爬虫经历

    前言 最近业余在做一个基于.NET Core的搜索项目,奈何基层代码写好了,没有看起来很华丽的数据供测试.很巧的也是博客搜索,于是乎想到了博客园.C#也能做做页面数据抓取的,不过在博客园看到的大部分都 ...