深入理解JavaScript中的call、apply、bind方法的区别


Posted in Javascript onMay 30, 2016

在JavaScript 中,this的指向是动态变化的,很可能在写程序的过程中,无意中破坏掉this的指向,所以我们需要一种可以把this的含义固定的技术,于是就有了call,apply 和bind这三个方法,来改变函数体内部 this 的指向,因为函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念

apply、call

apply:应用某一对象的一个方法,用另一个对象替换当前对象

call:调用一个对象的一个方法,以另一个对象替换当前对象

function person() {}
 
person.prototype = {
 attr: {age:18,sex:'girl'},
 say: function() {
  console.log("My age is " + this.attr.age);
  console.log("I am a " + this.attr.sex);
 }
}
 
var Marry = new person();
Marry.say();
 
// My age is 18
// I am a girl

改变指向

function person() {}
 
person.prototype = {
 attr: {age:18,sex:'girl'},
 say: function() {
  console.log("My age is " + this.attr.age);
  console.log("I am a " + this.attr.sex);
 }
}
 
xiaoming ={ attr : {age:20,sex:'boy'} };
 
var Marry = new person();
Marry.say();
 
Marry.say.call(xiaoming);
// My age is 18
// I am a girl
// My age is 20
// I am a boy

共同之处

都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

不同之处

1、apply:最多只能有两个参数——新this对象和一个数组 argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里面。如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj,并且无法被传递任何参数。

fun.call(thisArg[, arg1[, arg2[, ...]]])
 
function f(x,y){
 console.log(x+y);
}
f.call(null, 1, 1)
//return 2

2、call:则是直接的参数列表,主要用在js对象各方法互相调用的时候,使当前this实例指针保持一致,或在特殊情况下需要改变this指针。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

fun.apply(thisArg, [argsArray])
 
function f(x,y){
 console.log(x+y);
}
f.call(null, [1,1])
//return 2

apply和call功能一样,只是传入的参数列表形式不同,其中 thisArg 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。

如果某个函数的参数数量是不固定的,当你的参数是明确知道数量时用 call ,而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数,我们看一下一些用法

代码一

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

代码二

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

代码三

log(12 , "foo" , {name:"Joe"} , -2458);
function log(){
 var args = Array.prototype.slice.call(arguments);
 args.unshift('(app)');
 console.log.apply(console, args);
};
// (app) 12 foo Object {name: "Joe"} -2458

bind

fun.bind(thisArg[, arg1[, arg2[, ...]]])

与上面不同的是,bind会返回一个改变this指向的新函数 ,注意这里强调的是新函数,其与之前的使用的不是同一块内存地址,所以当你需要重复使用这个函数的时候,你就不得不把其保存到一个变量,方便下次调用。上面的两个函数都是返回的执行结果,即调用即执

行,此外,另外需要注意的地方是,bind函数中的首个参数,会自动成为返回新函数中参数的默认值,那么正式调用的时候,只需要给出除首个参数外,剩余参数即可。

function f(x,y){
 console.log(x+y);
}
f.call(null, [1,1])
var new_f = f.bind(null,1,1)
//return new function
new_f(1)
//return 2

需要说明的是,上面所有示例代码中的thisArg参数均用null来代替了,在未给出指定thisArg对象的情况下,null与undefined下this指向是全局对象,即js代码执行环境

apply、call、bind比较

var obj = {bar: 'Oops , this is a bad idea' };
 
var foo = {
  get: function() {
    return this.bar;
  }
}
 
var bind = foo.get.bind(obj) ,call = foo.get.call(obj) ,apply = foo.get.apply(obj);
 
console.log(bind(),call,apply);
console.log(bind,call,apply); 
 
console.log(typeof bind,typeof call,typeof apply);
console.log(typeof bind(),typeof call,typeof apply);

深入理解JavaScript中的call、apply、bind方法的区别

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

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

以上这篇深入理解JavaScript中的call、apply、bind方法的区别就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Node.js模拟浏览器文件上传示例
Mar 26 Javascript
一个JavaScript处理textarea中的字符成每一行实例
Sep 22 Javascript
基于jQuery+PHP+Mysql实现在线拍照和在线浏览照片
Sep 06 Javascript
js格式化输入框内金额、银行卡号
Feb 01 Javascript
BootStrap轮播HTML代码(推荐)
Dec 10 Javascript
DropDownList控件绑定数据源的三种方法
Dec 24 Javascript
基于jQuery选择器之表单对象属性筛选选择器的实例
Sep 19 jQuery
JavaScript实现的开关灯泡点击切换特效示例
Jul 08 Javascript
JavaScript 监听组合按键思路及代码实现
Jul 28 Javascript
Vue ElementUI实现:限制输入框只能输入正整数的问题
Jul 31 Javascript
Vue+element-ui添加自定义右键菜单的方法示例
Dec 08 Vue.js
关于React Native使用axios进行网络请求的方法
Aug 02 Javascript
全面解析Bootstrap中transition、affix的使用方法
May 30 #Javascript
全面解析Bootstrap中form、navbar的使用方法
May 30 #Javascript
js实现页面a向页面b传参的方法
May 29 #Javascript
浅析jQuery中使用$所引发的问题
May 29 #Javascript
基于jQuery实现仿百度首页选项卡切换效果
May 29 #Javascript
jQuery实现图像旋转动画效果
May 29 #Javascript
jQuery中使用animate自定义动画的方法
May 29 #Javascript
You might like
PHP执行zip与rar解压缩方法实现代码
2010/12/05 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
php微信扫码支付 php公众号支付
2019/03/24 PHP
Laravel监听数据库访问,打印SQL的例子
2019/10/24 PHP
基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作
2020/08/17 PHP
Javascript学习笔记 delete运算符
2011/09/13 Javascript
jquery ajax同步异步的执行最终解决方案
2013/04/26 Javascript
JS Replace()的高级使用方法介绍
2013/06/29 Javascript
用正则表达式替换图片地址img标签
2013/11/22 Javascript
javascript实现类似百度分享功能的方法
2015/07/27 Javascript
jquery中键盘事件小结
2016/02/24 Javascript
js实现ctrl+v粘贴上传图片(兼容chrome、firefox、ie11)
2016/03/09 Javascript
深入浅析Bootstrap列表组组件
2016/05/03 Javascript
12个非常实用的JavaScript小技巧【推荐】
2016/05/18 Javascript
JS实现的按钮点击颜色切换功能示例
2017/10/19 Javascript
详解如何webpack使用DllPlugin
2018/09/30 Javascript
利用不到200行代码写一款属于你自己的js类库
2019/07/08 Javascript
微信小程序swiper左右扩展各显示一半代码实例
2019/12/05 Javascript
vue element table中自定义一些input的验证操作
2020/07/18 Javascript
js实现查询商品案例
2020/07/22 Javascript
django利用request id便于定位及给日志加上request_id
2018/08/26 Python
使用python3调用wxpy模块监控linux日志并定时发送消息给群组或好友
2019/06/05 Python
python使用socket 先读取长度,在读取报文内容示例
2019/09/26 Python
Numpy中对向量、矩阵的使用详解
2019/10/29 Python
python 的numpy库中的mean()函数用法介绍
2020/03/03 Python
keras实现调用自己训练的模型,并去掉全连接层
2020/06/09 Python
Python实现邮件发送的详细设置方法(遇到问题)
2021/01/18 Python
法国体育用品商店:GO Sport
2019/10/23 全球购物
C语言笔试集
2012/07/24 面试题
音乐节策划方案
2014/06/09 职场文书
二年级语文下册复习计划
2015/01/19 职场文书
2015年班主任个人工作总结
2015/03/31 职场文书
医药公司采购员岗位职责
2015/04/03 职场文书
行政申诉状范文
2015/05/20 职场文书
靠谱准确的求职信
2019/04/02 职场文书
pytorch fine-tune 预训练的模型操作
2021/06/03 Python