为什么需要这些?主要是因为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使用指南,带部分原理。的更多相关文章

  1. js 中call,apply,bind的区别

    call.apply.bind方法的共同点与区别: apply.call.bind 三者都是用来改变函数的this对象的指向: apply.call.bind 三者都可以利用后续参数传参: bind ...

  2. JS中call,apply,bind方法的总结

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...

  3. JS中call,apply,bind的区别

    1.关于this对象的指向,请看如下代码 var name = 'jack'; var age = 18; var obj = { name:'mary', objAge:this.age, myFu ...

  4. 深入理解js中的apply、call、bind

    概述 js中的apply,call都是为了改变某个函数运行时的上下文环境而存在的,即改变函数内部的this指向. apply() apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作 ...

  5. JS 的 call apply bind 方法

    js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[,   [,.argN]]]] ...

  6. javascript中call,apply,bind的用法对比分析

    这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们.   关于call,apply,bind这三个函数的用法,是学习java ...

  7. [转]js中几种实用的跨域方法原理详解

    转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...

  8. js: this,call,apply,bind 总结

    对js中的一些基本的很重要的概念做一些总结,对进一步学习js很重. 一.this JavaScript 中的 this 总是指向一个对象,而具体指向那个对象是在运行时基于函数的执行环境动态绑定的,而非 ...

  9. JavaScript中call,apply,bind方法的总结。

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...

  10. JS中setInterval、setTimeout不能传递带参数的函数的解决方案

    在JS中无论是setTimeout还是setInterval,在使用函数名作为调用句柄时都不能带参数,而在许多场合必须要带参数,接下来为大家介绍具体的解决方法 在JS中无论是setTimeout还是s ...

随机推荐

  1. Python socket (多线程)

    Server 端 code import SocketServer class MyTCPHandler(SocketServer.BaseRequestHandler): ""& ...

  2. (最小路径覆盖) News 消息传递 (hust OJ 2604)

    http://begin.lydsy.com/JudgeOnline/problem.php?id=2604   Description 总部最近打算向下面的N个工作人员发出了一条秘密消息.因为它是机 ...

  3. jQUery 1.9中被删除的API

    jQuery1.9删除了一些在以前版本中已经过时的api,想要把那些不够安全的.缺乏效率的.用处不大的,以及带有误导的特性统统去掉.如果你想升级你的jquery版本,但又使用了如下被删除的api的话, ...

  4. ubuntu上搭建review board代码评审站点

    Reviewboard是一个开源个人可以免费使用的代码评审框架,貌似现在有越来越多的公司也开始使用reviewboard作为公司的代码评审工具. 今天早上试了一下,搭建过程非常方便简单,按照网页提示即 ...

  5. mysql命令化操作实用小技巧

    ★1.问:如果我的mysql数据库服务器程序在D:\program files\phpstudy\mysql,里,那么我该怎么在cmd命令状态下使用它?      进入cmd状态后,系统默认在当前用户 ...

  6. (转)使用Node.js+Socket.IO搭建WebSocket实时应用

    Web领域的实时推送技术,也被称作Realtime技术.这种技术要达到的目的是让用户不需要刷新浏览器就可以获得实时更新.它有着广泛的应用场景,比如在线聊天室.在线客服系统.评论系统.WebIM等. W ...

  7. 读入一个c程序,并按字母表顺序分组打印变量名,每组前N个字符相同(TCPL 练习6-2)

    在建立结构tnode的过程中,我们没有预设门槛.这道题目就设置了门槛,必须根据前N个字符来进行分组,于是排除了长度小于N的变量,以便减轻负担. 因为要求对变量名分组打印,组别理所应当地应该按照至少是升 ...

  8. java 多线程--- Thread Runnable Executors

    java 实现多线程的整理: Thread实现多线程的两种方式: (1)继承 Thread类,同时重载 run 方法: class PrimeThread extends Thread { long ...

  9. python 调用nmap

    1.系统中需要安装nmap 2.系统中安装pip 2.安装python调用nmap的lib包 命令为:pip install python-nmap 以下是在centos系统下安装成功后的截图 在命令 ...

  10. HTML5学习生涯1--touchmove中遇到的问题

    在使用html5做在手机上显示轮播图片的效果时突然遇到touchmove事件在touchstart事件之后只触发了一次touchmove之后和touchend一起触发了一次,咦,这是怎么回事?怎么不和 ...