Can I set the type of a Javascript object?

2019-03-09 22:45发布

I'm trying to use some of the more advanced OO features of Javascript, following Doug Crawford's "super constructor" pattern. However, I don't know how to set and get types from my objects using Javascript's native type system. Here's how I have it now:

function createBicycle(tires) {
    var that = {};
    that.tires = tires;
    that.toString = function () {
        return 'Bicycle with ' + tires + ' tires.';
    }
}

How can I set or retrieve the type of my new object? I don't want to create a type attribute if there's a right way to do it.

Is there a way to override the typeof or instanceof operators for my custom object?

5条回答
Evening l夕情丶
2楼-- · 2019-03-09 23:00

The instanceof operator, internally, after both operand values are gather, uses the abstract [[HasInstance]](V) operation, which relies on the prototype chain.

The pattern you posted, consists simply on augmenting objects, and the prototype chain is not used at all.

If you really want to use the instanceof operator, you can combine another Crockford's technique, Prototypal Inheritance with super constructors, basically to inherit from the Bicycle.prototype, even if it's an empty object, only to fool instanceof:

// helper function
var createObject = function (o) {
  function F() {}
  F.prototype = o;
  return new F();
};

function Bicycle(tires) {
    var that = createObject(Bicycle.prototype); // inherit from Bicycle.prototype
    that.tires = tires;                         // in this case an empty object
    that.toString = function () {
      return 'Bicycle with ' + that.tires + ' tires.';
    };

    return that;
}

var bicycle1 = Bicycle(2);

bicycle1 instanceof Bicycle; // true

A more in-depth article:

查看更多
ら.Afraid
3楼-- · 2019-03-09 23:00

if you're using a constructor, a better solution than instanceOf, would be this :

Object.toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
}


toType({a: 4}); //"object"
toType([1, 2, 3]); //"array"
(function() {console.log(toType(arguments))})(); //arguments
toType(new ReferenceError); //"error"
toType(new Date); //"date"
toType(/a-z/); //"regexp"
toType(Math); //"math"
toType(JSON); //"json"
toType(new Number(4)); //"number"
toType(new String("abc")); //"string"
toType(new Boolean(true)); //"boolean"
toType(new CreateBicycle(2)); //"createbicycle"

The explanation of WHY it's the best way to do it relies in This post.

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-03-09 23:17

If you declare Bicycle like this, instanceof will work:

function Bicycle(tires) {
  this.tires = tires;
  this.toString = function () {
    return 'Bicycle with ' + tires + ' tires.';
  }
}

var b = new Bicycle(2);
console.log(b instanceof Bicycle);
查看更多
Luminary・发光体
5楼-- · 2019-03-09 23:17

In Firefox only, you can use the __proto__ property to replace the prototype for an object. Otherwise, you cannot change the type of an object that has already been created, you must create a new object using the new keyword.

查看更多
地球回转人心会变
6楼-- · 2019-03-09 23:17

In my opinion, in a properly designed type heirarchy, you don't need to know the types of the individual objects. But I seem to be in the minority on that point.

If you must have type identification, make it explicit.

MyClass.prototype.type = "MyClass";

It is reliable and portable, at least for your objects. It also works across contexts. DOM objects are another matter, although you can make things easier for yourself with

window.type = "window";

and so on.

I believe the quote above was written by Douglas Crockford.

查看更多
登录 后发表回答