質問

I'm writing a unit test (in Mocha with Chai) to see if some object, o is an instanceof ClassY. The unit test succeeds, but I can make it fail depending on how I create an object literal, despite the fact that the produced object literal is the same.

That's a bit vague, I know. Let me explain more.

ClassY is part of an object, which we will call Parent. This relationship simply looks like this:

Parent: {
  ClassY: function() {}
}

I'm attaching Parent to Backbone using the Underscore extend method:
_.extend( Backbone, Parent )

This results in Backbone having the ClassY property, which can be accessed via Backbone.ClassY.

My unit test is:
expect( o ).to.be.instanceof( Backbone.ClassY );

where I know for a fact that o is an instance of Backbone.ClassY.

It passes if I write:

var Parent = {};
var ClassY = Parent.ClassY = function() {};

and also

var Parent = {};
var ClassY = function() {};
Parent.ClassY = ClassY;

But the unit tests fails when I write the following:

var ClassY = function() {};
var Parent = {  
  ClassY: ClassY  
};

The reason for failure is:

TypeError: '[object Object]' is not a valid argument for 'instanceof'
(evaluating 'flag(this, 'object') instanceof constructor')

Indeed, inspecting Backbone in Chrome DevTools reveals to me in the failing case, ClassY is an Object. In the cases of success it is the constructor.

I imagine this is some simple property of object literals that eludes me. Do you know what's going on here?

役に立ちましたか?

解決

I'm not sure what Backbone is doing here (I've got a couple of ideas as to why that might happen, based on knowledge of various "Class"/inheritance implementations in JS, but I'd have to look at the library).

What I CAN tell you, however, is that it's something the library is doing, rather than something about objects, inherently.

Here is your proof:

var Parent_1 = {
        ClassX : function () { this.x = "x"; }
    },

    ClassY = function () { this.y = "y"; },

    Parent_2 = {
        ClassY : ClassY
    };


var littleX = new Parent_1.ClassX(),
    littleY = new Parent_2.ClassY();

littleX instanceof Parent_1.ClassX;
littleY instanceof Parent_2.ClassY;

Both of those should be true.

In JS, when you do something like :

var x = {}, y = [];
x.y = y;

You're giving it a reference to the exact same instance of that object (numbers/strings/booleans work differently).

So x.y === y is true, while {} === {} is false, even if both objects have the same properties.

In backbone, I would imagine that you're passing it in, Backbone is finding a constructor and manipulating it to append helpers or hooks, or to add extra inheritance or MVC functionality/observation, et cetera.

So what comes through the other side isn't the exact same object, in memory -- that's probably buried in a closure, somewhere that Backbone can then poke at, and wire itself up to. Again, haven't read the source, but that's my initial reaction.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top