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() 时的全局作用域。

最新文章

  1. android 自定义动画
  2. 获取View的截图-将View转换为Bitmap对象
  3. 深入理解javascript中的焦点管理
  4. iPhone被盗后续更新一:怎么找老机
  5. Net分布式系统之三:Keepalived+LVS+Nginx负载均衡之高可用
  6. hibernate的主键生成策略
  7. 【python】分片copy和等号的区别
  8. Java基础知识强化之集合框架笔记58:Map集合之LinkedHashMap类的概述
  9. jquery为多个元素添加事件
  10. Google Python编程规范
  11. 前端工程师必须要知道的HTTP部分
  12. C博客作业01--分支,顺序结构
  13. Docker Registry私有仓库搭建
  14. GDB dump mem example和命令
  15. 转-OWASP CSRFGuard使用细节
  16. oracle group by placement可能导致错误结果的bug
  17. collocation
  18. Innodb中自增长值的列
  19. error: pathspec 'master' did not match any file(s) known to git.
  20. apk反编译看包名什么的

热门文章

  1. 【JZOJ3886】【长郡NOIP2014模拟10.22】道路维护
  2. ELK学习之jdk和jre的区别
  3. springboot security 安全
  4. 微服务开源生态报告 No.4
  5. git 密钥
  6. MUI - 实现关闭除指定页面外的其他所有页面的功能
  7. 《DL/T 976-2017 带电作业用工具、装置和设备预防性试验规程》中的样品名称及试验项目
  8. CPU核数和线程数查找
  9. UVa 10285【搜索】
  10. Python 变量赋值