`
jimode2013
  • 浏览: 39360 次
社区版块
存档分类
最新评论

`instanceof` considered harmful (or how to write a robust `isArray`)

阅读更多

 

Checking types in Javascript is well known as a pretty unreliable process.
Good old typeof operator is often useless when it comes to certain types of values:

typeof null; // "object"
typeof []; // "object"

 

People often expect to see something like “null” in the former check and something like “array” in the latter one.
Fortunately, checking for null is not that hard, despite useless typeof, and is usually accomplished by strict-comparing value to null:

value === null;

 

Checking for arrays, on the other hand, is a somewhat tricky business. There are usually two schools of thought – usinginstanceof operator (or checking object’s constructor property) and the-duck-typing way – checking for presence (or types) of certain set of properties (which are known to be present in array objects).

Obviously, both ways have their pros and cons.

1) `instanceof` operator / `constructor` property

instanceof operator essentially checks whether anything from left-hand object’s prototype chain is the same object as what’s referenced by prototype property of right-hand object. It sounds somewhat complicated but is easily understood from a simple example:

var arr = [];
arr instanceof Array; // true

 

This statement returns `true` because Array.prototype (being a prototype property of a right-hand object) references the same object as an internal [[Prototype]] of left-hand object ([[Prototype]] is “visible” via arr.__proto__ in clients that have__proto__ extension). An alternative constructor check, which I mentioned earlier, would usually look like:

var arr = [];
arr.constructor == Array; // true

 

Both instanceof and constructor look very innocent and seem like great ways to check if an object is an array. If I remember correctly, latest jQuery is using constructor:

An excerpt from jQuery (rev. 5917):

...
isArray: function( arr ) {
  return !!arr && arr.constructor == Array;
}

 

The problems arise when it comes to scripting in multi-frame DOM environments. In a nutshell, Array objects created within one iframe do not share [[Prototype]]’s with arrays created within another iframe. Their constructors are different objects and so both instanceof and constructor checks fail:

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]

// Boom!
arr instanceof Array; // false

// Boom!
arr.constructor === Array; // false

 

This “problem” was mentioned by Crockford as far as back in 2003. Doug suggested to try duck-typing and check for a type of one of the Array.prototype methods – e.g.:

typeof myArray.sort == 'function'

 

Exactly for these reasons Javascript authors often resort to a second approach:

2) Duck-typing

We’ve been using it in Prototype.JS for quite some time now. Dean Edwards was using it in its base2, last time I looked at it.

An excerpt from Prototype.js (v. 1.6.0.3):

function isArray(object) {
  return object != null && typeof object === "object" &&
    'splice' in object && 'join' in object;
}

 

By “fixing” multi-frame “problem”, this naive approach fails short in some of the trivial cases. If you were ever to have an object with splice and join properties, Object.isArray would obviously detect that object as being an Array:

var testee = { splice: 1, join: 2 };
Object.isArray(testee); // true

 

Back in June, I was reading ECMA-262 specs and noticed that there was an easy way to get value of an internal [[Class]] property that every native object has. Object.prototype.toString was defined like so:



Object.prototype.toString( )
When the toString method is called, the following steps are taken:
1. Get the [[Class]] property of this object.
2. Compute a string value by concatenating the three strings “[object ", Result (1), and "]“.
3. Return Result (2)

Contrary to Function.prototype.toString which is implementation dependent and is NOT recommended to be relied upon,Object.prototype.toString has a clearly defined behavior for all native objects.



15.3.4.2 Function.prototype.toString()
An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation string is implementation-dependent.

Just as a fun exercise, I wrote a simple __getClass method, put it into an “experimental” folder and forgot about it : )


function __getClass(object) {
  return Object.prototype.toString.call(object)
    .match(/^\[object\s(.*)\]$/)[1];
};

A couple of weeks ago, though, someone created a ticket for Prototype.js – proposing an Object.isDate method. An implementation used constructor check and so was vulnerable to cross-frame issues. This is when I remembered aboutgetClass and its possible usage in isArrayisDate and other similar methods.

Specs mention that:



15.4.2.1 new Array([ item0[, item1 [,...]]])

The [[Class]] property of the newly constructed object is set to “Array”.


This means that creating isArray function could not be simpler than:


function isArray(o) {
  return Object.prototype.toString.call(o) === '[object Array]';
}

The solution is not dependent on frames (since it checks internal [[Class]]) and is more robust than duck-typing approach. I have tested it on a handful of browsers (including some archaic and mobile ones) and was happy to find that all of them are indeed compliant in this regard.

Let’s hope this little “trick” serves as a remedy to cross-frame issues that authors struggle to find workarounds for : )

Happy new year!

分享到:
评论

相关推荐

    instanceof关键字---马克-to-win java视频

    instanceof 马克-to-win java视频的详细的描述介绍

    JS中typeof与instanceof的区别

    JS 中 typeof 与 instanceof 的区别 在 JavaScript 中,typeof 和 instanceof 是两个常用的运算符,用来判断一个变量是否为空,或者是什么类型的。但是,这两个运算符之间还是有区别的。 typeof 运算符是一个一元...

    instanceof关键字.md

    ### instanceof 关键字详解 在Java编程语言中,`instanceof`是一个十分重要的关键字,用于判断一个对象是否属于特定的类或接口。本文将详细解释`instanceof`的关键特性和使用场景,并通过示例代码加深理解。 #### ...

    instanceof.js ES5的instanceof手写实现

    ES5的instanceof手写实现

    PHP强制对象类型之instanceof操作符

    if ($header instanceof Div && $body instanceof Div && $footer instanceof Header1) { // 生成页面 } else { throw new InvalidArgumentException('Incorrect element types'); } } } ``` 在这个例子中,`...

    instanceof 和 prototype 关系

    在JavaScript中,`instanceof`和`prototype`是两个非常重要的概念,它们涉及到对象的类型检测和继承机制。本文将深入探讨这两个关键字的关系及其在实际编程中的应用。 首先,我们来理解`instanceof`操作符。`...

    15.instanceof运算符.zip

    15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof运算符.zip15.instanceof...

    instanceof 判断引用类型,typeof判断基本类型。

    在JavaScript编程语言中,`instanceof` 和 `typeof` 是两个非常重要的操作符,用于判断变量的类型。它们各自有着不同的用途和用法,对于理解和调试代码至关重要。 首先,我们来详细了解一下`instanceof`操作符。`...

    instanceof关键字

    NULL 博文链接:https://chaoyi.iteye.com/blog/2079574

    js中的instanceof操作符1

    `instanceof`是JavaScript中的一个操作符,用于检查一个对象是否是特定构造函数的实例,或者更具体地说,是检查该对象的原型链上是否存在指定构造函数的`prototype`。这个操作符对于理解和处理对象继承关系非常关键...

    JS:typeof instanceof constructor prototype区别

    本文将深入探讨四种常用的方法来识别和判断JavaScript中的数据类型:`typeof`、`instanceof`、`constructor`以及`prototype`。 ### 1. `typeof` `typeof`操作符是最常见的类型检测方式之一,它返回一个表示未经计算...

    向下转型和instanceof运算符的应用.pdf

    在面向对象编程中,向下转型和`instanceof`运算符是两种重要的概念,尤其是在多态性的实现中扮演关键角色。本文将深入探讨这两个主题,并结合Delphi编程语言的背景进行阐述,尽管`instanceof`运算符在Java中更为常见...

    详解JavaScript中typeof与instanceof用法

    alert(a instanceof Array); // 返回true alert(a instanceof Object); // 返回true,因为Array是Object的子类 ``` 在上面的例子中,a是通过Array构造函数创建的数组实例,因此它既是Array的实例,也是Object的实例...

    Java instanceof用法详解及实例代码

    // 输出:a instanceof A: false ``` #### 示例2:对象实例检查 创建`B`类的实例`b`,然后检查`b`是否是`B`或`A`(因为`B`继承自`A`)的实例。在这种情况下,`b instanceof B`和`b instanceof A`都返回`true`。 `...

    Javascript原型链及instanceof原理详解

    console.log('a instanceof A:', a instanceof A); console.log('a instanceof Object:', a instanceof Object); console.log('b instanceof B:', b instanceof B); console.log('b instanceof A:', b instanceof A)...

    08-手写instanceof.md

    更具体地讲,当我们使用a instanceof b的表达式时,它会从a的原型(__proto__)开始,沿着原型链向上查找,直到到达原型链的顶端(null)为止。如果在这个过程中,遇到了b的prototype属性,那么表达式返回true,否则返回...

    java instanceof运算符.txt

    java instanceof运算符

Global site tag (gtag.js) - Google Analytics