澳门在线威尼斯官方 > 威尼斯澳门在线 > 特殊对象

原标题:特殊对象

浏览次数:100 时间:2019-10-31

JavaScript 特殊指标 Array-Like Objects 详解

2016/06/26 · JavaScript · Javascript, underscore

正文小编: 伯乐在线 - 韩子迟 。未经作者许可,制止转载!
接待参与伯乐在线 专栏审核人。

那篇作品拖了有两周,前天来跟我们拉家常 JavaScript 中风姿洒脱类特殊的对象 -> Array-Like Objects。

(本文节选自 underscore 源码解读种类作品,完整版请关心 )

那篇小说拖了有两周,后天来跟大家拉家常 JavaScript 中大器晚成类非常的对象 -> Array-Like Objects。

Array-Like

JavaScript 中漫天皆为对象,那么哪些是 Array-Like Objects?看名称就能够想到其意义,就是像数组的指标,当然,数组本人便是目的嘛!微微有一点点基础的校友,一定知道 arguments 正是 Array-Like Objects 的风姿洒脱种,能像数组同样用 [] 去访问 arguments 的元素,有 length 属性,不过却不可能用一些数组的章程,如 push,pop,等等。

这正是说,什么样的因素是 Array-Like Objects?大家来探视 underscore 中对其的概念。

JavaScript

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var getLength = property('length'); var isArrayLike = function(collection) { var length = getLength(collection); return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; };

1
2
3
4
5
6
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

比较轻松,不是数组,不过有 length 属性,且属性值为非负 Number 类型就能够。至于 length 属性的值,underscore 给出了一个上限值 MAX_ARRAY_INDEX,其实是 MAX_SAFE_INTEGE中华V(多谢 @HangYang 同学提议) ,因为那是 JavaScript 中能准确表示的最大数字。

心想还应该有啥样相同的时间能满意上述口径的?NodeList,HTML Collections,留神思索,以致还应该有字符串,只怕持有 length 属性的指标,函数(length 属性值为形参数量),等等。

(本文节选自 underscore 源码解读连串小说,完整版请关心 https://github.com/hanzichi/underscore-analysis)

Array-Like to Array

部分时候,供给将 Array-Like Objects 转为 Array 类型,使之能用数组的部分办法,一个非常轻便暴虐而且包容性特出的艺术是新建个数组,然后循环存入数据。

我们以 arguments 为例。

function fn() { // Uncaught TypeError: arguments.push is not a function // arguments.push(4); var arr = []; for (var i = 0, len = arguments.length; i < len; i++) arr[i] = arguments[i]; arr.push(4); // [1, 2, 3, 4] } fn(1, 2, 3);

1
2
3
4
5
6
7
8
9
10
11
12
function fn() {
  // Uncaught TypeError: arguments.push is not a function
  // arguments.push(4);
 
  var arr = [];
  for (var i = 0, len = arguments.length; i < len; i++)
    arr[i] = arguments[i];
 
  arr.push(4); // [1, 2, 3, 4]
}
 
fn(1, 2, 3);

不过那不是最温婉的,越来越高雅的解法大家断定都知晓了,use Array.prototype.slice(IE9- 会有标题)。

function fn() { var arr = Array.prototype.slice.call(arguments); arr.push(4); // arr -> [1, 2, 3, 4] } fn(1, 2, 3);

1
2
3
4
5
6
function fn() {
  var arr = Array.prototype.slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}
 
fn(1, 2, 3);

还是可以用 [] 取代 Array.prototype 节省多少个字节。

function fn() { var arr = [].slice.call(arguments); arr.push(4); // arr -> [1, 2, 3, 4] } fn(1, 2, 3);

1
2
3
4
5
6
function fn() {
  var arr = [].slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}
 
fn(1, 2, 3);

假定非得追求品质,用 [] 会新建个数组,质量料定不比前边三个,可是由于外燃机的优化,那点间距基本得以忽视不计了(所以重重框架用的就是后人)。

为啥那样能够转换?大家大概明白下,首要的案由是 slice 方法只需求参数有 length 属性就能够。首先,slice 方法获得的结果是贰个 新的数组,通过 Array.prototype.slice.call 传入的参数(要是为 a),若无 length 属性,恐怕 length 属性值不是 Number 类型,或然为负,那么直接再次回到二个空数组,不然重返a[0]-a[length-1] 组成的数组。(具体能够看下 v8 源码 )

理所必然,ES6 提供了更方便的章程。

var str = "helloworld"; var arr = Array.from(str); // ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

1
2
3
var str = "helloworld";
var arr = Array.from(str);
// ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

小结下,即使要把 Array-Like Objects 转为 Array,首选Array.prototype.slice,不过出于 IE 下 Array.prototype.slice.call(nodes) 会抛出荒诞(because a DOM NodeList is not a JavaScript object),所以兼容的写法如下。(但还应该有少数要专心的是,如若是 arguments 转为 Array,最棒别用 Array.prototype.slice,V8 下会超级慢,具体能够看下 避免改善和传递 arguments 给其余方法 — 影响优化 )

function nodeListToArray(nodes){ var arr, length; try { // works in every browser except IE arr = [].slice.call(nodes); return arr; } catch(err){ // slower, but works in IE arr = []; length = nodes.length; for(var i = 0; i < length; i++){ arr.push(nodes[i]); } return arr; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function nodeListToArray(nodes){
  var arr, length;
 
  try {
    // works in every browser except IE
    arr = [].slice.call(nodes);
    return arr;
  } catch(err){
    // slower, but works in IE
    arr = [];
    length = nodes.length;
 
    for(var i = 0; i < length; i++){
       arr.push(nodes[i]);
     }  
 
    return arr;
  }
}

Array-Like

JavaScript 中全方位皆为目标,那么什么样是 Array-Like Objects?看名称就可以想到其意义,便是像数组的目的,当然,数组本身就是指标嘛!微微有一些基础的同桌,一定领会arguments 就是 Array-Like Objects 的风华正茂种,能像数组同样用 [] 去访问 arguments 的元素,有 length 属性,不过却无法用一些数组的办法,如 push,pop,等等。

那正是说,什么样的因素是 Array-Like Objects?大家来探访 underscore 中对其的定义。

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

很简短,不是数组,不过有 length 属性,且属性值为非负 Number 类型就可以。至于 length 属性的值,underscore 给出了一个上限值 MAX_ARRAY_INDEX,其实是 MAX_SAFE_INTEGE安德拉(多谢 @HangYang 同学提议) ,因为那是 JavaScript 中能正确表示的最大数字。

合计还好似何同一时候能满意上述条件的?NodeList,HTML Collections,留意揣摩,以致还应该有字符串,只怕有所 length 属性的指标,函数(length 属性值为形参数量),等等。

Others

不菲时候,有个别方法您感到选拔的参数是数组,其实类数组也是足以的。

Function.prototype.apply() 函数选择的第二个参数,其实也得以是类数组。

var obj = {0: 4, length: 2}; var arr = [1, 2, 3]; Array.prototype.push.apply(arr, obj); console.log(arr); // [1, 2, 3, 4, undefined]

1
2
3
4
var obj = {0: 4, length: 2};
var arr = [1, 2, 3];
Array.prototype.push.apply(arr, obj);
console.log(arr); // [1, 2, 3, 4, undefined]

Array-Like to Array

风姿洒脱对时候,必要将 Array-Like Objects 转为 Array 类型,使之能用数组的生龙活虎对措施,一个特轻巧狂暴而且宽容性卓越的不二诀若是新建个数组,然后循环存入数据。

我们以 arguments 为例。

function fn() {
  // Uncaught TypeError: arguments.push is not a function
  // arguments.push(4);

  var arr = [];
  for (var i = 0, len = arguments.length; i < len; i++)
    arr[i] = arguments[i];

  arr.push(4); // [1, 2, 3, 4]
}

fn(1, 2, 3);

唯独那不是最文雅的,更温婉的解法我们自然都知晓了,use Array.prototype.slice(IE9- 会有标题)。

function fn() {
  var arr = Array.prototype.slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}

fn(1, 2, 3);

或许可以用 [] 替代 Array.prototype 节省多少个字节。

function fn() {
  var arr = [].slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}

fn(1, 2, 3);

若果非得追求质量,用 [] 会新建个数组,品质确定未有后面一个,然而出于斯特林发动机的优化,这一点间距基本能够忽视不计了(所以众多框架用的正是后世)。

为啥那样能够转换?大家大致领会下,首要的原因是 slice 方法只需求参数有 length 属性就能够。首先,slice 方法赢得的结果是三个 新的数组,通过 Array.prototype.slice.call 传入的参数(要是为 a),若无 length 属性,恐怕 length 属性值不是 Number 类型,大概为负,那么间接回到一个空数组,不然重返a[0]-a[length-1] 组成的数组。(具体能够看下 v8 源码 https://github.com/v8/v8/blob/master/src/js/array.js#L621-L660)

自然,ES6 提供了更简便的措施。

var str = "helloworld";
var arr = Array.from(str); 
// ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

小结下,假若要把 Array-Like Objects 转为 Array,首荐Array.prototype.slice,不过由于 IE 下 Array.prototype.slice.call(nodes) 会抛出乖谬(because a DOM NodeList is not a JavaScript object),所以包容的写法如下。(但还应该有少数要专一的是,假设是 arguments 转为 Array,最佳别用 Array.prototype.slice,V8 下会超级慢,具体能够看下 防止予修业正和传递 arguments 给此外办法 — 影响优化 )

function nodeListToArray(nodes){
  var arr, length;

  try {
    // works in every browser except IE
    arr = [].slice.call(nodes);
    return arr;
  } catch(err){
    // slower, but works in IE
    arr = [];
    length = nodes.length;

    for(var i = 0; i < length; i++){
       arr.push(nodes[i]);
     }  

    return arr;
  }
} 

本文由澳门在线威尼斯官方发布于威尼斯澳门在线,转载请注明出处:特殊对象

关键词:

上一篇:如何准备前端开发者面试

下一篇:没有了