菜单

妙用Javascript中apply、call、bind

2018年12月15日 - 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地图