JS apply 、call和bind

JS当中的call 、apply、和bind

这三个方法都是js function当中自带的方法,用来改变this的指向。数组

call()方法

语法格式:app

fun.call(thisArg[,arg1[, arg2[, ...]]])

该方法能够传递一个thisArgs参数和一个参数列表,thisArgs指定了函数在运行期的调用者,也就是函数中的this对象,而参数列表会被传入调用函数中。函数

经过 call 方法,你能够在一个对象上借用另外一个对象上的方法,好比Object.prototype.toString.call([]),就是一个Array对象借用了Object对象上的方法。this

thisArgs的取值有如下4种状况:prototype

(1) 不传,或者传null,undefined, 函数中的this指向window对象
(2) 传递另外一个函数的函数名,函数中的this指向这个函数的引用
(3) 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean
(4) 传递一个对象,函数中的this指向这个对象code

function a(){
 console.log(this); //输出函数a中的this对象
 }
 function b(){} //定义函数b
 var obj = {name:'onepixel'}; //定义对象obj
 a.call(); //window
 a.call(null); //window
 a.call(undefined);//window
 a.call(1); //Number
 a.call(''); //String
 a.call(true); //Boolean
 a.call(b);// function b(){}
 a.call(obj); //Object

这是call的核心功能,它容许你在一个对象上调用该对象没有定义的方法,而且这个方法能够访问该对象中的属性。对象

例如:继承

var a = {
    name:'onepixel', //定义a的属性
    say:function(){ //定义a的方法
        console.log("Hi,I'm function a!");
    }
};
function b(name){
    console.log("Post params: "+ name);
    console.log("I'm "+ this.name);
    this.say();
}
b.call(a,'test');     //将b的this指向a,参数是b的

还能够经过call方法来调用匿名函数索引

在下例中的for循环体内,咱们建立了一个匿名函数,而后经过调用该函数的call方法,将每一个数组元素做为指定的this值执行了那个匿名函数。这个匿名函数的主要目的是给每一个数组元素对象添加一个print方法,这个print方法能够打印出各元素在数组中的正确索引号。固然,这里不是必须得让数组元素做为this值传入那个匿名函数(普通参数就能够),目的是为了演示call的用法。事件

var animals = [
  {species: 'Lion', name: 'King'},
  {species: 'Whale', name: 'Fail'}
];

for (var i = 0; i < animals.length; i++) {
  (function (i) { 
    this.print = function () { 
      console.log('#' + i  + ' ' + this.species + ': ' + this.name); 
    } 
    this.print();
  }).call(animals[i], i);
}
//#0 Lion: King
//#1 Whale: Fail

apply()方法

语法格式:

fun.apply(thisArg[, argsArray])

apply和call的惟一区别是第二个参数的传递方式不一样,apply的第二个参数必须是一个数组,而call容许传递一个参数列表。值得你注意的是,虽然apply接收的是一个参数数组,但在传递给调用函数时,倒是以参数列表的形式传递。

注意:这里的argsArray能够是一个数组或者类数组对象,若是该参数的值为null 或 undefined,则表示不须要传入任何参数。

function b(x,y,z){
    console.log(x,y,z);
}
b.apply(null,[1,2,3]); // 1 2 3

apply方法的实用写法

//里面有最大最小数字值的一个数组对象
var numbers = [5, 6, 2, 3, 7];

/* 使用 Math.min/Math.max 在 apply 中应用 */
var max = Math.max.apply(null, numbers);
// 通常状况是用 Math.max(5, 6, ..) 或者 Math.max(numbers[0], ...) 来找最大值
var min = Math.min.apply(null, numbers);

当参数是明确知道数量时用call;不肯定的时候用apply,而后把参数push进数组传递进去,也能够经过arguments这个数组来遍历全部的参数。

bind()方法

语法格式:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

bind是ES5新增的一个方法,它的传参和call相似,但又和call/apply有着显著的不一样,即调用call或apply都会自动执行对应的函数,而bind不会执行对应的函数,只是返回了对函数的引用。

ES5中新增长的bind方法能够弥补call()和apply()方法的不足,因为call/apply会对目标函数自动执行,从而致使它没法在事件绑定函数中使用,由于事件绑定函数不须要咱们手动执行,它是在事件被触发时由JS内部自动执行的。而bind在实现改变函数this的同时又不会自动执行目标函数,所以能够完美的解决上述问题,看一个例子就能明白:

当点击网页时,EventClick被触发执行,输出JSLite.io p1 p2, 说明EventClick中的this被bind改变成了obj对象。若是你将EventClick.bind(obj,'p1','p2') 变成 EventClick.call(obj,'p1','p2') 的话,页面会直接输出 JSLite.io p1 p2

var obj = {name:'JSLite.io'};
/**
 * 给document添加click事件监听,并绑定EventClick函数
 * 经过bind方法设置EventClick的this为obj,并传递参数p1,p2
 */
document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false);
//当点击网页时触发并执行
function EventClick(a,b){
    console.log(
            this.name, //JSLite.io
            a, //p1
            b  //p2
    )
}
// JSLite.io p1 p2

兼容写法

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1), 
        fToBind = this, // this在这里指向的是目标函数
        fNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof fNOP
                 ? this //此时的this就是new出的obj
                 : oThis || this,//若是传递的oThis无效,就将fBound的调用者做为this
                
               //将经过bind传递的参数和调用时传递的参数进行合并,并做为最终的参数传递
               aArgs.concat(Array.prototype.slice.call(arguments)));
        };
    fNOP.prototype = this.prototype;
    //将目标函数的原型对象拷贝到新函数中,由于目标函数有可能被看成构造函数使用
    fBound.prototype = new fNOP();
    //返回fBond的引用,由外部按需调用
    return fBound;
  };
}

应用

经过call和apply实现继承:

function Animal(name,weight){
   this.name = name;
   this.weight = weight;
}
function Cat(){
    Animal.call(this,'cat','50');
  //Animal.apply(this,['cat','50']);
   this.say = function(){
      console.log("I am " + this.name+",my weight is " + this.weight);
   }
}
var cat = new Cat();
cat.say();//I am cat,my weight is 50
相关文章
相关标签/搜索