JS中call、apply、bind使用指南,带部分原理。
为什么需要这些?主要是因为this,来看看this干的好事。
box.onclick = function(){
function fn(){
alert(this);
}
fn();
};
我们原本以为这里面的this指向的是box,然而却是Window。一般我们这样解决:
box.onclick = function(){
var _this = this;
function fn(){
alert(_this);
}
fn();
};
将this保存下来。
还有一些情况,有时我们想让伪数组也能够调用数组的一些方法,这时call、apply、bind就派上用场了。
我们先来解决第一个问题修复this指向。
box.onclick = function(){
function fn(){
alert(this);
}
fn();
};
改成如下:
box.onclick = function(){
function fn(){
console.log(this);
}
fn.call(this);
};
很神奇吧,call的作用就是改变this的指向的,第一个传的是一个对象,就是你要借用的那个对象。
fn.call(this);
这里的意思是让this去调用fn这个函数,这里的this是box,这个没有意见吧?如果这个你不清楚,很可能你是javscript的新朋友。box调用fn,这句话非常重要,我们知道this它始终指向一个对象,刚好box就是一个对象。那么fn里面的this就是box。
box.onclick = function(){
function fn(){
console.log(this);
}
fn.call(this);
};
这句话在某些情况下是可以简写的,比如:
box.onclick = function(){
var fn = function(){
console.log(this); //box
}.call(this);
};
或者这样:
box.onclick = function(){
(function(){
console.log(this);
}.call(this)); //box
};
又或者这样:
var objName = {name:'JS2016'};
var obj = {
name:'0 _ 0',
sayHello:function(){
console.log(this.name);
}.bind(objName)
};
obj.sayHello();//JS2016
call和apply、bind但是用来改变this的指向的,但也有一些小小的差别。下面我们来看看它们的差别在哪。
function fn(a,b,c,d){
console.log(a,b,c,d);
}//call
fn.call(null,1,2,3);//apply
fn.apply(null,[1,2,3]);//bind
var f = fn.bind(null,1,2,3);
f(4);
结果如下:
1 2 3 undefined
1 2 3 undefined
1 2 3 4
前面说过第一个参数传的是一个你要借用的对象,但这么我们不需要,所有就传了一个null,当然你也可以传其他的,反正在这里没有用到,除了第一个参数后面的参数将作为实际参数传入到函数中。
call就是挨个传值,apply传一个数组,bind也是挨个传值,但和call和apply还有多少不同,使用call和apply会直接执行这个函数,而bind并不会而是将绑定好的this重新返回一个新函数,什么时候调用由你自己决定。
var objName = {name:'JS2016'};
var obj = {
name:'0 _ 0',
sayHello:function(){
console.log(this.name);
}.bind(objName)
};
obj.sayHello();//JS2016
这里也就是为什么我要用bind的原因,如果用call的话就会报错了。自己想想这个sayHello在obj都已经执行完了,就根本没有sayHello这个函数了。
这几个方法使用的好的话可以帮你解决不少问题比如:
正常情况下Math.max只能这样用
Math.max(10,6)
但如果你想传一个数组的话你可以用apply
var arr = [1,2,30,4,5];
console.log(Math.max.apply(null,arr));
又或者你想让伪数组调用数组的方法
function fn(){
[].push.call(arguments,3);
console.log(arguments); //[1, 2, 3]
}
fn(1,2);
再者:
var arr = ['aaabc'];
console.log(''.indexOf.call(arr,'b')); //3
牛逼不,简直偷梁换柱,当然还有很多可以利用的,自己尽情花辉去吧。
简单说一下这种偷梁换柱的原理吧,实际上浏览器内部根本就不在乎你是谁,它只关心你传给我的是不是我能够运行的,如下:
正常情况
var str = 'aaabc';
console.log(str.indexOf('b'));
而这种情况其实做的事情和上面一模一样,看我来拆解。
var arr = ['aaabc'];
''.indexOf.call(arr);
这句话就是说让arr调用字符串的indexOf方法,前面说过了浏览器内部不在乎你是谁,所以谁都可以来调用,但不是100%成功,具体看如下。
''.indexOf.call(arr,'b')
这里的arr就是['aaabc'],内部很可能拆成了'aaabc',因此就成了下面的这段代码。
'aaabc'.indexOf('b');
这就是它们的秘密。
这里得说一下bind在某些浏览器下不兼容。我们来模拟一个玩玩。
Function.prototype.$bind = function(obj){
//保存当前this
var _this = this;
//截取除了第一个以外的所有实际参数
var a = [].slice.call(arguments,1);
//返回一个新函数
return function(){
//让当前那个调用的函数的this指向obj,并且把实参传给它,这里用了concat是因为,我们可能在绑定以后还传递参数,所以才把他们合并起来。如f(4)这个是在绑定以后传的参数,a这个argument是绑定时的。
_this.apply(obj,a.concat([].slice.call(arguments)));
};
};function fn(a,b,c,d){
console.log(a,b,c,d);
}var f = fn.$bind(null,1,2,3);
f(4);
这个方法和实际上的bind还是差别很大的,如
var arr = ['JSS'];
var index = ''.indexOf.$bind(arr,'S');
console.log(index())------------------
function fff(){
[].push.$bind(arguments,1);
console.log(arguments);
}fff();
这些都没法使用,因为技术有限就没办法带大家封装一个完美的bind了,如果有需要网上搜索一下吧。
结束了啊。
JS中call、apply、bind使用指南,带部分原理。的更多相关文章
- js 中call,apply,bind的区别
call.apply.bind方法的共同点与区别: apply.call.bind 三者都是用来改变函数的this对象的指向: apply.call.bind 三者都可以利用后续参数传参: bind ...
- JS中call,apply,bind方法的总结
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...
- JS中call,apply,bind的区别
1.关于this对象的指向,请看如下代码 var name = 'jack'; var age = 18; var obj = { name:'mary', objAge:this.age, myFu ...
- 深入理解js中的apply、call、bind
概述 js中的apply,call都是为了改变某个函数运行时的上下文环境而存在的,即改变函数内部的this指向. apply() apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作 ...
- JS 的 call apply bind 方法
js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[, [,.argN]]]] ...
- javascript中call,apply,bind的用法对比分析
这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们. 关于call,apply,bind这三个函数的用法,是学习java ...
- [转]js中几种实用的跨域方法原理详解
转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...
- js: this,call,apply,bind 总结
对js中的一些基本的很重要的概念做一些总结,对进一步学习js很重. 一.this JavaScript 中的 this 总是指向一个对象,而具体指向那个对象是在运行时基于函数的执行环境动态绑定的,而非 ...
- JavaScript中call,apply,bind方法的总结。
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- JS中setInterval、setTimeout不能传递带参数的函数的解决方案
在JS中无论是setTimeout还是setInterval,在使用函数名作为调用句柄时都不能带参数,而在许多场合必须要带参数,接下来为大家介绍具体的解决方法 在JS中无论是setTimeout还是s ...
随机推荐
- storm trident 示例
Storm Trident的核心数据模型是一批一批被处理的“流”,“流”在集群的分区在集群的节点上,对“流”的操作也是并行的在每个分区上进行. Trident有五种对“流”的操作: 1. 不 ...
- IQueryable<T> 与 ObjectQuery<T> 差异
命名空间:System.Data.Objects程序集: System.Data.Entity(在 System.Data.Entity.dll 中)public class ObjectQuery ...
- 【转】IE劫持原理 BHO
为什么"浏览器劫持"能够如此猖狂呢?放眼众多论坛的求助贴,我们不时可以看到诸如"我的IE被主页被改了,我用杀毒工具扫了一遍都没发现病毒,我把主页改回自己的地址,可是一重启 ...
- java7笔记
1 switch case 增加字符串类型,原理根据字符串hashcode以及string.equal比较2 数值字面量改进 新增二进制数值字面量 0b000004,在数值中间新增下划线方便阅读200 ...
- shell 记录
查看进程打开的文件句柄lsof -p 进程号|wc -l date --set "Wed Dec 11 14:51:41 CST 2013" 重启VPN pon vpn arg=` ...
- (转)Android开发出来的APP在手机的安装路径是?
一.安装路径在哪? Android应用安装涉及到如下几个目录: system/app系统自带的应用程序,无法删除.data/app用户程序安装的目录,有删除权限.安装时把apk文件复制到此目录.dat ...
- js基础知识:变量
一.什么是变量? 在JavaScript中,变量用来存放值的,存放任何数据类型的值都可以,它就是值的容器. 二.变量怎么用? (一)用var声明1个变量 在使用变量之前,需要var关键字来声明变量,变 ...
- MVVM框架中的一个非常重要的内容:数据双向绑定
双向绑定的意思就是,如下图中,当在input框中输入字符时,红色框框中的字也会随之改变. input框中需要一个绑定:ms-duplex(即“双工绑定”),http://avalonjs.github ...
- (原创)巩固理解基于DS18B20的1-wire协议(MCU,经验)
1.Abstract 如前篇随笔所写,将以前遇到最难懂的两个部分重拾一下.前一篇写的是I2C协议(http://www.cnblogs.com/hechengfei/p/4117840.htm ...
- Main()
P25 “每一个c#可执行文件都必须有一个入口——Main()方法” 我一直对这个Main()方法有一些疑问. 那就是这里头的参数. 在JAVA里,main(String args[])中的参数是绝对 ...