Apply,Call,bind对比
apply、call
call和apply都是为了改变上下文背景存在的,即改变函数内部指向
javascript一大特点是函数存在定义时的上下文,运行时的上下文和上下文可改变的概念
apply、call可改变this的指向,即this可以在一个对象没有
某个方法但其他的对象有着一想要方法时使用
apple.say.call(banana);
apple.say.apply(banana);
//两者都可获得banner中的方法
两者区别
两者作用一样但接受参数方法不同,call放入的参数是按照顺序传入,apply则将参数放入数组中
实例
apply可用作两个数组追加
Array.prototype.push.apply(array1,array2)
调用Math函数中的max方法
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
验证数组(前提是toString()方法没有被重写过)
functionisArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
类(伪)数组使用数组方法
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。
例题
定义一个 log 方法,让它可以代理 console.log 方法,常见的解决方法是:
function log(msg) {
console.log(msg);
}
log(1); //1
log(1,2); //1
上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:
function log(){
console.log.apply(console, arguments);
};
log(1); //1
log(1,2); //1 2
接下来的要求是给每一个 log 消息添加一个"(app)"的前辍,比如:
log("hello world"); //(app)hello world
该怎么做比较优雅呢?这个时候需要想到arguments参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift,像这样:
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
bind
在讨论bind()方法之前我们先来看一道题目:
var altwrite = document.write;
altwrite("hello");
结果:Uncaught TypeError: Illegal invocation
altwrite()函数改变this的指向global或window对象,导致执行时提示非法调用异常,正确的方案就是使用bind()方法:
altwrite.bind(document)("hello")
当然也可以使用call()方法:
altwrite.call(document, "hello")
绑定函数
bind()
最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象。如果不做特殊处理,一般会丢失原来的对象。使用bind()方法能够很漂亮的解决这个问题:
this.num = 9;
var mymodule = {
num: 81,
getNum: function() {
console.log(this.num);
}
};
mymodule.getNum(); // 81
var getNum = mymodule.getNum;
getNum(); // 9, 因为在这个例子中,"this"指向全局对象
var boundGetNum = getNum.bind(mymodule);
boundGetNum(); // 81
bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
直接来看看具体如何使用,在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它。 像这样:
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() 时的全局作用域。
Apply,Call,bind对比的更多相关文章
- javascript中call()、apply()、bind()的用法终于理解
其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows( ...
- JavaScirpt的this指向 apply().call(),bind()个人笔记
写在前头: 本站内容为个人学习记录,纯属个人观点,不喜勿喷,欢迎指正! 笔记记录缘由:JavaScript的流行趋势已经势不可挡,衍生的AngularJs,Node.js,BootStrmp中小企业的 ...
- JavaScript的动态特性(通过eval,call,apply和bind来体现)
JavaScript的动态特性(通过eval,call,apply和bind来体现) JavaScript是一种基于面向对象的.函数式的.动态的编程语言.现在发展到已经可以用在浏览器和服务器端了. 这 ...
- (转)javascript中call()、apply()、bind()的用法
其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows( ...
- <JavaScript> call()、apply()、bind() 的用法
其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例 1 obj.objAge; obj.myFun() // 小张年龄 undefined 例 2 shows() ...
- JS中call()和apply()以及bind()的区别
一.方法定义: apply:调用一个对象的一个方法,用另一个对象替换当前对象.例如:B.apply(A, arguments);即A对象应用B对象的方法. call:调用一个对象的一个方法,用另一个对 ...
- 对于call,apply,bind 的理解
JavaScript 中 call().apply().bind() 的用法 之前对与JavaScript中的call,apply,bind这几个方法一直理解的很模糊,今天总结一下. 例1 var n ...
- call、apply、bind 的用法
例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows() //盲僧 比较一下这两者this 的差别,第一个打印里面的this 指向obj,第 ...
- JS中call()、apply()、bind()的用法
其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows( ...
- 前端面试手写代码——call、apply、bind
1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...
随机推荐
- 【JZOJ4929】【NOIP2017提高组模拟12.18】B
题目描述 在两个n*m的网格上染色,每个网格中被染色的格子必须是一个四联通块(没有任何格子被染色也可以),四联通块是指所有染了色的格子可以通过网格的边联通,现在给出哪些格子在两个网格上都被染色了,保证 ...
- 【JZOJ4745】【NOIP2016提高A组模拟9.3】看电影
题目描述 听说NOIP2016大家都考得不错,于是CCF奖励省常中了 K 张变形金刚5的电影票奖励OI队的同学去看电影.可是省常中OI队的同学们共有 N(N >= K)人.于是机智的你想到了一个 ...
- oracle-600错误
event='10841 trace name context forever' 可以屏蔽这个ORA-00600错误. SQL> show parameter event NAME TYPE V ...
- Kubernetes1.4即将发布
(一)发布历史 Kubernetes 1.0 - 2015年7月发布 Kubernetes 1.1 - 2015年11月发布 Kubernetes 1.2 - 2016年3月发布 Kubernetes ...
- 猜年龄v2.0
''' 用户登录,只有三次机会 给定年龄,用户可以猜三次年龄 年龄猜对,让用户选择两次奖励,输入无效字符,让其选择要不要礼物 用户选择两次奖励后可以退出,选择第一次后提示还有一次 ''' #基本信息定 ...
- @RequestBody对象为空,异常Required request body is missing错误解决
1.异常 org.springframework.http.converter.HttpMessageNotReadableException: Required request body is mi ...
- Java练习 SDUT-1211_英文金曲大赛
英文金曲大赛 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 我们在"渊子数"的题目中已经了解了渊子 ...
- Laravel Class config does not exist in
修改了Laravel里面的.env文件之后报这个错误,找半天,找到罪魁祸首了,错误信息: Fatal error: Uncaught ReflectionException: Class config ...
- 洛谷P2504 [HAOI2006]聪明的猴子
#include<bits/stdc++.h> using namespace std; ; ; int n,m,k,ans; double Max; int monkey[maxn]; ...
- IP应用加速技术详解:如何提升动静混合站点的访问速率?
全站加速(DCDN)-IPA是阿里云自主研发四层加速产品,它基于TCP/UDP的私有协议提供加速服务,包括解决跨运营商网络不稳定.单线源站.突发流量.网络拥塞等诸多因素导致的延迟高.服务不稳定的问题, ...