澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站优雅的数组降维,js将类数组

2019-06-08 作者:澳门新萄京赌场网址   |   浏览(173)

优雅的数组降维——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).”

即如果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.”

即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

在标准浏览器中,好像只要对象存在length属性,就能把它转换为数组,但IE就不尽然。

1.indexOf和lastIndexOf方法:

javascript框架设计读书笔记之数组的扩展与修复,javascript读书笔记

1.indexOf和lastIndexOf方法:

因为IE7在数组对象上使用indexOf会报错,所以需要重写一个兼容性的。

复制代码 代码如下:

Array.prototype.lastIndexOf(item,index){
  var n = this.length,i = (index==null||index>n-1)?n-1:index;
  if(i < 0) i = n i;
  for(;i>=0;i--)
    if(this[i] === item)   //全等判断,indexOf,lastIndexOf
      return i;
  return -1;
}

2.shuffle方法:对数组进行洗牌。

复制代码 代码如下:

function shuffle(target){
  var i = target.length, j ,temp;
  for(;i>0;j=parseInt(Math.random() * i), x = target[--i],target[i] = target[j],target[j]=x){}   
     //假设length=10,那么Math.random()*10->[0,10),parseInt后,[0,9],随机的选择一个与数组最后一项交换。第二次循环,[0,8],与数组的倒数第二项交换。
  return target;
}

3.数组的平坦化处理:flatten,返回一个一维数组

复制代码 代码如下:

function flatten(arr){
  var result = [];
  arr.forEach(function(item){
    if(Array.isArray(item))   result.concat(flatten(item));
    else  result.push(item);
  });
  return result;
}

4.unique方法:对数组去重操作

此方法,面试官最喜欢问了,因为它有多种实现方法,最普通的是两个for循环。一般知道的最多的是使用一个对象a,然后一个for循环数组arr,每次if(a[arr[i]])是否存在,不存在则push到你新定义的数组result中。存在就证明,重复,因此不用push到result中。这种方案,针对"123",123,会认为相同的,其实一个是字符串,一个是数字,不应该认为是相同的。

所以就出现了以下方法:[1,"1","1"]

复制代码 代码如下:

 if ((typeof obj[array[i]]) != (typeof array[i]) || obj[array[i]] != array[i]) {
  a.push(array[i]);
  obj[array[i]] = array[i];
}

//首先判断类型是否相同,如果相同,就判断他们的值是否相等,不相等就存进去,相等就证明之前已经存在这个值了。

如果类型不相同,这里存在两种情况,

第一种情况,obj之前已经存了此数据了,比如:obj[123] = 123,现在array[i] = "123",这时,typeof obj[array[i]])是数字,而typeof array[i]是字符串,因此存入数组中。

第二种情况是obj还没存此数据,比如:array[i] = "123",obj["123"] = undefind,这时typeof obj[array[i]])就是typeof undefined = undefined,不等于typeof array[i],存入数组中。

此种方法,可以解决字符串和数字相同的情况,但是无法解决对象相同的情况。比如:a = {1:2}, b ={2:1};

第一次循环时,typeof obj[a] = undefined,typeof a = Object。存入obj[a] =a.其实就是obj[Object] = a;

第二次循环时,typeof obj[b] 等于typeof obj[Object]其实就是typeof a = object,typeof b = object.因此进入到obj[array[i]] != array[i]|,也就是obj[b]->obj[Object]->a != b,因此存入

obj[b] = b;也就是obj[Object] = b;覆盖了之前的obj[Object] = a;

这种情况下,就会出现所有的对象,都只会存最后一个对象值。

当考虑对象时,我就会使用以下这种方法:

复制代码 代码如下:

for(var i = 0; i < temp.length; i ){
                for(var j = i 1; j < temp.length; j ){
                        if(temp[i] === temp[j]){
                                temp.splice( j, 1 );
                                j--;
                        }
                }
        }
 return temp;

5.数组排序:sort方法,如果要排序的是对象,可以自己写一个compare(a,b){if(a.age>b.age) return 1;else return -1;},A.sort(compare).

6.min返回数组最小值:return Math.min.apply(0,array);

7.unshift在ie6,7下不返回数组长度。

复制代码 代码如下:

if([].unshift(1)!==1)   //往空数组中从前面添加一项,其他浏览器会返回1,而IE6,7不会返回数组长度。这时就执行if语句
{
  var _unshift = Array.prototype.unshift;      //函数劫持。
  Array.prototype.unshift = function(){
    _unshift.apply(this,arguments);
    return this.length;
  }
}

8.splice在一个参数的情况下,IE8以及以下版本默认第二个参数为0,而其他浏览器是数组长度。

复制代码 代码如下:

if([1,2,3].splice(1).length == 0)   //IE8以及以下版本会等于0,其他版本会等于3,进入if里面
{
  var _splice = Array.prototype.splice;
  Array.prototype.splice = function(a){
    if(arguments.length == 1)   //如果只有一个参数时
    {
      return _splice.call(this,a,this.length);
    }else{
      return _splice.apply(this,arguments);
    }
  }
}

这个方法会改变数组的选项,因此数组的push,pop,shift,unshift(这几个方法也会修改数组的选项)都会调用这个方法来实现。

这里有一个地方需要注意:

复制代码 代码如下:

var color = new Array('red','blue','yellow','black');
var color2 = color.splice(2,0,'brown','pink');
alert(color); // red,blue,brown,pink,yellow,black,在yellow选项上,开始操作,如果删除为0,则添加的选项是在yellow之前插入。切记。

 
这里请大家去看下splice和slice的区别,返回值,以及对原数组的影响。

以上就是本节的内容的精简版了,虽然精简,但重点都在,希望对大家阅读本节的时候能有所帮助

1.indexOf和lastIndexOf方法: 因为IE7在数组对象上使用indexOf会报错,所以需要...

在标准浏览器中,好像只要对象存在length属性,就能把它转换为数组,但IE就不尽然。

[Ctrl A 全选 注:如需引入外部Js需刷新才能执行]

因为IE7在数组对象上使用indexOf会报错,所以需要重写一个兼容性的。

[Ctrl A 全选 注:如需引入外部Js需刷新才能执行]

接着我们看看各大类库的处理:

复制代码 代码如下:

接着我们看看各大类库的处理:

复制代码 代码如下:

Array.prototype.lastIndexOf(item,index){
  var n = this.length,i = (index==null||index>n-1)?n-1:index;
  if(i < 0) i = n i;
  for(;i>=0;i--)
    if(this[i] === item)   //全等判断,indexOf,lastIndexOf
      return i;
  return -1;
}

复制代码 代码如下:

//jQuery的makeArray
var makeArray = function( array ) {
var ret = [];
if( array != null ){
var i = array.length;
// The window, strings (and functions) also have 'length'
if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
ret[0] = array;
else
while( i )
ret[--i] = array[i];
}
return ret;
}

2.shuffle方法:对数组进行洗牌。

//jQuery的makeArray
var makeArray = function( array ) {
var ret = [];
if( array != null ){
var i = array.length;
// The window, strings (and functions) also have 'length'
if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
ret[0] = array;
else
while( i )
ret[--i] = array[i];
}
return ret;
}

jQuery对象是用来储存与处理dom元素的,它主要依赖于setArray方法来设置与维护长度与索引,而setArray的参数要求是一个数组,因此makeArray的地位非常重要。这方法保证就算没有参数也要返回一个空数组。
Prototype.js的$A方法

复制代码 代码如下:

jQuery对象是用来储存与处理dom元素的,它主要依赖于setArray方法来设置与维护长度与索引,而setArray的参数要求是一个数组,因此makeArray的地位非常重要。这方法保证就算没有参数也要返回一个空数组。
Prototype.js的$A方法

复制代码 代码如下:

function shuffle(target){
  var i = target.length, j ,temp;
  for(;i>0;j=parseInt(Math.random() * i), x = target[--i],target[i] = target[j],target[j]=x){}   
     //假设length=10,那么Math.random()*10->[0,10),parseInt后,[0,9],随机的选择一个与数组最后一项交换。第二次循环,[0,8],与数组的倒数第二项交换。
  return target;
}

复制代码 代码如下:

function $A(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}

3.数组的平坦化处理:flatten,返回一个一维数组

function $A(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}

mootools的$A方法

复制代码 代码如下:

mootools的$A方法

复制代码 代码如下:

function flatten(arr){
  var result = [];
  arr.forEach(function(item){
    if(Array.isArray(item))   result.concat(flatten(item));
    else  result.push(item);
  });
  return result;
}

复制代码 代码如下:

function $A(iterable){
if (iterable.item){
var l = iterable.length, array = new Array(l);
while (l--) array[l] = iterable[l];
return array;
}
return Array.prototype.slice.call(iterable);
};

4.unique方法:对数组去重操作

function $A(iterable){
if (iterable.item){
var l = iterable.length, array = new Array(l);
while (l--) array[l] = iterable[l];
return array;
}
return Array.prototype.slice.call(iterable);
};

Ext的toArray方法

此方法,面试官最喜欢问了,因为它有多种实现方法,最普通的是两个for循环。一般知道的最多的是使用一个对象a,然后一个for循环数组arr,每次if(a[arr[i]])是否存在,不存在则push到你新定义的数组result中。存在就证明,重复,因此不用push到result中。这种方案,针对"123",123,会认为相同的,其实一个是字符串,一个是数字,不应该认为是相同的。

Ext的toArray方法

复制代码 代码如下:

所以就出现了以下方法:[1,"1","1"]

复制代码 代码如下:

var toArray = function(){
return isIE ?
function(a, i, j, res){
res = [];
Ext.each(a, function(v) {
res.push(v);
});
return res.slice(i || 0, j || res.length);
} :
function(a, i, j){
return Array.prototype.slice.call(a, i || 0, j || a.length);
}
}()

复制代码 代码如下:

var toArray = function(){
return isIE ?
function(a, i, j, res){
res = [];
Ext.each(a, function(v) {
res.push(v);
});
return res.slice(i || 0, j || res.length);
} :
function(a, i, j){
return Array.prototype.slice.call(a, i || 0, j || a.length);
}
}()

Ext的设计比较巧妙,功能也比较强大。它一开始就自动执行自身,以后就不用判定浏览器了。它还有两个可选参数,对生成的纯数组进行操作。
最后看dojo的_toArray,dojo的实现总是那么怪异的。 和Ext一样,后面两个参数是可选,只不过第二个是偏移量,最后一个是已有的数组,用于把新生的新组元素合并过去。

 if ((typeof obj[array[i]]) != (typeof array[i]) || obj[array[i]] != array[i]) {
  a.push(array[i]);
  obj[array[i]] = array[i];
}

Ext的设计比较巧妙,功能也比较强大。它一开始就自动执行自身,以后就不用判定浏览器了。它还有两个可选参数,对生成的纯数组进行操作。
最后看dojo的_toArray,dojo的实现总是那么怪异的。 和Ext一样,后面两个参数是可选,只不过第二个是偏移量,最后一个是已有的数组,用于把新生的新组元素合并过去。

复制代码 代码如下:

//首先判断类型是否相同,如果相同,就判断他们的值是否相等,不相等就存进去,相等就证明之前已经存在这个值了。

复制代码 代码如下:

(function(){
var efficient = function(obj, offset, startWith){
return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
};
var slow = function(obj, offset, startWith){
var arr = startWith||[];
for(var x = offset || 0; x >obj.length; x ){
arr.push(obj[x]);
}
return arr;
};
dojo._toArray =
dojo.isIE ? function(obj){
return ((obj.item) ? slow : efficient).apply(this, arguments);
} :
efficient;
})();

如果类型不相同,这里存在两种情况,

(function(){
var efficient = function(obj, offset, startWith){
return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
};
var slow = function(obj, offset, startWith){
var arr = startWith||[];
for(var x = offset || 0; x >obj.length; x ){
arr.push(obj[x]);
}
return arr;
};
dojo._toArray =
dojo.isIE ? function(obj){
return ((obj.item) ? slow : efficient).apply(this, arguments);
} :
efficient;
})();

您可能感兴趣的文章:

  • JavaScript中的类数组对象介绍
  • JavaScript 里的类数组对象
  • js 用于检测类数组对象的函数方法
  • JQuery $.each遍历JavaScript数组对象实例
  • js使用Array.prototype.sort()对数组对象排序的方法
  • js接收并转化Java中的数组对象的方法
  • JS从非数组对象转数组的方法小结
  • javascript Array数组对象的扩展函数代码
  • JavaScript类数组对象转换为数组对象的方法实例分析

第一种情况,obj之前已经存了此数据了,比如:obj[123] = 123,现在array[i] = "123",这时,typeof obj[array[i]])是数字,而typeof array[i]是字符串,因此存入数组中。

[Ctrl A 全选 注:如需引入外部Js需刷新才能执行] 接着我...

第二种情况是obj还没存此数据,比如:array[i] = "123",obj["123"] = undefind,这时typeof obj[array[i]])就是typeof undefined = undefined,不等于typeof array[i],存入数组中。

此种方法,可以解决字符串和数字相同的情况,但是无法解决对象相同的情况。比如:a = {1:2}, b ={2:1};

第一次循环时,typeof obj[a] = undefined,typeof a = Object。存入obj[a] =a.其实就是obj[Object] = a;

第二次循环时,typeof obj[b] 等于typeof obj[Object]其实就是typeof a = object,typeof b = object.因此进入到obj[array[i]] != array[i]|,也就是obj[b]->obj[Object]->a != b,因此存入

obj[b] = b;也就是obj[Object] = b;覆盖了之前的obj[Object] = a;

这种情况下,就会出现所有的对象,都只会存最后一个对象值。

当考虑对象时,我就会使用以下这种方法:

复制代码 代码如下:

for(var i = 0; i < temp.length; i ){
                for(var j = i 1; j < temp.length; j ){
                        if(temp[i] === temp[j]){
                                temp.splice( j, 1 );
                                j--;
                        }
                }
        }
 return temp;

5.数组排序:sort方法,如果要排序的是对象,可以自己写一个compare(a,b){if(a.age>b.age) return 1;else return -1;},A.sort(compare).

6.min返回数组最小值:return Math.min.apply(0,array);

7.unshift在ie6,7下不返回数组长度。

复制代码 代码如下:

if([].unshift(1)!==1)   //往空数组中从前面添加一项,其他浏览器会返回1,而IE6,7不会返回数组长度。这时就执行if语句
{
  var _unshift = Array.prototype.unshift;      //函数劫持。
  Array.prototype.unshift = function(){
    _unshift.apply(this,arguments);
    return this.length;
  }
}

8.splice在一个参数的情况下,IE8以及以下版本默认第二个参数为0,而其他浏览器是数组长度。

复制代码 代码如下:

if([1,2,3].splice(1).length == 0)   //IE8以及以下版本会等于0,其他版本会等于3,进入if里面
{
  var _splice = Array.prototype.splice;
  Array.prototype.splice = function(a){
    if(arguments.length == 1)   //如果只有一个参数时
    {
      return _splice.call(this,a,this.length);
    }else{
      return _splice.apply(this,arguments);
    }
  }
}

这个方法会改变数组的选项,因此数组的push,pop,shift,unshift(这几个方法也会修改数组的选项)都会调用这个方法来实现。

这里有一个地方需要注意:

复制代码 代码如下:

var color = new Array('red','blue','yellow','black');
var color2 = color.splice(2,0,'brown','pink');
alert(color); // red,blue,brown,pink,yellow,black,在yellow选项上,开始操作,如果删除为0,则添加的选项是在yellow之前插入。切记。

 
这里请大家去看下splice和slice的区别,返回值,以及对原数组的影响。

以上就是本节的内容的精简版了,虽然精简,但重点都在,希望对大家阅读本节的时候能有所帮助

您可能感兴趣的文章:

  • 十大热门的JavaScript框架和库
  • 深入解析JavaScript框架Backbone.js中的事件机制
  • JavaScript框架是什么?怎样才能叫做框架?
  • 超赞的动手创建JavaScript框架的详细教程
  • javascript框架设计之类工厂
  • javascript框架设计之浏览器的嗅探和特征侦测
  • javascript框架设计之种子模块
  • javascript框架设计之框架分类及主要功能
  • 2014 年最热门的21款JavaScript框架推荐
  • javascript框架设计读书笔记之字符串的扩展和修复
  • javascript框架设计读书笔记之模块加载系统
  • 澳门新萄京官方网站优雅的数组降维,js将类数组对象转换成数组对象。javascript框架设计读书笔记之种子模块
  • JavaScript框架(iframe)操作总结
  • 怎么选择Javascript框架(Javascript Framework)
  • 详细介绍8款超实用JavaScript框架
  • brook javascript框架介绍
  • 澳门新萄京官方网站优雅的数组降维,js将类数组对象转换成数组对象。16个最流行的JavaScript框架[推荐]
  • 如何选择适合你的JavaScript框架

本文由澳门新萄京官方网站发布于澳门新萄京赌场网址,转载请注明出处:澳门新萄京官方网站优雅的数组降维,js将类数组

关键词: