深刻浅出妙用

美高梅开户网址 ,长远浅出妙用 Javascript 中 apply、call、bind

2015/09/24 · JavaScript
· 4 评论 ·
apply,
bind,
call

正文作者: 伯乐在线 –
chokcoco
。未经作者许可,禁止转发!
迎接出席伯乐在线 专辑小编。

那篇作品实在是很难下笔,因为网上有关作品比比皆是。

戏剧性的是前天看到阮老师的一篇文章的一句话:

“对自己来说,博客首先是一种知识管理工具,其次才是流传工具。我的技能文章,主要用来收拾自己还不懂的文化。我只写那一个自己还向来不完全控制的事物,这么些自己精通的东西,往往没有动力写。炫耀没有是自个儿的意念,好奇才是。”

对于那句话,不可能帮忙越来越多,也让自家下决心好好写那篇,网上小说虽多,大多复制粘贴,且晦涩难懂,我期待可以通过那篇小说,可以清晰的晋级对apply、call、bind的认识,并且列出有些它们的妙用加深纪念。

   apply、call

在 javascript 中,call 和 apply
都是为着改变某个函数运行时的上下文(context)而留存的,换句话说,就是为着改变函数体内部
this 的对准。

JavaScript
的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以转移的」那样的概念。

先来一个板栗:

JavaScript

function fruits() {} fruits.prototype = { color: “red”, say: function()
{ console.log(“My color is ” + this.color); } } var apple = new fruits;
apple.say(); //My color is red

1
2
3
4
5
6
7
8
9
10
11
function fruits() {}
 
fruits.prototype = {
    color: "red",
    say: function() {
        console.log("My color is " + this.color);
    }
}
 
var apple = new fruits;
apple.say();    //My color is red

不过只要大家有一个目的banana= {color : “yellow”} ,大家不想对它再也定义
say 方法,那么大家得以通过 call 或 apply 用 apple 的 say 方法:

JavaScript

banana = { color: “yellow” } apple.say.call(banana); //My color is
yellow apple.say.apply(banana); //My color is yellow

1
2
3
4
5
banana = {
    color: "yellow"
}
apple.say.call(banana);     //My color is yellow
apple.say.apply(banana);    //My color is yellow

所以,可以看来 call 和 apply 是为着动态改变 this 而出现的,当一个 object
没有某个方法(本栗子中banana没有say方法),不过其他的有(本栗子中apple有say方法),大家得以看重call或apply用此外对象的法门来操作。

apply、call 的区别

对于 apply、call
二者而言,成效完全一致,只是接受参数的方法不太相同。例如,有一个函数定义如下:

JavaScript

var func = function(arg1, arg2) { };

1
2
3
var func = function(arg1, arg2) {
 
};

就足以由此如下方式来调用:

JavaScript

func.call(this, arg1, arg2); func.apply(this, [arg1, arg2])

1
2
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])

中间 this 是您想指定的上下文,他可以是其余一个 JavaScript
对象(JavaScript 中任何皆对象),call 必要把参数按顺序传递进入,而 apply
则是把参数放在数组里。

JavaScript
中,某个函数的参数数量是不定点的,因而要说适用标准的话,当您的参数是醒目知道多少时用
call 。

而不确定的时候用 apply,然后把参数 push
进数组传递进入。当参数数量不确定时,函数内部也足以通过 arguments
这么些数组来遍历所有的参数。

为了加固深化回忆,上面列举部分常用用法:

1、数组之间追加

JavaScript

var array1 = [12 , “foo” , {name “Joe”} , -2458]; var array2 = [“Doe”
, 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1
值为 [12 , “foo” , {name “Joe”} , -2458 , “Doe” , 555 , 100] */

1
2
3
4
var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为  [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

2、获取数组中的最大值和最小值

JavaScript

var numbers = [5, 458 , 120 , -215 ]; var maxInNumbers =
Math.max.apply(Math, numbers), //458 maxInNumbers =
Math.max.call(Math,5, 458 , 120 , -215); //458

1
2
3
var  numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers),   //458
    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

number 本身并未 max 方法,不过 Math 有,大家就可以依靠 call 或者 apply
使用其方法。

3、验证是或不是是数组(前提是toString()方法没有被重写过)

JavaScript

functionisArray(obj){ returnObject.prototype.toString.call(obj) ===
‘[object Array]’ ; }

1
2
3
functionisArray(obj){
    returnObject.prototype.toString.call(obj) === ‘[object Array]’ ;
}

4、类(伪)数组使用数组方法

JavaScript

var domNodes =
Array.prototype.slice.call(document.getElementsByTagName(“*”));

1
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));

Javascript中存在一种名为伪数组的目的协会。相比特其他是 arguments
对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们重临NodeList对象都属于伪数组。不可能利用
Array下的 push , pop 等艺术。

而是大家能透过 Array.prototype.slice.call 转换为实在的数组的包括 length
属性的对象,那样 domNodes 就可以运用 Array 下的富有办法了。

深深了然运用apply、call

下面就借用一道面试题,来更长远的去了解下
apply 和 call 。

概念一个 log 方法,让它可以代办 console.log 方法,常见的解决格局是:

JavaScript

function log(msg) { console.log(msg); } log(1); //1 log(1,2); //1

1
2
3
4
5
function log(msg) {
  console.log(msg);
}
log(1);    //1
log(1,2);    //1

上边方法可以缓解最基本的要求,可是当传入参数的个数是不确定的时候,上边的艺术就失效了,这些时候就足以考虑拔取apply 或者
call,注意那里流传多少个参数是不确定的,所以利用apply是最好的,方法如下:

JavaScript

function log(){ console.log.apply(console, arguments); }; log(1); //1
log(1,2); //1 2

1
2
3
4
5
function log(){
  console.log.apply(console, arguments);
};
log(1);    //1
log(1,2);    //1 2

接下去的需要是给每一个 log 音信添加一个”(app)”的前辍,比如:

JavaScript

log(“hello world”); //(app)hello world

1
log("hello world");    //(app)hello world

该如何是好相比较优雅呢?那一个时候必要想到arguments参数是个伪数组,通过
Array.prototype.slice.call
转化为正规数组,再利用数组方法unshift,像这么:

JavaScript

function log(){ var args = Array.prototype.slice.call(arguments);
args.unshift(‘(app)’); console.log.apply(console, args); };

1
2
3
4
5
6
function log(){
  var args = Array.prototype.slice.call(arguments);
  args.unshift(‘(app)’);
 
  console.log.apply(console, args);
};

bind

说完了 apply 和 call ,再来说说bind。bind() 方法与 apply 和 call
很相似,也是足以转移函数体内 this 的指向。

MDN的说明是:bind()方法会创造一个新函数,称为绑定函数,当调用这几个绑定函数时,绑定函数会以创立它时传出 bind()方法的首先个参数作为 this,传入 bind() 方法的第三个以及随后的参数加上绑定函数运行时我的参数根据顺序作为原函数的参数来调用原函数。

平从来探视现实如何行使,在普遍的单体形式中,日常大家会选拔 _this , that
, self 等保存 this
,那样我们得以在转移了上下文之后屡次三番引用到它。 像那样:

JavaScript

var foo = { bar : 1, eventBind: function(){ var _this = this;
$(‘.someClass’).on(‘click’,function(event) { /* Act on the event */
console.log(_this.bar); //1 }); } }

1
2
3
4
5
6
7
8
9
10
var foo = {
    bar : 1,
    eventBind: function(){
        var _this = this;
        $(‘.someClass’).on(‘click’,function(event) {
            /* Act on the event */
            console.log(_this.bar);     //1
        });
    }
}

鉴于 Javascript 特有的建制,上下文环境在 eventBind:function(){ }
过渡到 $(‘.someClass’).on(‘click’,function(event)
{ }) 爆发了改变,上述使用变量保存 this 那一个方法都是实惠的,也尚未什么样难点。当然使用
bind() 可以越发文雅的解决那一个标题:

JavaScript

var foo = { bar : 1, eventBind: function(){
$(‘.someClass’).on(‘click’,function(event) { /* Act on the event */
console.log(this.bar); //1 }.bind(this)); } }

1
2
3
4
5
6
7
8
9
var foo = {
    bar : 1,
    eventBind: function(){
        $(‘.someClass’).on(‘click’,function(event) {
            /* Act on the event */
            console.log(this.bar);      //1
        }.bind(this));
    }
}

在上述代码里,bind()
成立了一个函数,当那么些click事件绑定在被调用的时候,它的 this
关键词会被设置成被盛传的值(那里指调用bind()时传出的参数)。因而,那里大家传入想要的上下文
this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候,
this 便指向 foo 对象。再来一个不难的栗子:

JavaScript

var bar = function(){ console.log(this.x); } bar(); // undefined var
func = bar.bind(foo); func(); // 3

1
2
3
4
5
6
7
var bar = function(){
    console.log(this.x);
}
 
bar(); // undefined
var func = bar.bind(foo);
func(); // 3

此地大家创建了一个新的函数 func,当使用 bind()
创造一个绑定函数之后,它被实践的时候,它的 this 会被设置成 foo ,
而不是像大家调用 bar() 时的大局功效域。

有个有意思的标题,即使连接 bind() 两遍,亦或者是连接 bind()
三遍那么输出的值是怎么着啊?像这么:

JavaScript

var bar = function(){ console.log(this.x); } var foo = { x:3 } var sed =
{ x:4 } var func = bar.bind(foo).bind(sed); func(); //? var fiv = { x:5
} var func = bar.bind(foo).bind(sed).bind(fiv); func(); //?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var bar = function(){
    console.log(this.x);
}
var foo = {
    x:3
}
var sed = {
    x:4
}
var func = bar.bind(foo).bind(sed);
func(); //?
 
var fiv = {
    x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?

答案是,五次都仍将出口 3 ,而非期待中的 4 和 5
。原因是,在Javascript中,很多次 bind() 是行不通的。更深层次的来头, bind()
的落到实处,约等于拔取函数在里边包了一个 call / apply ,第二次 bind()
相当于再包住首回 bind() ,故第二次未来的 bind 是不可以生效的。

apply、call、bind比较

那就是说 apply、call、bind 三者相比较,之间又有如何异同呢?哪一天使用
apply、call,曾几何时使用 bind 呢。简单的一个板栗:

JavaScript

var obj = { x: 81, }; var foo = { getX: function() { return this.x; } }
console.log(foo.getX.bind(obj)()); //81 console.log(foo.getX.call(obj));
//81 console.log(foo.getX.apply(obj)); //81

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
    x: 81,
};
 
var foo = {
    getX: function() {
        return this.x;
    }
}
 
console.log(foo.getX.bind(obj)());  //81
console.log(foo.getX.call(obj));    //81
console.log(foo.getX.apply(obj));   //81

多少个出口的都是81,可是注意看使用 bind() 方法的,他前边多了对括号。

也就是说,不一致是,当你指望改变上下文环境之后不要立刻实施,而是回调执行的时候,使用
bind() 方法。而 apply/call 则会及时施行函数。

再下结论一下:

  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
  • apply 、 call 、bind
    三者第三个参数都是this要本着的目的,也就是想指定的上下文;
  • apply 、 call 、bind 三者都得以应用一连参数传参;
  • bind 是再次回到对应函数,便于稍后调用;apply 、call 则是当下调用 。

正文实例出现的有所代码,在本身的github上可以下载。

打赏协助自己写出越多好文章,谢谢!

打赏作者

各位观众老爷大家好,欢迎收看底裤总动员之程序猿的IT程序大讲堂,明天给大家大饱眼福一个小知识.就是call和apple的分歧.

小编:伯乐在线专栏作者 – chokcoco

如有好文章投稿,请点击 →
这里询问详情

如需转发,发送「转发」二字查看表明

那篇小说实在是很难下笔,因为网上有关小说俯拾即是。
戏剧性的是后天看到阮老师的一篇作品的一句话:
“对自我的话,博客首先是一种知识管理工具,其次才是流传工具。我的技术小说,紧要用来整理自己还不懂的学问。我只写那么些自己还不曾完全控制的事物,那多少个自己明白的东西,往往没有动力写。炫耀没有是本身的情绪,好奇才是。”
对于那句话,无法襄助更加多,也让我下决心好好写那篇,网上文章虽多,大多复制粘贴,且晦涩难懂,我愿意能够因而那篇小说,能够清晰的升级换代对apply、call、bind的认识,并且列出一些它们的妙用加深回忆。
apply、call
在 javascript 中,call 和 apply
都是为着改变某个函数运行时的上下文(context)而留存的,换句话说,就是为着改变函数体内部
this 的指向。
JavaScript
的一大特征是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以变动的」那样的概念。
先来一个板栗:

打赏帮助我写出越来越多好小说,谢谢!

任选一种支付办法

美高梅开户网址 1
美高梅开户网址 2

2 赞 16 收藏 4
评论


 

function fruits() {};
fruits.prototype = {
    color: "red",
    say: function() {
        console.log("My color is " + this.color);
    }
}

var apple = new fruits;
apple.say();    //My color is red

至于作者:chokcoco

美高梅开户网址 3

经不住小运似水,逃可是此间少年。

个人主页 ·
我的篇章 ·
63 ·
   

美高梅开户网址 4

call和apple

在javascript中,
call和apple都是为了转移某个函数中运作的上下文(context)而存在的,换句话说就是为着转移函数内部的this的指向.

JavaScript
的一大特征是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以变更的」那样的概念。

先给大家来一个板栗: 

functionfruits() {}

fruits.prototype = {

color:”red”,

say:function() {

深刻浅出妙用。console.log(“My color is “+this.color);

}

}

varapple =newfruits;

apple.say();//My color is red

只是一旦我们有一个目的banana= {color : “yellow”} ,大家不想对它再度定义
say 方法,那么大家得以经过 call 或 apply 用 apple 的 say 方法

banana = {

color:”yellow”

}

apple.say.call(banana);//My color is yellow

apple.say.apply(banana);//My color is yellow

从而,可以看到 call 和 apply 是为了动态改变 this 而出现的,当一个 object
没有某个方法(本栗子中banana没有say方法),但是任何的有(本栗子中apple有say方法),大家可以借助call或apply用任何对象的形式来操作。


那篇小说实在是很难下笔,因为网上有关小说俯拾即是。

不过一旦大家有一个目的banana= {color : “yellow”} ,大家不想对它再一次定义
say 方法,那么大家得以经过 call 或 apply 用 apple 的 say 方法:

apply、call 的区别

对此 apply、call
二者而言,成效完全相同,只是接受参数的主意不太一致。例如,有一个函数定义如下:

varfunc =function(arg1, arg2) {

};

就可以透过如下格局来调用:

func.call(this, arg1, arg2);

func.apply(this, [arg1, arg2])

中间 this 是你想指定的上下文,他可以是任何一个 JavaScript
对象(JavaScript 中全方位皆对象),call 需求把参数按顺序传递进入,而 apply
则是把参数放在数组里。

JavaScript
中,某个函数的参数数量是不稳定的,由此要说适用条件的话,当您的参数是扎眼知晓数码时用
call 。

而不确定的时候用 apply,然后把参数 push
进数组传递进入。当参数数量不确定时,函数内部也足以经过 arguments
那几个数组来遍历所有的参数。

为了加固深化记念,下边罗列部分常用用法:

1、数组之间追加

vararray1 = [12 ,”foo”, {name”Joe”} , -2458];

vararray2 = [“Doe”, 555 , 100];

Array.prototype.push.apply(array1, array2);

/* array1 值为  [12 , “foo” , {name “Joe”} , -2458 , “Doe” , 555 ,
100] */

2、获取数组中的最大值和最小值

varnumbers = [5, 458 , 120 , -215 ];

varmaxInNumbers = Math.max.apply(Math, numbers),//458

maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215);//458

number 本身没有 max 方法,不过 Math 有,我们就足以看重 call 或者 apply
使用其方法。

3、验证是或不是是数组(前提是toString()方法没有被重写过)

functionisArray(obj){

return Object.prototype.toString.call(obj) ==='[object Array]’;

}

4、类(伪)数组使用数组方法

vardomNodes =
Array.prototype.slice.call(document.getElementsByTagName(“*”));

Javascript中设有一种名为伪数组的对象协会。相比特其余是 arguments

对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们重回NodeList对象都属

于伪数组。不可以运用 Array下的 push , pop 等措施。

可是大家能经过 Array.prototype.slice.call 转换为真正的数组的带有 length
属性的靶子,这样 domNodes 就足以选用 Array 下的具有办法了。


 

banana = {
    color: "yellow"
}
apple.say.call(banana);     //My color is yellow
apple.say.apply(banana);    //My color is yellow

深入精晓运用apply、call

下面就借用一道面课题,来更尖锐的去领略下
apply 和 call 。

概念一个 log 方法,让它可以代劳 console.log 方法,常见的缓解措施是:

functionlog(msg) {

console.log(msg);

}

log(1);//1

log(1,2);//1

上边方法可以解决最要旨的急需,不过当传入参数的个数是不确定的时候,上边的方法就失效了,那么些时候就足以考虑拔取apply 或者
call,注意那里流传多少个参数是不确定的,所以选用apply是最好的,方法如下:

functionlog(){

console.log.apply(console, arguments);

};

log(1);//1

log(1,2);//1 2

接下去的渴求是给每一个 log 新闻添加一个”(app)”的前辍,比如:

log(“hello world”);//(app)hello world

该怎么办相比优雅呢?这一个时候须要想到arguments参数是个伪数组,通过
Array.prototype.slice.call
转化为专业数组,再利用数组方法unshift,像那样:

functionlog(){

varargs = Array.prototype.slice.call(arguments);

args.unshift(‘(app)’);

console.log.apply(console, args);

};


偶合的是今天看到阮老师的一篇文章的一句话:

所以,可以见见 call 和 apply 是为了动态改变 this 而产出的,当一个 object
没有某个方法(本栗子中banana没有say方法),然则任何的有(本栗子中apple有say方法),我们可以借助call或apply用此外对象的法门来操作。
apply、call 的区别
对于 apply、call
二者而言,功效完全相同,只是接受参数的格局不太相同。例如,有一个函数定义如下:

bind

说完了 apply 和 call ,再来说说bind。bind() 方法与 apply 和 call
很相像,也是可以变动函数体内 this 的指向。

MDN的讲演是:bind()方法会创建一个新函数,称为绑定函数,当调用这几个绑定函数时,绑定函数会以创办它时传出 bind()方法的第二个参数

作为 this,传入 bind() 方法的第一个以及随后的参数加上绑定函数运行时自我的参数根据顺序作为原函数的参数来调用原函数。

从来来探视具体怎样行使,在大规模的单体方式中,平日大家会选用 _this , that
, self 等保存 this
,那样我们得以在转移了上下文之后持续引用到它。 像那样:

varfoo = {

bar : 1,

eventBind:function(){

var _this =this;

$(‘.someClass’).on(‘click’,function(event) {

/* Act on the event */

console.log(_this.bar);//1

});

}

}

出于 Javascript 特有的机制,上下文环境在 eventBind:function(){ }

接通到 $(‘.someClass’).on(‘click’,function(event) { })
暴发了转移,上述使用变量保存

this 那些方法都是实用的,也绝非怎么难题。当然使用 bind()
可以进一步高雅的化解那么些难题:

varfoo = {

bar : 1,

eventBind:function(){

$(‘.someClass’).on(‘click’,function(event) {

/* Act on the event */

console.log(this.bar);//1

}.bind(this));

}

}

在上述代码里,bind()
创设了一个函数,当以此click事件绑定在被调用的时候,它的 this

重在词会被设置成被传出的值(这里指调用bind()时传出的参数)。因而,那里大家传入想要的前后文
this(其实就是 foo ),到

bind() 函数中。然后,当回调函数被实施的时候, this
便指向 foo 对象。再来一个简单的栗子:

var bar =function(){

console.log(this.x);

}

var foo = {

x:3

}

bar();// undefined

var func = bar.bind(foo);

func();// 3

此间大家创制了一个新的函数 func,当使用 bind()
创造一个绑定函数之后,它被实践的时候,它的 this 会被设置成 foo ,
而不是像大家调用 bar() 时的全局功效域。

有个好玩的难点,假如总是 bind() 一次,亦或者是连连 bind()
三回那么输出的值是何许吗?像这么:

varbar =function(){

console.log(this.x);

}

var foo = {

x:3

}

var sed = {

x:4

}

var func = bar.bind(foo).bind(sed);

func();//?

var fiv = {

x:5

}

var func = bar.bind(foo).bind(sed).bind(fiv);

func();//?

答案是,两遍都仍将出口 3 ,而非期待中的 4 和 5
。原因是,在Javascript中,数十次 bind()

是无效的。更深层次的原由, bind() 的贯彻,约等于接纳函数在中间包了一个
call / apply ,第二次 bind()

约等于再包住第三回 bind() ,故第二次之后的 bind 是无力回天生效的。


“对自我来说,博客首先是一种文化管理工具,其次才是传播工具。我的技艺文章,主要用来打点自己还不懂的知识。我只写那多少个自己还未曾完全驾驭的东西,那多少个自己明白的事物,往往没有引力写。炫耀没有是自身的动机,好奇才是。”

var func = function(arg1, arg2) {

apply、call、bind比较

那就是说 apply、call、bind 三者相相比较,之间又有怎么着异同呢?什么日期使用
apply、call,曾几何时使用 bind 呢。不难的一个板栗:

var obj = {

x: 81,

};

var foo = {

getX:function() {

return this.x;

}

}

console.log(foo.getX.bind(obj)());//81

console.log(foo.getX.call(obj));//81

console.log(foo.getX.apply(obj));//81

几个出口的都是81,可是注意看使用 bind() 方法的,他背后多了对括号。

也就是说,不相同是,当您愿意改变上下文环境之后并非马上执行,而是回调执行的时候,使用
bind() 方法。而 apply/call 则会应声实施函数。

再统计一下:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

apply 、 call 、bind
三者第三个参数都是this要针对性的靶子,也就是想指定的上下文;

apply 、 call 、bind 三者都足以利用三番五次参数传参;

bind 是再次回到对应函数,便于稍后调用;apply 、call 则是当下调用 。

 

};
就足以由此如下格局来调用:

对于那句话,不可以接济越来越多,也让自家下决心好好写那篇,网上小说虽多,大多复制粘贴,且晦涩难懂,我期待可以通过那篇小说,能够清晰的升级换代对apply、call、bind的认识,并且列出有些它们的妙用加深记念。

func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
内部 this 是你想指定的上下文,他得以是其余一个 JavaScript
对象(JavaScript 中整体皆对象),call 须要把参数按梯次传递进入,而 apply
则是把参数放在数组里。
JavaScript
中,某个函数的参数数量是不固定的,由此要说适用原则的话,当您的参数是尽人皆知明白数据时用
call 。
而不确定的时候用 apply,然后把参数 push
进数组传递进入。当参数数量不确定时,函数内部也足以透过 arguments
那些数组来遍历所有的参数。
为了加固深化回想,下边列举部分常用用法:
1、数组之间追加

 

var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为  [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

apply、call

2、获取数组中的最大值和最小值

 

var  numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers),   //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

在 javascript 中,call 和 apply
都是为着改变某个函数运行时的上下文(context)而留存的,换句话说,就是为了改变函数体内部
this 的针对。

number 本身并未 max 方法,可是 Math 有,大家就可以依靠 call 或者 apply
使用其方法。

 

3、验证是不是是数组(前提是toString()方法没有被重写过)

JavaScript
的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」那样的定义。

functionisArray(obj){
return Object.prototype.toString.call(obj) === ‘[object Array]’ ;
}
4、类(伪)数组使用数组方法

 

var domNodes =
Array.prototype.slice.call(document.getElementsByTagName(“*”));
Javascript中留存一种名为伪数组的靶子社团。比较特其他是 arguments
对象,还有像调用 getElementsByTagName , document.childNodes
之类的,它们再次回到NodeList对象都属于伪数组。无法拔取 Array下的 push , pop
等办法。
但是大家能经过 Array.prototype.slice.call 转换为实在的数组的含有 length
属性的目标,那样 domNodes 就可以选拔 Array 下的兼具办法了。
深刻驾驭运用apply、call
上面就借出一道面课题,来更深入的去精通下 apply 和 call 。
概念一个 log 方法,让它可以代办 console.log 方法,常见的解决办法是:

先来一个板栗:

function log(msg) {
  console.log(msg);
}
log(1);    //1
log(1,2);    //1

 

上边方法可以解决最中央的急需,不过当传入参数的个数是不确定的时候,下面的艺术就失效了,这些时候就足以设想动用
apply 或者
call,注意这里流传多少个参数是不确定的,所以选取apply是最好的,方法如下:

function fruits() {}

 

fruits.prototype = {

color: “red”,

say: function() {

console.log(“My color is ” + this.color);

}

}

 

var apple = new fruits;

apple.say(); //My color is red

function log(){
  console.log.apply(console, arguments);
};
log(1);    //1
log(1,2);    //1 2

 

接下去的渴求是给每一个 log 音信添加一个”(app)”的前辍,比如:
log(“hello world”); //(app)hello world
该怎么办相比优雅呢?那些时候必要想到arguments参数是个伪数组,通过
Array.prototype.slice.call
转化为正规数组,再使用数组方法unshift,像这么:

可是假设大家有一个目标banana= {color : “yellow”} ,大家不想对它再一次定义
say 方法,那么大家得以经过 call 或 apply 用 apple 的 say 方法:

function log(){
  var args = Array.prototype.slice.call(arguments);
  args.unshift('(app)');

  console.log.apply(console, args);
};

 

bind
说完了 apply 和 call ,再来说说bind。bind() 方法与 apply 和 call
很相似,也是足以变更函数体内 this 的指向。
MDN的解说是:bind()方法会创造一个新函数,称为绑定函数,当调用这几个绑定函数时,绑定函数会以创造它时传出
bind()方法的首先个参数作为 this,传入 bind()
方法的第一个以及之后的参数加上绑定函数运行时我的参数按照顺序作为原函数的参数来调用原函数。
一直来探视现实怎样利用,在大面积的单体方式中,平常大家会动用 _this , that
, self 等保存 this ,那样大家得以在转移了上下文之后再三再四引用到它。
像那样:

banana = {

color: “yellow”

}

apple.say.call(banana); //My color is yellow

apple.say.apply(banana); //My color is yellow

var foo = {
    bar : 1,
    eventBind: function(){
        var _this = this;
        $('.someClass').on('click',function(event) {
            /* Act on the event */
            console.log(_this.bar);     //1
        });
    }
}

 

鉴于 Javascript 特有的建制,上下文环境在 eventBind:function(){ } 过渡到
$(‘.someClass’).on(‘click’,function(event) { })
发生了改变,上述使用变量保存 this
那个方法都是可行的,也一贯不什么样难题。当然使用 bind()
可以越发文雅的解决那个标题:

从而,可以阅览 call 和 apply 是为了动态改变 this 而出现的,当一个 object
没有某个方法(本栗子中banana没有say方法),不过任何的有(本栗子中apple有say方法),大家可以依靠call或apply用别样对象的形式来操作。

var foo = {
    bar : 1,
    eventBind: function(){
        $('.someClass').on('click',function(event) {
            /* Act on the event */
            console.log(this.bar);      //1
        }.bind(this));
    }
}

 

在上述代码里,bind()
创设了一个函数,当那么些click事件绑定在被调用的时候,它的 this
关键词会被设置成被流传的值(那里指调用bind()时传出的参数)。因而,这里我们传入想要的光景文
this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被实施的时候,
this 便指向 foo 对象。再来一个不难的栗子:

apply、call 的区别

var bar = function(){
    console.log(this.x);
}

bar(); // undefined
var func = bar.bind(foo);
func(); // 3

 

那边大家成立了一个新的函数 func,当使用 bind()
创立一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo ,
而不是像我们调用 bar() 时的大局效能域。
apply、call、bind比较
那么 apply、call、bind 三者相相比,之间又有何样异同呢?曾几何时使用
apply、call,哪一天使用 bind 呢。简单的一个板栗:

对于 apply、call
二者而言,功用完全相同,只是接受参数的不二法门不太一样。例如,有一个函数定义如下:

var obj = {
    x: 81,
};

var foo = {
    getX: function() {
        return this.x;
    }
}

console.log(foo.getX.bind(obj)());  //81
console.log(foo.getX.call(obj));    //81
console.log(foo.getX.apply(obj));   //81

 

五个出口的都是81,不过注意看使用 bind() 方法的,他背后多了对括号。
也就是说,不一样是,当您愿意改变上下文环境之后并非立时实施,而是回调执行的时候,使用
bind() 方法。而 apply/call 则会应声施行函数。
再总括一下:
* apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
* apply 、 call 、bind
三者第三个参数都是this要本着的目标,也就是想指定的上下文;
* apply 、 call 、bind 三者都得以利用三番五次参数传参;
* bind 是回来对应函数,便于稍后调用;apply 、call 则是及时调用 。

var func = function(arg1, arg2) {

 

};

 

就可以通过如下格局来调用:

 

func.call(this, arg1, arg2);

func.apply(this, [arg1, arg2])

 

中间 this 是你想指定的上下文,他可以是其余一个 JavaScript
对象(JavaScript 中任何皆对象),call 要求把参数按顺序传递进入,而 apply
则是把参数放在数组里。  

 

JavaScript
中,某个函数的参数数量是不稳定的,因而要说适用标准的话,当您的参数是肯定知道数据时用
call 。

 

而不确定的时候用 apply,然后把参数 push
进数组传递进入。当参数数量不确定时,函数内部也足以因此 arguments
那些数组来遍历所有的参数。

 

为了巩固深化纪念,下边罗列部分常用用法:

 

1、数组之间追加

 

var array1 = [12 , “foo” , {name “Joe”} , -2458];

var array2 = [“Doe” , 555 , 100];

Array.prototype.push.apply(array1, array2);

/* array1 值为 [12 , “foo” , {name “Joe”} , -2458 , “Doe” , 555 ,
100] */

 

2、获取数组中的最大值和最小值

 

var numbers = [5, 458 , 120 , -215 ];

var maxInNumbers = Math.max.apply(Math, numbers), //458

maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

 

number 本身并未 max 方法,可是 Math 有,我们就可以凭借 call 或者 apply
使用其格局。

 

3、验证是或不是是数组(前提是toString()方法没有被重写过)

 

functionisArray(obj){

    returnObject.prototype.toString.call(obj) === ‘[object Array]’ ;

}

 

4、类(伪)数组使用数组方法

 

var domNodes = Array.prototype.slice.call(document.getElementsByTagName(“*”));

 

Javascript中设有一种名为伪数组的对象协会。相比越发的是 arguments
对象,还有像调用 getElementsByTagName , document.childNodes
之类的,它们再次回到NodeList对象都属于伪数组。不可以使用 Array下的 push , pop
等方法。

 

但是我们能通过 Array.prototype.slice.call 转换为确实的数组的盈盈 length
属性的靶子,那样 domNodes 就足以利用 Array 下的具备办法了。

 

深切掌握运用apply、call

 

上边就借出一道面试题,来更深远的去了解下 apply 和 call 。

 

概念一个 log 方法,让它可以代劳 console.log 方法,常见的解决方法是:

 

function log(msg) {

    console.log(msg);

}

log(1); //1

log(1,2); //1

 

地点方法可以缓解最基本的必要,可是当传入参数的个数是不确定的时候,上边的措施就失效了,这几个时候就足以考虑拔取apply 或者
call,注意那里流传多少个参数是不确定的,所以利用apply是最好的,方法如下:

 

function log(){

    console.log.apply(console, arguments);

};

log(1); //1

log(1,2); //1 2

 

接下去的渴求是给每一个 log 音信添加一个”(app)”的前辍,比如:

 

log(“hello world”); //(app)hello world

 

该如何是好比较优雅呢?那些时候须要想到arguments参数是个伪数组,通过
Array.prototype.slice.call
转化为业内数组,再使用数组方法unshift,像那样:

 

function log(){

    var args = Array.prototype.slice.call(arguments);

    args.unshift(‘(app)’);

 

    console.log.apply(console, args);

};

 

bind

 

说完了 apply 和 call ,再来说说bind。bind() 方法与 apply 和 call
很一般,也是足以变更函数体内 this 的针对性。

 

MDN的分解是:bind()方法会创设一个新函数,称为绑定函数,当调用这么些绑定函数时,绑定函数会以创办它时传出
bind()方法的第二个参数作为 this,传入 bind()
方法的第四个以及之后的参数加上绑定函数运行时自我的参数根据顺序作为原函数的参数来调用原函数。

 

直接来看望实际什么行使,在大规模的单体形式中,日常我们会选取 _this , that
, self 等保存 this ,那样我们可以在转移了上下文之后继续引用到它。
像那样:

 

var foo = {

bar : 1,

eventBind: function(){

var _this = this;

$(‘.someClass’).on(‘click’,function(event) {

/* Act on the event */

console.log(_this.bar); //1

});

}

}

 

由于 Javascript 特有的建制,上下文环境在 eventBind:function(){ } 过渡到
$(‘.someClass’).on(‘click’,function(event) { })
发生了改观,上述使用变量保存 this
这个点子都是一蹴而就的,也从未什么难题。当然使用 bind()
可以更进一步高雅的缓解那一个题材:

 

var foo = {

bar : 1,

eventBind: function(){

$(‘.someClass’).on(‘click’,function(event) {

/* Act on the event */

console.log(this.bar); //1

}.bind(this));

}

}

 

在上述代码里,bind()
创立了一个函数,当那个click事件绑定在被调用的时候,它的 this
关键词会被设置成被传到的值(这里指调用bind()时传出的参数)。由此,那里大家传入想要的内外文
this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候,
this 便指向 foo 对象。再来一个不难的栗子:

 

var bar = function(){

console.log(this.x);

}

 

bar(); // undefined

var func = bar.bind(foo);

func(); // 3

 

此间大家创造了一个新的函数 func,当使用 bind()
成立一个绑定函数之后,它被实践的时候,它的 this 会被设置成 foo ,
而不是像我们调用 bar() 时的大局成效域。

 

有个有意思的难题,如若一而再 bind() 三遍,亦或者是连连 bind()
三遍那么输出的值是哪些啊?像这么:

 

var bar = function(){

console.log(this.x);

}

var foo = {

x:3

}

var sed = {

x:4

}

var func = bar.bind(foo).bind(sed);

func(); //?

 

var fiv = {

x:5

}

var func = bar.bind(foo).bind(sed).bind(fiv);

func(); //?

 

答案是,一次都仍将出口 3 ,而非期待中的 4 和 5
。原因是,在Javascript中,多次 bind() 是船到江心补漏迟的。更深层次的来头, bind()
的完结,相当于接纳函数在中间包了一个 call / apply ,第二次 bind()
相当于再包住首回 bind() ,故第二次之后的 bind 是力不从心生效的。

 

apply、call、bind比较

 

那么 apply、call、bind 三者相比较,之间又有怎样异同呢?哪天使用
apply、call,曾几何时使用 bind 呢。简单的一个板栗:

 

var obj = {

x: 81,

};

 

var foo = {

getX: function() {

return this.x;

}

}

 

console.log(foo.getX.bind(obj)()); //81

console.log(foo.getX.call(obj)); //81

console.log(foo.getX.apply(obj)); //81

 

三个出口的都是81,不过注意看使用 bind() 方法的,他背后多了对括号。

 

也就是说,不一致是,当您愿意改变上下文环境之后并非马上执行,而是回调执行的时候,使用
bind() 方法。而 apply/call 则会即时实施函数。

 

再统计一下:

 

  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

  • apply 、 call 、bind
    三者第二个参数都是this要本着的靶子,也就是想指定的上下文;

  • apply 、 call 、bind 三者都足以动用三番五次参数传参;

  • bind是再次来到对应函数,便于稍后调用;apply、call则是即时调用 。

 

正文实例出现的有所代码,在自身的github上得以下载。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图