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

call和apply区别

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

举个栗子:

const obj1 = {
name: 'microzz',
getName: function() {
return this.name;
}
};
 
const obj2 = {
name: 'Zhaohui'
}
 
console.log(obj1.getName()); // "microzz"
console.log(obj1.getName.call(obj2)); // "Zhaohui"
console.log(obj1.getName.apply(obj2)); // "Zhaohui"

call和apply的用途

改变this指向

call和apply可以改变this的指向,这点我们从上面这个例子中可以看出。我们还可以举一个实际当中可以遇到的情况:

有的时候我们会觉得 document.getElementById这个方法太长了,我们会尝试用一个短函数来代替它,如同prototype.js等一些框架所做过的事情,下面用代码说明:

const getId = function(id) {
return document.getElementById(id);
}
 
getId('id');

在Chrome、Firefox、IE10中执行会发现抛出异常,这是因为很多引擎的 document.getElementById 的方法内部需要用到this,这个this本来被期望指向document,但直接普通函数调用就指向了window。我们可以利用apply“修正” this

document.getElementById = (function(func) {
return function() {
return func.apply(document, arguments);
}
})(document.getElement);
 
const getId = document.getElementById;

Function.prototype.bind

在大部分高级浏览器已经实现了内置的Function.prototype.bind,用来指定函数内部的this指向,如果没有原生的Function.prototype.bind,我们也可以模拟一个,代码如下:

Function.prototype.bind = function(context) {
var self = this;
return function() {
return self.apply(context, arguments);
}
}
 
var obj = {
name: 'microzz'
};
 
var func = function() {
console.log(this.name); // microzz
}.bind(obj);
 
func();

这是一个简化版的,通常我们会实现得稍微复杂一点:

 
Function.prototype.bind = function() {
var self = this;
 
// 需要绑定的this上下文
var context = [].shift.call(arguments);
 
// 剩余的参数转成数组
var args = [].slice.call(arguments);
 
return function() {
return self.apply(context, [].concat.call(args, [].slice.call(arguments)));
}
}
 
var obj = {
name: 'microzz'
};
 
var func = function(a, b, c, d) {
console.log(this.name); // microzz
console.log([a, b, c, d]); // [1, 2, 3, 4]
}.bind(obj, 1, 2);
 
func(3, 4);

借用其他对象的方法

借用构造函数

借用方法的第一种场景是“借用构造函数”,可以实现类似继承的效果:

var A = function(name) {
this.name = name;
}
 
var B = function() {
A.apply(this, arguments);
}
 
B.prototype.getName = function() {
return this.name;
}
 
var b = new B('microzz');
console.log(b.getName()); // microzz

类数组

函数参数列表arguments是一个类数组对象,虽然它有下标,但是并不是真正的数组。为了能使用数组的一些方法,我们常常会借用Array.prototype对象上的方法。
比如想往arguments中添加新元素,通常会借用Array.prototype.push
想把arguments转成真正数组的时候,可以借用Array.prototype.slice或者也可以使用ES6的Array.from

About

JavaScript中的call和apply应用的更多相关文章

  1. Javascript中call函数和apply函数的使用

    Javascript 中call函数和apply的使用: Javascript中的call函数和apply函数是对执行上下文进行切换,是将一个函数从当前执行的上下文切换到另一个对象中执行,例如: so ...

  2. Javascript 中的 call 和 apply

    发表于 2012年02月1日 by 愚人码头   原文链接:http://www.css88.com/archives/4431 JavaScript 中通过call或者apply用来代替另一个对象调 ...

  3. javascript中call函数与apply

    javascript中的call方法使当前对象可以调用另一个对象的方法,即改变this的指向内容 var first_object = { num: 42 }; var second_object = ...

  4. javascript 中caller,callee,call,apply 的概念[转载]

    在提到上述的概念之前,首先想说说javascript中函数的隐含参数:arguments Arguments : 该对象代表正在执行的函数和调用它的函数的参数. [function.]argument ...

  5. 理解和运用javascript中的call及apply

    call是为了改变函数上下文context而存在的,换言之,就是改变函数内部this的指向.因为javascript存在[定义时上下文],[运行时上下文]及[上下文]是可以改变的.例如:var fun ...

  6. javascript 中的call和apply

    一.作用及应用场景 call和apply是Function的方法,他的第一个参数是this,第二个是Function的参数.call 和 apply 都是为了改变某个函数运行时的 context 即上 ...

  7. JavaScript中的call()、apply()与bind():

    关于call()与apply(): 在JavaScript中,每个函数都有call与apply(),这两个函数都是用来改变函数体内this的指向,并调用相关的参数. 看一个例子: 定义一个animal ...

  8. 理解JavaScript中的call和apply方法

    call方法 总的来说call()有这几种作用:1.可以借用另一个对象的方法.2.改变this的指向(重要).3.将arguments数组化.下面详细介绍这三种作用: 1.可以借用另一个对象的方法:当 ...

  9. JavaScript中的call、apply、bind方法的区别

    在JavaScript 中,this的指向是动态变化的,很可能在写程序的过程中,无意中破坏掉this的指向,所以我们需要一种可以把this的含义固定的技术,于是就有了call,apply 和bind这 ...

  10. 简单理解Javascript中的call 和 apply

    javascript中面向对像的能力是后来加进来的, 为了兼容性, 所以整出了很多奇特的东西, function Animal(){ this.name = "Animal"; t ...

随机推荐

  1. PIL图片合成旋转缩放

    用PIL实现图片的旋转,缩放,合成 我们需要知道合成位置的中心点坐标,用中心点坐标,不使用左顶点的坐标是由于缩放过程容易计算. 假设A是局部透明的图片,我们希望把B放在A的底部,仅从A的透明部分显示B ...

  2. 设置NGINX进程分配至多核CPU提升性能

    Nginx 配置文件 nginx.conf 首先需要找到 Nginx 的配置文件 nginx.conf 才能进行下面的操作,在LNMP一键安装包默认配置下,nginx.conf 存放在/usr/loc ...

  3. 设计模式--工厂模式 caffe_layer注册

    来源:http://www.cnblogs.com/zhouqiang/archive/2012/07/20/2601365.html 来源:http://blog.luoyetx.com/2016/ ...

  4. 服务器或普通PC裸机安装 ESXI6.5

    ESXI :安装包 http://pan.baidu.com/s/1c2gM0Xq (包含注册机和其他套件,驱动打包工具) ESXI 6.5 在服务器安装比较方便,一般intel 的网卡都没多大问题, ...

  5. python ConfigParser 配置读写

    我们写程序的时候一般都会写程序包的时候,很少硬编码写在一起,这有个很好的配置文件包. 参考 ConfigParser  和   ConfigParser 的使用 一.ConfigParser 简介 C ...

  6. php简明学习教程

    1.变量 <?php //变量声明(php变量无需单独创建,变量会在第一次赋值时创建) $a = 1; //弱类型(php变量会根据其值自动转换为相应的数据类型) $a = "a&qu ...

  7. 洛谷——P3376 【模板】网络最大流

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...

  8. Eclipse酷炫项目、最新趋势介绍

    作为Eclipse基金组织的执行董事,我需要经常审阅每一个新提交的Eclipse项目协议书.作为Eclipse的一分子,我很乐意与加入我们团队的新开发人员互动.这也是我工作中的乐趣之一.2013年,我 ...

  9. BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

    http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...

  10. windows下eclipse搭建android_ndk开发环境

    安装cygwin: 由于NDK编译代码时必须要用到make和gcc,所以你必须先搭建一个linux环境, cygwin是一个在windows平台上运行的unix模拟环境,它对于学习unix/linux ...