JS要旨连串

JS主旨序列:浅谈 call apply 与 bind

2016/03/01 · JavaScript
· apply,
bind,
call

初稿出处: 一像素   

在JavaScript中,call、apply和bind
是Function对象自带的多少个艺术,那八个艺术的紧要功用是改变函数中的this指向,从而可以高达接花移木的效应。本文将对这三个点子开展详细的讲授,并列出几个经典应用场景。

 

call(thisArgs [,args…])


该方法可以传递一个thisArgs参数和一个参数列表,thisArgs指定了函数在运行期的调用者,也就是函数中的this对象,而参数列表会被传播调用函数中。thisArgs的取值有以下4种情况:

(1) 不传,或者传null,undefined, 函数中的this指向window对象

(2) 传递另一个函数的函数名,函数中的this指向这几个函数的引用

(3)
传递字符串、数值或布尔类型等基础项目,函数中的this指向其相应的卷入对象,如
String、Number、Boolean

(4) 传递一个目标,函数中的this指向那几个目的

JavaScript

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的中央成效,它同意你在一个对象上调用该对象没有概念的点子,并且这么些方法可以访问该对象中的属性,至于那样做有啥利益,我待会再讲,大家先看一个简练的事例:

JavaScript

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’); >> Post params: test I’m onepixel
I’m function a!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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’);
>>
Post params: test
I’m onepixel
I’m function a!

当执行b.call时,字符串test用作参数传递给了函数b,由于call的机能,函数b中的this指向了对象a,
由此一定于调用了目的a上的函数b,而实质上a中一贯不定义b 。

 

apply(thisArgs[,args[]])


apply和call的绝无仅有分裂是第四个参数的传递格局各异,apply的第四个参数必须是一个数组,而call允许传递一个参数列表。值得您放在心上的是,固然apply接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的花样传递,大家看个简易的例子:

JavaScript

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

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

apply的这几个特点很重大,大家会在上面的利用场景中提到这么些特性。

 

bind(thisArgs [,args…])


bind是ES5新增的一个主意,它的传参和call类似,但又和call/apply有着强烈的差别,即调用call或apply都会活动执行相应的函数,而bind不会举行相应的函数,只是重返了对函数的引用。粗略一看,bind如同比call/apply要走下坡路一些,那ES5怎么还要引入bind呢?

实际上,ES5引入bind的的确目标是为了弥补call/apply的阙如,由于call/apply会对目的函数自动执行,从而造成它不可能在事件绑定函数中使用,因为事件绑定函数不需求大家手动执行,它是在事件被触发时由JS内部自行执行的。而bind在促成转移函数this的同时又不会活动执行对象函数,因而得以圆满的缓解上述问题,看一个事例就能了解:

JavaScript

var obj = {name:’onepixel’}; /** *
给document添加click事件监听,并绑定onClick函数 *
通过bind方法设置onClick的this为obj,并传递参数p1,p2 */
document.add伊夫ntListener(‘click’,onClick.bind(obj,’p1′,’p2′),false);
//当点击网页时接触并举行 function onClick(a,b){ console.log( this.name,
//onepixel a, //p1 b //p2 ) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var obj = {name:’onepixel’};
 
/**
* 给document添加click事件监听,并绑定onClick函数
* 通过bind方法设置onClick的this为obj,并传递参数p1,p2
*/
document.addEventListener(‘click’,onClick.bind(obj,’p1′,’p2′),false);
 
//当点击网页时触发并执行
function onClick(a,b){
    console.log(
            this.name, //onepixel
            a, //p1
            b  //p2
    )
}

当点击网页时,onClick被触发执行,输出onepixel p1 p2,
表明onClick中的this被bind改变成了obj对象,为了对bind进行深切的掌握,咱们来看一下bind的polyfill完结:

JavaScript

if (!Function.prototype.bind) { Function.prototype.bind = function
(oThis) { var aArgs = Array.prototype.slice.call(arguments, 1), fToBind
= this, //this在此处针对的是目标函数 fBound = function () { return
fToBind.apply( //倘若外部执行var obj = new
fBound(),则将obj作为最后的this,放任行使oThis this instanceof fToBind ?
this //此时的this就是new出的obj : oThis || this,
//倘诺传递的oThis无效,就将fBound的调用者作为this
//将通过bind传递的参数和调用时传递的参数进行联合,并作为最后的参数传递
aArgs.concat(Array.prototype.slice.call(arguments))); };
//将目的函数的原型对象拷贝到新函数中,因为目的函数有可能被看作构造函数使用
fBound.prototype = this.prototype; //重临fBond的引用,由外部按需调用
return fBound; }; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this, //this在这里指向的是目标函数
            fBound = function () {
                return fToBind.apply(
                    //如果外部执行var obj = new fBound(),则将obj作为最终的this,放弃使用oThis
                    this instanceof fToBind
                            ? this  //此时的this就是new出的obj
                            : oThis || this, //如果传递的oThis无效,就将fBound的调用者作为this
 
                    //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };
 
        //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用
        fBound.prototype = this.prototype;
 
        //返回fBond的引用,由外部按需调用
        return fBound;
    };
}

利用场景一:继承


世家明白,JavaScript中尚无诸如Java、C#等高级语言中的extend
关键字,由此JS中从不继续的概念,假如一定要延续的话,call和apply可以达成那个成效:

JavaScript

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

当通过new运算符发生了cat时,Cat中的this就本着了cat对象(关于new运算符的上课,请参考:),而持续的重中之重是在乎Cat中推行了Animal.call(this,’cat’,’50’)
那句话,在call中将this作为thisArgs参数传递,于是Animal方法中的this就对准了Cat中的this,而cat中的this指向的是cat对象,所以Animal中的this指向的就是cat对象,在Animal中定义了name和weight属性,就一定于在cat中定义了那么些属性,由此cat对象便享有了Animal中定义的习性,从而落成了继续的目标。

 

应用场景二:冯谖三窟


在讲上边的内容前面,我们首先来认识一下JavaScript中的一个非标准专业术语:ArrayLike(类数组/伪数组)

ArrayLike
对象即拥有数组的一部分作为,在DOM中已经呈现出来,而jQuery的凸起让ArrayLike在JavaScript中大放异彩。ArrayLike对象的技艺极其精巧在于它和JS原生的Array类似,不过它是随意构建的,它来自开发者对JavaScript对象的恢弘,也就是说:对于它的原型(prototype)大家可以自由定义,而不会污染到JS原生的Array。

ArrayLike对象在JS中被广泛使用,比如DOM中的NodeList,
函数中的arguments都是类数组对象,那些目的像数组一样存储着每一个元素,但它从不操作数组的点子,而我们可以透过call将数组的一些方法移接到ArrayLike对象,从而落成操作其元素的目标。比如大家可以这么遍历函数中的arguments:

JavaScript

function test(){ //检测arguments是还是不是为Array的实例 console.log( arguments
instanceof Array, //false Array.isArray(arguments) //false );
//判断arguments是不是有forEach方法 console.log(arguments.forEach);
//undefined // 将数组中的forEach应用到arguments上
Array.prototype.forEach.call(arguments,function(item){
console.log(item); // 1 2 3 4 }); } test(1,2,3,4);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function test(){
    //检测arguments是否为Array的实例
    console.log(
            arguments instanceof Array, //false
            Array.isArray(arguments)  //false
    );
    //判断arguments是否有forEach方法
    console.log(arguments.forEach); //undefined
 
    // 将数组中的forEach应用到arguments上
    Array.prototype.forEach.call(arguments,function(item){
        console.log(item); // 1 2 3 4
    });
 
}
test(1,2,3,4);

除开,对于apply而言,我们地点提到了它独有的一个特性,即apply接收的是数组,在传递给调用函数的时候是以参数列表传递的。
这几个特点让apply看起来比call
后来的超过先前的,比如有那样一个气象:给定一个数组[1,3,4,7],然后求数组中的最大因素,而你掌握,数组中并不曾得到最大值的法门,一般景观下,你必要经过编制代码来已毕。而大家了然,Math对象中有一个到手最大值的艺术,即Math.max(),
max方法必要传递一个参数列表,然后重临这么些参数中的最大值。而apply不仅可以将Math对象的max方法应用到别的对象上,还足以将一个数组转化为参数列表传递给max,看代码就能看清:

JavaScript

var arr = [2,3,1,5,4]; Math.max.apply(null,arr); // 5

1
2
3
var arr = [2,3,1,5,4];
 
Math.max.apply(null,arr); // 5

以上便是call和apply比较经典的多少个应用场景,熟识了解那一个技巧,并把这么些特色应用到你的其实项目中,会使您的代码看起来更为有意思!

2 赞 12 收藏
评论

亚洲必赢官网 1

在JavaScript中,call、apply和bind
是Function对象自带的两个措施,这多个措施的要害职能是改变函数中的this指向,从而可以高达`JS要旨连串。接花移木`的效能。本文将对那多少个主意开展详尽的讲解,并列出多少个经典应用场景。 

浅谈javascript中的call、apply、bind,applybind

在JavaScript中,call、apply和bind
是Function对象自带的三个方法,那八个法子的要紧作用是改变函数中的this指向,从而可以落成`接花移木`的效益。本文将对那多个艺术开展详尽的执教,并列出多少个经典应用场景。 

call(thisArgs [,args…])

该措施能够传递一个thisArgs参数和一个参数列表,thisArgs指定了函数在运行期的调用者,也就是函数中的this对象,而参数列表会被传到调用函数中。thisArgs的取值有以下4种情景:

(1) 不传,或者传null,undefined, 函数中的this指向window对象

(2) 传递另一个函数的函数名,函数中的this指向那个函数的引用

(3)
传递字符串、数值或布尔类型等基础项目,函数中的this指向其相应的包装对象,如
String、Number、Boolean

(4) 传递一个目的,函数中的this指向那几个目标

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');
>>
Post params: test
I'm onepixel
I'm function a!

当执行b.call时,字符串`test`用作参数传递给了函数b,由于call的功用,函数b中的this指向了对象a,
由此一定于调用了目的a上的函数b,而其实a中绝非定义b 。

apply(thisArgs[,args[]])

apply和call的绝无仅有不一致是第一个参数的传递方式各异,apply的第三个参数必须是一个数组,而call允许传递一个参数列表。值得您放在心上的是,尽管apply接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的花样传递,大家看个简单的事例:

function b(x,y,z){
  console.log(x,y,z);
}

b.apply(null,[1,2,3]); // 1 2 3

apply的那些特点很重大,大家会在上面的行使场景中提到这些特性。

bind(thisArgs [,args…])

bind是ES5新增的一个格局,它的传参和call类似,但又和call/apply有着明显的不一致,即调用call或apply都会活动执行相应的函数,而bind不会进行相应的函数,只是再次来到了对函数的引用。粗略一看,bind似乎比call/apply要走下坡路一些,那ES5怎么还要引入bind呢?

实则,ES5引入bind的实在目的是为着弥补call/apply的紧缺,由于call/apply会对目的函数自动执行,从而造成它无法在事件绑定函数中行使,因为事件绑定函数不要求大家手动执行,它是在事件被触发时由JS内部自行执行的。而bind在达成转移函数this的同时又不会活动执行对象函数,由此得以圆满的缓解上述问题,看一个事例就能知道:

var obj = {name:'onepixel'};

/**
 * 给document添加click事件监听,并绑定onClick函数
 * 通过bind方法设置onClick的this为obj,并传递参数p1,p2
 */
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);

//当点击网页时触发并执行
function onClick(a,b){
  console.log(
      this.name, //onepixel
      a, //p1
      b //p2
  )
}

当点击网页时,onClick被触发执行,输出onepixel p1 p2,
表达onClick中的this被bind改变成了obj对象,为了对bind举行浓密的领会,大家来看一下bind的polyfill完毕:

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    var aArgs = Array.prototype.slice.call(arguments, 1),
      fToBind = this, //this在这里指向的是目标函数
      fBound = function () {
        return fToBind.apply(
          //如果外部执行var obj = new fBound(),则将obj作为最终的this,放弃使用oThis
          this instanceof fToBind
              ? this //此时的this就是new出的obj
              : oThis || this, //如果传递的oThis无效,就将fBound的调用者作为this

          //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递
          aArgs.concat(Array.prototype.slice.call(arguments)));
      };

    //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用
    fBound.prototype = this.prototype;

    //返回fBond的引用,由外部按需调用
    return fBound;
  };
}

运用场景一:**继承**

世家清楚,JavaScript中没有诸如Java、C#等高等语言中的extend
关键字,由此JS中尚无继承的概念,若是一定要继承的话,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

当通过new运算符爆发了cat时,Cat中的this就针对了cat对象(关于new运算符的讲解,请参见:’)
那句话,在call中校this作为thisArgs参数传递,于是Animal方法中的this就本着了Cat中的this,而cat中的this指向的是cat对象,所以Animal中的this指向的就是cat对象,在Animal中定义了name和weight属性,就一定于在cat中定义了这个属性,因而cat对象便拥有了Animal中定义的性能,从而落成了一连的目的。 

使用场景二:**白云苍狗**

在讲下边的始末前边,我们首先来认识一下JavaScript中的一个非标准专业术语:ArrayLike(类数组/伪数组)

ArrayLike
对象即拥有数组的一片段作为,在DOM中已经突显出来,而jQuery的凸起让ArrayLike在JavaScript中大放异彩。ArrayLike对象的小巧在于它和JS原生的Array类似,不过它是任意构建的,它出自开发者对JavaScript对象的恢弘,也就是说:对于它的原型(prototype)大家可以随意定义,而不会污染到JS原生的Array。

ArrayLike对象在JS中被普遍选择,比如DOM中的NodeList,
函数中的arguments都是类数组对象,那几个目的像数组一样存储着每一个元素,但它从不操作数组的措施,而大家可以透过call将数组的某些方法`移接`到ArrayLike对象,从而达到操作其元素的目标。比如大家可以这样遍历函数中的arguments:

function test(){
  //检测arguments是否为Array的实例
  console.log(
      arguments instanceof Array, //false
      Array.isArray(arguments) //false
  );
  //判断arguments是否有forEach方法
  console.log(arguments.forEach); //undefined

  // 将数组中的forEach应用到arguments上
  Array.prototype.forEach.call(arguments,function(item){
    console.log(item); // 1 2 3 4
  });

}
test(1,2,3,4);

而外,对于apply而言,大家地点提到了它独有的一个特征,即apply接收的是数组,在传递给调用函数的时候是以参数列表传递的。
那几个特点让apply看起来比call
后发先至,比如有诸如此类一个景象:给定一个数组[1,3,4,7],然后求数组中的最大因素,而你掌握,数组中并不曾拿走最大值的不二法门,一般景色下,你需要通过编制代码来落到实处。而我辈领会,Math对象中有一个获取最大值的法子,即Math.max(),
max方法需要传递一个参数列表,然后回来那些参数中的最大值。而apply不仅可以将Math对象的max方法运用到任何对象上,还是能将一个数组转化为参数列表传递给max,看代码就能一目精通:

var arr = [2,3,1,5,4];

Math.max.apply(null,arr); // 5

以上便是call和apply比较经典的多少个应用场景,熟悉明白那一个技巧,并把这一个特色应用到您的实际上项目中,会使您的代码看起来尤其长远!

四个函数都是Function对象自带的多个办法,首要功用是改变函数中this的指向。

call(thisArgs [,args…])

您可能感兴趣的小说:

  • js apply/call/caller/callee/bind使用办法与分化分析
  • javascript中call,apply,bind的用法相比较分析
  • 浅谈javascript中call()、apply()、bind()的用法
  • 翻开Javascript中apply、call、bind的用法之旅方式
  • 跟我就学javascript的call(),apply(),bind()与回调
  • 浅谈javascript的call()、apply()、bind()的用法

在JavaScript中,call、apply和bind
是Function对象自带的七个法子,这八个办法的严重性效用是改变函数中…

call()

该方法可以传递一个thisArgs参数和一个参数列表,thisArgs指定了函数在运行期的调用者,也就是函数中的this对象,而参数列表会被传到调用函数中。thisArgs的取值有以下4种情景:

语法 fun.call(thisArg[, arg1[, arg2[, …]]])

(1) 不传,或者传null,undefined, 函数中的this指向window对象

该情势可以传递一个thisArgs参数和一个参数列表,thisArgs指定了函数在运行期的调用者,也就是函数中的this对象,而参数列表会被盛传调用函数中。

(2) 传递另一个函数的函数名,函数中的this指向那个函数的引用

经过 call
方法,你可以在一个对象上借用另一个对象上的不二法门,比如Object.prototype.toString.call([]),就是一个Array对象借用了Object对象上的法子。

(3)
传递字符串、数值或布尔类型等基础项目,函数中的this指向其对应的包装对象,如
String、Number、Boolean

thisArgs的取值有以下4种情景:

(4) 传递一个对象,函数中的this指向那些目的

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

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
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的中央作用,它同意你在一个对象上调用该目的没有概念的法子,并且那几个方法可以访问该对象中的属性,至于那样做有怎样利益,我待会再讲,大家先看一个简短的例证:

那是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');
>>
Post params: test
I'm onepixel
I'm function a!

示例:

当执行b.call时,字符串`test`用作参数传递给了函数b,由于call的法力,函数b中的this指向了目标a,
由此一定于调用了对象a上的函数b,而事实上a中一贯不概念b 。

A、

apply(thisArgs[,args[]])

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的

apply和call的唯一分化是第三个参数的传递形式各异,apply的首个参数必须是一个数组,而call允许传递一个参数列表。值得你注意的是,纵然apply接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的款式传递,大家看个大约的例证:

输出:

function b(x,y,z){
 console.log(x,y,z);
}

b.apply(null,[1,2,3]); // 1 2 3
//Post params: test
//I'm onepixel
//I'm function a!

apply的那个特点很重点,大家会在底下的应用场景中涉嫌那几个特点。

B、

bind(thisArgs [,args…])

运用call方法调用匿名函数

bind是ES5新增的一个方式,它的传参和call类似,但又和call/apply有着显明的不等,即调用call或apply都会活动执行相应的函数,而bind不会举行相应的函数,只是重回了对函数的引用。粗略一看,bind如同比call/apply要滞后一些,那ES5怎么还要引入bind呢?

在下例中的for循环体内,我们创造了一个匿名函数,然后经过调用该函数的call方法,将各样数组元素作为指定的this值执行了极度匿名函数。那一个匿名函数的紧要目的是给种种数组元素对象添加一个print方法,那些print方法可以打印出各因素在数组中的正确索引号。当然,这里不是必须得让数组元素作为this值传入那一个匿名函数(普通参数就足以),目标是为了演示call的用法。

骨子里,ES5引入bind的真的目标是为了弥补call/apply的阙如,由于call/apply会对目标函数自动执行,从而致使它无法在事件绑定函数中利用,因为事件绑定函数不必要大家手动执行,它是在事件被触发时由JS内部自行执行的。而bind在贯彻转移函数this的同时又不会自动执行对象函数,因而得以健全的化解上述问题,看一个例证就能明了:

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
var obj = {name:'onepixel'};

/**
 * 给document添加click事件监听,并绑定onClick函数
 * 通过bind方法设置onClick的this为obj,并传递参数p1,p2
 */
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);

//当点击网页时触发并执行
function onClick(a,b){
 console.log(
   this.name, //onepixel
   a, //p1
   b //p2
 )
}

另:

当点击网页时,onClick被触发执行,输出onepixel p1 p2,
表达onClick中的this被bind改变成了obj对象,为了对bind进行长远的知道,大家来看一下bind的polyfill达成:

亚洲必赢官网 2

if (!Function.prototype.bind) {
 Function.prototype.bind = function (oThis) {
  var aArgs = Array.prototype.slice.call(arguments, 1),
   fToBind = this, //this在这里指向的是目标函数
   fBound = function () {
    return fToBind.apply(
     //如果外部执行var obj = new fBound(),则将obj作为最终的this,放弃使用oThis
     this instanceof fToBind
       ? this //此时的this就是new出的obj
       : oThis || this, //如果传递的oThis无效,就将fBound的调用者作为this

     //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递
     aArgs.concat(Array.prototype.slice.call(arguments)));
   };

  //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用
  fBound.prototype = this.prototype;

  //返回fBond的引用,由外部按需调用
  return fBound;
 };
}

亚洲必赢官网 3

选用场景一:**继承**

apply()

大家清楚,JavaScript中向来不诸如Java、C#等高级语言中的extend
关键字,因而JS中从未持续的定义,如果一定要持续的话,call和apply可以已毕那个效果:

语法:fun.apply(thisArg[, argsArray])

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

apply和call的绝无仅有差异是第四个参数的传递方式分裂,apply的首个参数必须是一个数组,而call允许传递一个参数列表。值得你放在心上的是,固然apply接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的格局传递。

当通过new运算符爆发了cat时,Cat中的this就本着了cat对象,而继续的关键是在于Cat中执行了Animal.call(this,’cat’,’50’)
那句话,在call司令员this作为thisArgs参数传递,于是Animal方法中的this就针对了Cat中的this,而cat中的this指向的是cat对象,所以Animal中的this指向的就是cat对象,在Animal中定义了name和weight属性,就一定于在cat中定义了这个属性,由此cat对象便具有了Animal中定义的特性,从而达到了一连的目标。 

瞩目:那里的argsArray可以是一个数组或者类数组对象,如若该参数的值为null
或 undefined,则意味不需求传入任何参数。

应用场景二:**风云万变**

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

在讲上面的情节前面,大家第一来认识一下JavaScript中的一个非标准专业术语:ArrayLike(类数组/伪数组)

应用apply和停放函数

ArrayLike
对象即拥有数组的一有些作为,在DOM中曾经展现出来,而jQuery的凸起让ArrayLike在JavaScript中大放异彩。ArrayLike对象的精细在于它和JS原生的Array类似,可是它是轻易构建的,它出自开发者对JavaScript对象的扩张,也就是说:对于它的原型(prototype)大家可以随心所欲定义,而不会污染到JS原生的Array。

智慧的apply用法允许你在某些本来须要写成遍历数组变量的职责中运用内建的函数。在吸收里的事例中大家会利用Math.max/Math.min来找出一个数组中的最大/最小值。

ArrayLike对象在JS中被周边运用,比如DOM中的NodeList,
函数中的arguments都是类数组对象,那一个目的像数组一样存储着每一个因素,但它从未操作数组的法子,而我辈得以因此call将数组的少数方法`移接`到ArrayLike对象,从而已毕操作其元素的目的。比如我们可以那样遍历函数中的arguments:

//里面有最大最小数字值的一个数组对象
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);

//通常情况我们会这样来找到数字的最大或者最小值
//比对上面的栗子,是不是下面的看起来没有上面的舒服呢?
max = -Infinity, min = +Infinity;
for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max)
    max = numbers[i];
  if (numbers[i] < min) 
    min = numbers[i];
}
function test(){
 //检测arguments是否为Array的实例
 console.log(
   arguments instanceof Array, //false
   Array.isArray(arguments) //false
 );
 //判断arguments是否有forEach方法
 console.log(arguments.forEach); //undefined

 // 将数组中的forEach应用到arguments上
 Array.prototype.forEach.call(arguments,function(item){
  console.log(item); // 1 2 3 4
 });

}
test(1,2,3,4);

call()与apply()应该选哪一个可以吗?

除了,对于apply而言,我们地点提到了它独有的一个特色,即apply接收的是数组,在传递给调用函数的时候是以参数列表传递的。
那几个特性让apply看起来比call
后来者居上,比如有这么一个风貌:给定一个数组[1,3,4,7],然后求数组中的最大要素,而你精晓,数组中并从未获取最大值的主意,一般情形下,你须要经过编制代码来贯彻。而我们知晓,Math对象中有一个赢得最大值的艺术,即Math.max(),
max方法需求传递一个参数列表,然后回来那几个参数中的最大值。而apply不仅可以将Math对象的max方法运用到任何对象上,还足以将一个数组转化为参数列表传递给max,看代码就能一目精通:

当参数是众所周知了然多少时用call;不确定的时候用apply,然后把参数push进数组传递进入,也可以通过arguments那几个数组来遍历所有的参数。

var arr = [2,3,1,5,4];

Math.max.apply(null,arr); // 5

bind()

如上便是call和apply相比经典的多少个利用场景,熟稔明白那几个技术,并把那些特征应用到您的实在项目中,会使你的代码看起来越发深入!

语法:fun.bind(thisArg[, arg1[, arg2[, …]]])

你可能感兴趣的稿子:

  • js
    apply/call/caller/callee/bind使用办法与分化分析
  • 浅谈javascript中call()、apply()、bind()的用法
  • JS中改变this指向的办法(call和apply、bind)
  • 跟自身上学javascript的call(),apply(),bind()与回调
  • javascript中call,apply,bind的用法相比较分析
  • 浅谈javascript的call()、apply()、bind()的用法
  • javascript中call apply 与
    bind方法详解
  • 敞开Javascript中apply、call、bind的用法之旅情势
  • 有关JS中的apply,call,bind的中肯解析
  • javascript中apply、call和bind的选取分别
  • javascript中call,apply,bind函数用法示例

bind是ES5新增的一个办法,它的传参和call类似,但又和call/apply有着强烈的差别,即调用call或apply都会自动执行相应的函数,而bind不会举行相应的函数,只是重返了对函数的引用。

亚洲必赢官网 4

简单一看,bind如同比call/apply要滞后一些,那ES5为啥还要引入bind呢?

实际,ES5引入bind的真正目标是为着弥补call/apply的供不应求,由于call/apply会对目标函数自动执行,从而导致它无法在事变绑定函数中选择,因为事件绑定函数不需求大家手动执行,它是在事变被触发时由JS内部自行执行的。而bind在落到实处转移函数this的同时又不会自行执行对象函数,因而可以周全的解决上述问题,看一个例子就能领会:

亚洲必赢官网 ,当点击网页时,伊芙(Eve)ntClick被触发执行,输出JSLite.io p1 p2,
表明伊芙(Eve)ntClick中的this被bind改变成了obj对象。若是你将伊芙ntClick.bind(obj,’p1′,’p2′)
变成 伊夫(Eve)ntClick.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;
  };
}

应用场景一:继承
大家了解,JavaScript中没有诸如Java、C#等高级语言中的extend
关键字,由此JS中尚无持续的定义,要是一定要三番两次的话,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

当通过new运算符发生了cat时,Cat中的this就本着了cat对象(关于new运算符的讲解,请参见:)
那句话,在call中校this作为thisArgs参数传递,于是Animal方法中的this就对准了Cat中的this,而cat中的this指向的是cat对象,所以Animal中的this指向的就是cat对象,在Animal中定义了name和weight属性,就一定于在cat中定义了这个属性,由此cat对象便享有了Animal中定义的性质,从而完结了继承的目标。

动用场景二:冯谖三窟(原型伸张)

在讲上面的情节前边,大家第一来认识一下JavaScript中的一个非标准专业术语:ArrayLike(类数组/伪数组)

ArrayLike 对象即拥有数组的一片段作为,在DOM中一度显示出来,而jQuery的非凡让ArrayLike在JavaScript中大放异彩。ArrayLike对象的小巧在于它和JS原生的Array类似,然而它是自由构建的,它来自开发者对JavaScript对象的恢宏,也就是说:对于它的原型(prototype)大家可以随便定义,而不会污染到JS原生的Array。

ArrayLike对象在JS中被广泛使用,比如DOM中的NodeList, 函数中的arguments都是类数组对象,那个目的像数组一样存储着每一个元素,但它没有操作数组的章程,而我辈得以经过call将数组的一些方法移接到ArrayLike对象,从而达成操作其元素的目的。比如大家可以这样遍历函数中的arguments:

function test(){
    //检测arguments是否为Array的实例
    console.log(
            arguments instanceof Array, //false
            Array.isArray(arguments)  //false
    );
    //判断arguments是否有forEach方法
    console.log(arguments.forEach); //undefined

    // 将数组中的forEach应用到arguments上
    Array.prototype.forEach.call(arguments,function(item){
        console.log(item); // 1 2 3 4
    });

}
test(1,2,3,4);

而外,对于apply而言,我们地点提到了它独有的一个特点,即apply接收的是数组,在传递给调用函数的时候是以参数列表传递的。
这几个特性让apply看起来比call 后发先至,比如有诸如此类一个现象:给定一个数组[1,3,4,7],然后求数组中的最大要素,而你精晓,数组中并没有取得最大值的章程,一般意况下,你必要通过编制代码来落到实处。而我辈知道,Math对象中有一个得到最大值的不二法门,即Math.max(), max方法须求传递一个参数列表,然后回到那几个参数中的最大值。而apply不仅可以将Math对象的max方法运用到其余对象上,还是可以将一个数组转化为参数列表传递给max,看代码就能一目精晓:

var arr = [2,3,1,5,4];

Math.max.apply(null,arr); // 5

 

 

 

 

 

 

 

参考:

 

网站地图xml地图