[Effective JavaScript note] 58th: Distinguishing between array objects and class array objects

Source: Internet
Author: User

Example

Imagine that there are two different classes of APIs.
The first is a bit vector: an ordered set of bits

var bits=new BitVector();bits.enable(4);bits.enable([1,3,8,17]);bits.bitAt(4);//1bits.bitAt(8);//1bits.bitAt(9);//0

The Enable method is overloaded and can pass in an array of indexes or indexes.
The second class's API is a collection of strings: unordered collection of strings

var set=new StringSet();set.add(‘Hamlet‘);set.add([‘Rosencrantz‘,‘Guildenstern‘]);set.add({‘Ophelia‘:1,‘Polonius‘:1,‘Horatio‘:1});set.contains(‘Polonius‘);//trueset.contains(‘Guildenstern‘);//trueset.contains(‘Falstaff‘);//false

Where the Add method is overloaded, you can receive a Dictionary object in addition to receiving strings and string arrays. function overloading

To implement the BitVerctor.prototype.enable method, you can test other situations to avoid the problem of how to determine whether an object is an array.

BitVector.prototype.enable=function(x){    if(typeof x === ‘number‘){        this.enableBit(x);    }else{        for(var i=0,n=x.length;i< n;i++){            this.enableBit(x[i]);        }    }};

This only implements the index and index array of judgments, it is easy to implement. How does the StringSet.prototype.add method come true? Here you need to differentiate between arrays and objects. In JS, an array is an object. What you really want to do here is detach the array object and the non-array object.
Such a distinction and the concept of JS's flexible class array object are disputed. Any object can be treated as an array, as long as it follows the correct interface. There is also no clear way to test whether an object satisfies an interface. You can try to treat an object with the length property as an array, but there will also be errors, such as the chance that a Dictionary object has a length attribute?

dimensions.add({    ‘length‘:1,    ‘height‘:1,    ‘width‘:1});

Using imprecise heuristics to determine an interface is an easy way to be misunderstood and abused. Guessing whether an object implements a struct type is sometimes called a duck test, which is bad practice. Because objects do not have explicit information tokens to represent the types of structures they implement, there is no reliable programmatic way to detect information.

Overloading two types means there must be a way to differentiate between the two cases. It is not possible to detect whether a value implements a structural interface.
Rule-api should never overload types that overlap with other types instanceof

For Stringset, do not start with a structured class array interface. Instead, we should choose a type that has a clearly defined "label" that indicates that the user really wants to use it as an array. An obvious but imperfect option is to use the instanceof operator to test whether an object inherits from Array.prototype.

StringSet.prototype.add=function(x){    if(typeof x === ‘string‘){        this.addString(x);    }else if(x instaceof Array){        x.forEach(function(s){            this.addString(s);        },this);    }};

Any time an instance of an array, it behaves like an array. Sometimes, however, in environments where multiple global objects can be allowed, there may be multiple copies of the standard array constructor and prototype objects. In this case in the browser, each frame will have a separate copy of the standard library. When you communicate across a frame, the array in one frame does not inherit from the Array.prototype of another frame. Array.isarray

In this case, ES5 introduces the Array.isarray function, which is used to test whether a value is an array, regardless of the stereotype inheritance. In the ES standard, the function tests whether an object's internal [[Class]] property value is an array. The Array.isarray method is better than the instanceof operator when it is necessary to test whether an object is a true array, rather than just a class array object.

StringSet.prototype.add=function(x){    if(typeof x === ‘undefined‘){        this.addString(x);    }else if(Array.isArray(x)){        x.forEach(function(s){            this.addString(s);        },this);    }else{        for(var key in x){            this.addString(key);        }    }};
Object.prototype.toString

In an environment that does not support ES5, you can use the standard Object.prototype.toString method to test whether an object is an array.

var toString=Object.prototype.toString;functin isArray(x){    return toString.call(x) === ‘[object Array]‘;}

The Object.prototype.toString function creates a result string using the [[Class]] property inside the object, so it is more accurate than the instanceof operator when testing whether an object is an array.

Note: This version of the Add method has different behavior that affects the user of the API. The array version of the overloaded API does not receive arbitrary class array objects. For example, you cannot pass in an arguments object and expect it to be treated as an array.

function MyClass(){    this.keys=new StringSet();    //...}MyClass.prototype.update=function(){    this.keys.add(arguments);};
Array.prototype.slice

Arguments will be treated as a dictionary here. You can convert a arguments object into a real array.

MyClass.prototype.update=function(){    this.keys.add([].slice.call(arguments));};

When the caller passes in multiple parameters, they are converted to a real array, and then the add operation is used. This conversion is required when the caller wants to pass a class array object to an API that expects to receive a real array. You can indicate which types of parameters each API receives in the API's documentation. As in the above example, the Enable method receives the numbers and class array objects. The Add method receives strings, true arrays, and non-array objects. Tips

    • Never overload a struct type that has overlapping other types

    • When you overload a struct type with another type, test other types first

    • Receive true arrays instead of class array objects when other object types are overloaded

    • Document callout Whether your API receives a true array or an array of classes

    • Test a true array using the Array.isarray method provided by ES5

[Effective JavaScript note] 58th: Distinguish between array objects and class array objects

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.