为什么需要这些?主要是因为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. EOS -- 一种灵巧的系统运行跟踪模块

    EOS到底是什么词的缩写,我猜应该是Error of System.最早接触它,是在UT那会.不过那会它是被设计成一个很大的数组,也没有被包含调用函数和行号,又或是时间,只是些计数.编码时,加减一个E ...

  2. MongoDB学习笔记-04 索引

    索引是用来加速查询的.有了索引之后,数据库不必进行全表扫描,只需先在索引中查找,再根据找到的索引查找数据.MongoDB的索引几乎和传统关系型数据库一样. 创建索引 创建索引是在相应的集合中使用ens ...

  3. C#学习感悟

    上周虽然没上课,课上的内容是部分同学展示大作业成果,但是对于我来说,看了一些同学辛勤劳动的成果,听了他们对C#学习的一些感悟,我受益匪浅. 在这里我想谈谈我的收获.老师给的模板是todolist,但是 ...

  4. [Leetcode]Palindrome Number

    Determine whether an integer is a palindrome. Do this without extra space. 这题貌似解法挺多,直接用简单的把数倒置,没有考虑数 ...

  5. [置顶]PADS PCB功能使用技巧系列之NO.005- 如何正确使用Verify Design?

    有没有遇到过进行Verify Design通过后,回来的样板仍然出现短路或其它莫名其妙的问题?此情此景,你是否一度对PADS失去的希望?但,工具是没有问题的,看看怎么样正确有效地使用它吧.主要需要注意 ...

  6. HashMap LinkedHashMap源码分析笔记

    MapClassDiagram

  7. java HashMap那点事

    集合类的整体架构 比较重要的集合类图如下:   有序否 允许元素重复否 Collection 否 是 List 是 是 Set AbstractSet 否 否 HashSet TreeSet 是(用二 ...

  8. 可嵌入式的动态http服务minihttp组件

    minihttp是基于c#实现的轻量级的动态WEB服务组件,通过minihttp可以轻松地构一个动态的WEB服务并嵌入到.NET程序中运行部署.由于minihttp完全基于托管代码实现,所以可以轻松运 ...

  9. Yii2中的入口文件环境配置

    默认的Debug配置 在入口文件中 defined ( 'YII_DEBUG' ) or define ( 'YII_DEBUG', true ); defined ( 'YII_ENV' ) or ...

  10. 开始VS 2012 中LightSwitch系列的第2部分:感受关爱——定义数据关系

    [原文发表地址]  Beginning LightSwitch in VS 2012 Part 2: Feel the Love - Defining Data Relationships [原文发表 ...