菜单

妙用Javascript中apply、call、bind

2018年12月14日 - JavaScript

淡雅的数组降维——Javascript中apply方法的妙用

2016/02/18 · JavaScript
· apply,
数组

原稿出处:
ralph_zhu   

拿多维数组(尤其是二维数组)转化为平维数组是业务支出被的常用逻辑,除了接纳节能的轮回转换以外,我们还好动用Javascript的言语特色实现更精简优雅的变。本文将由省的轮回转换起先,逐一介绍两种常用的转换方法,并借这简单回顾Array.prototype.concat方法以及Function.prototype.apply方法。
以下代码用因管二维数组降维到平等维数组为例。

  1. 省吃俭用的更换

JavaScript

function reduceDimension(arr) { var reduced = []; for (var i = 0; i
< arr.length; i++) { for (var j = 0; j < arr[i].length; j++) {
reduced.push(arr[i][j]); } } return reduced; }

1
2
3
4
5
6
7
8
9
function reduceDimension(arr) {
    var reduced = [];
    for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j < arr[i].length; j++) {
            reduced.push(arr[i][j]);
        }
    }
    return reduced;
}

斯方法思路简单,利用还循环遍历二维数组中的每个元素并置于新数组中。

 

  1. 利用concat转换
    事先来回顾一下MDN上对此拖欠方法的介绍:
    “concat creates a new array consisting of the elements in the object on
    which it is called, followed in order by, for each argument, the
    elements of that argument (if the argument is an array) or the argument
    itself (if the argument is not an array).”
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

就是只要concat方法的参数是一个因素,该因素会于直接插入到新数组中;即使参数是一个频组,该数组的逐条要素用被插入到新数组中;将拖欠特性应用到代码中:

JavaScript

function reduceDimension(arr) { var reduced = []; for (var i = 0; i
< arr.length; i++){ reduced = reduced.concat(arr[i]); } return
reduced; }

1
2
3
4
5
6
7
function reduceDimension(arr) {
    var reduced = [];
    for (var i = 0; i < arr.length; i++){
        reduced = reduced.concat(arr[i]);
    }
    return reduced;
}

arr的各个一个因素仍旧一个频繁组,作为concat方法的参数,数组中的诸一个子元素又都会晤受单独插入进新数组。
运用concat方法,我们拿重循环简化为了单重循环。

 

  1. 利用apply和concat转换
    以常规,先来回顾一下MDN上于apply方法的介绍:
    “The apply() method calls a function with a given this value and
    arguments provided as an array.”

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

即apply方法会调用一个函数,apply方法的首先个参数会当为调用函数的this值,apply方法的次只参数(一个勤组,或类数组的对象)会当为调用对象的arguments值,也就是说该数组的依次要素以碰面挨个成为深受调用函数的顺序参数;将该特性应用及代码中:

function reduceDimension(arr) { return
Array.prototype.concat.apply([], arr); }

1
2
3
function reduceDimension(arr) {
    return Array.prototype.concat.apply([], arr);
}

arr作为apply方法的老二个参数,本身是一个数组,数组中的各国一个要素(如故反复组,即二维数组的亚维)会让视作参数依次传入到concat中,效果等同于[].concat([1,2],
[3,4], [5,6])。
运用apply方法,我们拿单重循环优化为了一行代码,很简单有型有木有啊~

读者也不过参考本文思路,自己运递归实现N维数组降维的逻辑。

3 赞 8 收藏
评论

图片 1

本着apply、call、bind的认,并且列有部分其的妙用加深记念。

 

   apply、call 

以 javascript 中,call 和 apply
都是为了改变有函数运行时之上下文(context)而存在的,换句话说,就是为转移函数体内部
this 的针对性。

JavaScript
的同等老大特色是,函数存在「定义时达下文」和「运行时达下文」以及「上下文是好转的」那样的定义。

事先来一个板栗:

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 方法:

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
二者而言,功用了同,只是接受参数的法不顶相同。例如,有一个函数定义如下:

1
2
3
var func = function(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
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] */

获取数组中之太酷价值与最好小值

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
使用其法。

证是否是数组(前提是toString()方法无于再写过)

1
2
3
functionisArray(obj){ 
    return Object.prototype.toString.call(obj) === '[object Array]' ;
}

类似(伪)数组使用数组方法

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 方法,常见的缓解智是:

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

地点方法可以解决最主题的需,可是当传入参数的个数是免确定的当儿,下面的道就失效了,那一个时节就是足以设想动用
apply 或者
call,注意这里传出多少个参数是勿确定的,所以下apply是极致好之,方法如下:

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

连通下去的求是给各国一个 log 音信添加一个”(app)”的前辍,比如:

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

该怎么开比优雅也?那个时刻用想到arguments参数是个伪数组,通过
Array.prototype.slice.call
转化为专业往往组,再利用数组方法unshift,像这么:

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
,这样我们可于转移了上下文之后连续引用到其。 像这样:

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()可以进一步文雅的化解之题目:

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 对象。再来一个简单的栗子:

1
2
3
4
5
6
7
8
9
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()三涂鸦那么输出的价是啊呢?像这样:

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 呢。简单的一个板栗:

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 则会立即执行函数。

 

重新总结一下:

 原文出处:http://www.cnblogs.com/coco1s/p/4833199.html

 

相关文章

发表评论

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

网站地图xml地图