最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Is 'isArraylike'? - Stack Overflow

programmeradmin0浏览0评论

As for my understanding 'ArrayLike' type in JavaScript is an object with own numeric positive integer keys, not necesary in successive order(sparse arrays etc.), where object's (int) .length property is greater of them all, right? I came across dozen of explanations of the thing but every one of them gave diferent point of view, so I've wrote the function that finds max (int) key, trashes .length property (to prevent Math.max() yielding NaN value, wich pares false to anything) leaving the rest of object's own keys intact. If all of them are numerics it gives back max one, if not it gives NaN(returning false as result), and pared it's outputs with accepted jQuery equivalent function's results on same values. All explanations are wele. Here's the code I've ran:

// /jQuery version
function isArraylike(obj) {

  // casted the obj parameter to Object here 
  // because some primitive values was throwing an error 
  // not supporting .property access or 'in' operand
  // it doesn't change the logic just converts them to equivalent wrapped types

  var length = (obj = Object(obj)).length,
    type = jQuery.type(obj);

  if (type === "function" || jQuery.isWindow(obj)) {
    return false;
  }

  if (obj.nodeType === 1 && length) {
    return true;
  }

  return type === "array" || length === 0 ||
    typeof length === "number" && length > 0 && (length - 1) in obj;
}

// and my version
function isalike(o) {

  try {

    o.length;

    return (Math.max.apply(Math,
      erase(Object.keys(o), "length")
    ) < o.length);

  } catch (e) {}

  return false;

  function erase(arr, val) {
    var idx;
    ((idx = arr.indexOf(val)) != -1) && arr.splice(idx, 1);
    return arr;
  }

  function s(arg) {
    return Array.prototype.slice.call(arg, 0);
  }

}

// and tests cases that came to my mind
// first boolean value in side ment is jq's output
// second is '.isalike()' function's output
var a = 
{
  0: [], // #0 true true
  1: new Array, // #1 true true
  2: new Array(10), // #2 true true
  3: {}, // #3 false false
  4: {length:0}, // #4 true true
  5: {length:"0"}, // #5 false true
  6: {length:"asd"}, // #6 false false
  7: {length:false}, // #7 false true
  8: {length:true}, // #8 false true
  9: {length:null}, // #9 false true
 10: {length:0, 0:1}, // #10 true false
 11: {length:"0", 0:1}, // #11 false false
 12: {length:0, 1:1}, // #12 true false
 13: {length:0, 2:1}, // #13 true false
 14: {length:"asd", 0:1}, // #14 false false
 15: {length:0, x1:1}, // #15 true false
 16: {length:0, 0:1, x1:1, x2:1}, // #16 true false
 17: {length:1}, // #17 false true
 18: {length:1, 0:1}, // #18 true true
 19: {length:1, 1:1}, // #19 false false
 20: {length:1, 2:1}, // #20 false false
 21: {length:1, 0:1, x1:1}, // #21 true false
 22: {length:2, 0:1}, // #22 false true
 23: {length:2, 1:1}, // #23 true true
 24: {length:2, 2:1}, // #24 false false
 25: {length:2, 3:1}, // #25 false false
 26: {length:2, 1:1, x1:1}, // #26 true false
 27: window, // #27 false false
 28: document, // #28 false false
 29: function (x1) {}, // #29 false true
 30: document.documentElement, // #30 false false
 31: document.getElementsByTagName("*"), // #31 true false
 32: document.body.childNodes, // #32 true true
 33: document.body.children, // #33 true false
 34: document.querySelectorAll("*"), // #34 true true
 35: document.images, // #35 true true
 36: window.frames, // #36 false false
 37: $(), // #37 true true
 38: $("*"), // #38 true false
 39: "asd", // #39 true false
 40: {length:NaN}, // #40 false false
 41: {length:1/0} // #41 false true
};

console.clear();
for (
  var it = 0, 
  end = 42;
  it < end;
  it++
) {
  console.log( "#"+it, isArraylike(a[it]), isalike(a[it]) );
}
//

As for my understanding 'ArrayLike' type in JavaScript is an object with own numeric positive integer keys, not necesary in successive order(sparse arrays etc.), where object's (int) .length property is greater of them all, right? I came across dozen of explanations of the thing but every one of them gave diferent point of view, so I've wrote the function that finds max (int) key, trashes .length property (to prevent Math.max() yielding NaN value, wich pares false to anything) leaving the rest of object's own keys intact. If all of them are numerics it gives back max one, if not it gives NaN(returning false as result), and pared it's outputs with accepted jQuery equivalent function's results on same values. All explanations are wele. Here's the code I've ran:

// /jQuery version
function isArraylike(obj) {

  // casted the obj parameter to Object here 
  // because some primitive values was throwing an error 
  // not supporting .property access or 'in' operand
  // it doesn't change the logic just converts them to equivalent wrapped types

  var length = (obj = Object(obj)).length,
    type = jQuery.type(obj);

  if (type === "function" || jQuery.isWindow(obj)) {
    return false;
  }

  if (obj.nodeType === 1 && length) {
    return true;
  }

  return type === "array" || length === 0 ||
    typeof length === "number" && length > 0 && (length - 1) in obj;
}

// and my version
function isalike(o) {

  try {

    o.length;

    return (Math.max.apply(Math,
      erase(Object.keys(o), "length")
    ) < o.length);

  } catch (e) {}

  return false;

  function erase(arr, val) {
    var idx;
    ((idx = arr.indexOf(val)) != -1) && arr.splice(idx, 1);
    return arr;
  }

  function s(arg) {
    return Array.prototype.slice.call(arg, 0);
  }

}

// and tests cases that came to my mind
// first boolean value in side ment is jq's output
// second is '.isalike()' function's output
var a = 
{
  0: [], // #0 true true
  1: new Array, // #1 true true
  2: new Array(10), // #2 true true
  3: {}, // #3 false false
  4: {length:0}, // #4 true true
  5: {length:"0"}, // #5 false true
  6: {length:"asd"}, // #6 false false
  7: {length:false}, // #7 false true
  8: {length:true}, // #8 false true
  9: {length:null}, // #9 false true
 10: {length:0, 0:1}, // #10 true false
 11: {length:"0", 0:1}, // #11 false false
 12: {length:0, 1:1}, // #12 true false
 13: {length:0, 2:1}, // #13 true false
 14: {length:"asd", 0:1}, // #14 false false
 15: {length:0, x1:1}, // #15 true false
 16: {length:0, 0:1, x1:1, x2:1}, // #16 true false
 17: {length:1}, // #17 false true
 18: {length:1, 0:1}, // #18 true true
 19: {length:1, 1:1}, // #19 false false
 20: {length:1, 2:1}, // #20 false false
 21: {length:1, 0:1, x1:1}, // #21 true false
 22: {length:2, 0:1}, // #22 false true
 23: {length:2, 1:1}, // #23 true true
 24: {length:2, 2:1}, // #24 false false
 25: {length:2, 3:1}, // #25 false false
 26: {length:2, 1:1, x1:1}, // #26 true false
 27: window, // #27 false false
 28: document, // #28 false false
 29: function (x1) {}, // #29 false true
 30: document.documentElement, // #30 false false
 31: document.getElementsByTagName("*"), // #31 true false
 32: document.body.childNodes, // #32 true true
 33: document.body.children, // #33 true false
 34: document.querySelectorAll("*"), // #34 true true
 35: document.images, // #35 true true
 36: window.frames, // #36 false false
 37: $(), // #37 true true
 38: $("*"), // #38 true false
 39: "asd", // #39 true false
 40: {length:NaN}, // #40 false false
 41: {length:1/0} // #41 false true
};

console.clear();
for (
  var it = 0, 
  end = 42;
  it < end;
  it++
) {
  console.log( "#"+it, isArraylike(a[it]), isalike(a[it]) );
}
//
Share Improve this question edited Jan 14, 2014 at 17:56 sudocdslash asked Jan 14, 2014 at 14:20 sudocdslashsudocdslash 431 silver badge5 bronze badges 1
  • 1 Slightly old but still informative blog post from Kangax. – Pointy Commented Jan 14, 2014 at 14:30
Add a ment  | 

1 Answer 1

Reset to default 5

I came across dozen of explanations of the thing but every one of them gave diferent point of view...

When you asked this question in 2014, there were different points of view. Since then, the JavaScript specification has given us a specific definition of "array-like".

The jQuery isArrayLike function, as you can see from the code, imposes lots of requirements. The object must not be a function or a Window object; it must have a length property; that property's value must be a number (without conversion), and it must have an element at index length - 1.

JavaScript's definition is much less restrictive: The object must have a length property that doesn't throw an error when you get it and convert it to a non-negative integer with a quite loose conversion. That's it. It can be a function, a Window object, a sparse array with no element at length - 1, or any of several other things. All it needs is a length property that doesn't throw when converted. That property's value could be the string "flibbertygibbit" and that's fine (it'll be treated as 0). From that link:

LengthOfArrayLike(obj)

The abstract operation LengthOfArrayLike takes argument obj (an Object) and returns either a normal pletion containing a non-negative integer or a throw pletion. It returns the value of the "length" property of an array-like object. It performs the following steps when called:

  1. Return ℝ(? ToLength(? Get(obj, "length"))).

An array-like object is any object for which this operation returns a normal pletion.

NOTE 1

Typically, an array-like object would also have some properties with integer index names. However, that is not a requirement of this definition.

(In that, ℝ just means "the mathematical value of" (so for instance, both +0 and -0 are just 0), and ToLength is the abstract specification operation that quite loosely converts just about anything to a non-negative integer number value.)

发布评论

评论列表(0)

  1. 暂无评论