就是一个Array对象借用了Object对象上的方法巴黎人
分类:巴黎人-前端

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.addEventListener('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

复制代码 代码如下:

除去,对于apply来说,大家地方提到了它独有的三个特征,即apply接收的是数组,在传递给调用函数的时候是以参数列表传递的。 那么些特点让apply看起来比call 长江后浪推前浪,比如有诸如此比一个风貌:给定七个数组[1,3,4,7],然后求数组中的最轮廓素,而你领悟,数组中并未收获最大值的不二等秘书技,通常景况下,你必要经过编写制定代码来落到实处。而大家知晓,Math对象中有四个获取最大值的法子,即Math.max(), max方法必要传递贰个参数列表,然后回来这么些参数中的最大值。而apply不仅能将Math对象的max方法应用到其余对象上,还足以将三个数组转化为参数列表传递给max,看代码就会看清:

  bind和call以至apply同样,都以足以变动上下文的this指向的。分裂的是,call和apply同样,直接援用在格局上,而bind绑定this后回到多个方式,但此中基本还是apply。

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;
  };
}

var obj = {
  a: 1,
  b: 2,
  getCount: function(c, d) {
    return this.a + this.b + c + d;
  }
};
 
Function.prototype.bind = Function.prototype.bind || function(context) {
  var that = this;
  return function() {
    // console.log(arguments); // console [3,4] if ie<6-8>
    return that.apply(context, arguments);
 
  }
}
window.a = window.b = 0;
var func = obj.getCount.bind(obj);
console.log(func(3, 4));  // 10

示例:

var obj = {
  a: 1,
  b: 2,
  getCount: function(c, d) {
    return this.a + this.b + c + d;
  }
};
 
window.a = window.b = 0;
var func = obj.getCount.bind(obj);
console.log(func(3, 4));  // 10

bind()

怎会这么?因为func在内外文中的this是window!bind的留存就是为了转移this指向得到想要的值:

在下例中的for循环体内,我们创制了三个无名函数,然后经过调用该函数的call方法,将各样数组成分作为钦定的this值实践了十一分无名氏函数。那些无名函数的主要指标是给各类数组成分对象增加一个print方法,那一个print方法能够打印出各要素在数组中的精确索引号。当然,这里不是必得得让数组成分作为this值传入那三个无名氏函数(普通参数就足以),目标是为了演示call的用法。

复制代码 代码如下:

多个函数都以Function对象自带的多少个法子,首要功用是更改函数中this的针对。

平昔看例子:

当点击网页时,EventClick被触发执行,输出JSLite.io p1 p2, 表明伊芙ntClick中的this被bind改换成了obj对象。假令你将伊芙ntClick.bind(obj,'p1','p2') 形成 伊夫ntClick.call(obj,'p1','p2') 的话,页面会直接出口 JSLite.io p1 p2

  bind是function的二个函数扩张方法,bind现在代码重新绑定了func内部的this指向(obj),不过不宽容ie6~8,包容代码如下:

经过 call 方法,你能够在三个对象上借用另三个对象上的主意,譬喻Object.prototype.toString.call([]),便是一个Array对象借用了Object对象上的艺术。

  其实在自家看来bind的中坚是回来一个未执行的法子,即使直白接纳apply也许call:

thisArgs的取值有以下4种意况:

复制代码 代码如下:

A、

var obj = {
  a: 1,
  b: 2,
  getCount: function(c, d) {
    return this.a + this.b + c + d;
  }
};
 
window.a = window.b = 0;
console.log(obj.getCount(3, 4));  // 10
var func = obj.getCount;
console.log(func(3, 4));  // 7

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

  不能运用简写的func函数构造,所以用bind传递this指向,再再次来到二个未进行的方法,达成格局十二分抢眼。

 

您大概感兴趣的篇章:

  • JavaScript Array对象增加indexOf()方法
  • 实例解说JS中数组Array的操作方法
  • javascript版的in_array函数(判定数组中是否留存特定值)
  • JS数组(Array)管理函数整理
  • JavaScript中的ArrayBuffer详细介绍
  • js使用Array.prototype.sort()对数组对象排序的章程
  • javascript中Array数组的迭代方法实例深入分析
  • 浅谈javascript的Array.prototype.slice.call
  • JS Array.slice 截取数组的贯彻方式
  • Js的Array数组对象详解
  • JavaScript判定变量是或不是为数组的主意(Array)
  • JavaScript Array对象详解
  • JavaScript中循环遍历Array与Map的不二诀要小结
  • JavaScript ES5规范中新扩张的Array方法

call()与apply()应该选哪二个行吗?

复制代码 代码如下:

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

直白以来对和this有关的事物模糊不清,譬喻call、apply等等。此番看来贰个和bind有关的笔试题,故记此文以备忘。

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

var ans = obj.getCount.apply(obj, [3, 4]);
console.log(ans); // 10

利用call方法调用无名氏函数

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

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

 

参考:

apply()

巴黎人手机版 2

本文由巴黎人手机版发布于巴黎人-前端,转载请注明出处:就是一个Array对象借用了Object对象上的方法巴黎人

上一篇:布局的传统解决方案,《CSS3弹性伸缩布局(巴黎 下一篇:没有了
猜你喜欢
热门排行
精彩图文