Paul S.
Paul S.

Reputation: 66404

Difference between overloading __proto__ in two similar functions

In my investigation into making Array-like objects, I made this function,

Array2 = function(){
    var out = [];
    Object.defineProperty(out, 'prototype', { value : Array2.prototype }); // store a reference
    out.__proto__ = Array2.prototype; // necessary as Array uses __proto__ and not prototype

    if(arguments.length > 1) Array.prototype.push.apply(out, arguments);   // re-implement constructor's
    else if(arguments.length === 1) out.length = arguments[0];             // argument handling behaviour

    return out;
};

// allow for normal prototyping behaviour
Array2.prototype = [];
Object.defineProperty(Array2.prototype, 'constructor', { value : Array2 });

and noticed that calling Array2() was returning the same as calling new Array2(), which isn't what I was expecting, so I considered a similar function for integers

Int = function(n){
    var out = ~~n;
    out.prototype = Int.prototype;
    out.__proto__ = Int.prototype;

    this.value = out; // added to check value when working as object

    return out;
};

Int.prototype = 0;
Int.prototype.constructor = Int;

this time, Int returns a normal instance of a Number (__proto__ and prototype as for any number literal) and new Int returns an "Int" Object with Empty as __proto__ and undefined for prototype, with the number available through .value, same as calling without new.

Why are these very similar functions acting so differently, and why is new resulting in the for the first one? It is most likely something obvious I've overlooked.
Only tested in Google Chrome.

Upvotes: 3

Views: 92

Answers (1)

Bergi
Bergi

Reputation: 665476

Actually, your Array2 function return real Arrays instead of only Array-like objects, this does not change when setting the [[prototype]] to an object that inherits from Array.prototype (altough you should not have created an array using [], but a plain object using Object.create(Array.prototype).

Your function Int has several problems.

out is a primitive number value, and has no properties. When assigning some, it will be implicitly casted to a Number object, which is discarded rightafter. The same problem with the "constructor" property on Int.prototype = 0.

Also, you can't use primitive values like 0 as prototype objects. When creating a new Int instance, it will inherit from the default Object.prototype as 0 is not of type "object". I'm not sure what happens when assigning such to the non-standard __proto__ property, but I guess it just fails.

Use this instead:

function Int(n){
    var out = ~~n;
    this.valueOf = function(){ return out; };
    return out; // when not used as a constructor, return int-casted number
};

Int.prototype = Object.create(Number.prototype, {
    constructor:{value:Int}
});

Upvotes: 1

Related Questions