-1

My goal is to create a master_script.js. A handler file mainly used in development.

A subsection of this file is dedicated to customizing the prototypes of the foundation objects:

  1. String
  2. Number
  3. Array
  4. Object
  5. Date
  6. Function
  7. Boolean

So as I'm writing out my code blocks...

/********************************************************/
Object.defineProperty(
    Number.prototype,'len',
    {get:function(){
        str=this.toString()
        return str.length
    }}
)
/********************************************************/
n=123
o={123:'abc',abc:123}
/********************************************************/
console.log(
    'n              ⇒ ',n,
    '\n n.len       ⇒ ',n.len,
    '\n n.__proto__ ⇒ ',n.__proto__
)
/********************************************************/

Works fine!

  • when I expand n.__proto__ in the console it displays the len: (...) property and it's getter function get len: function (){.
  • and when I type n. into the console it is clearly visible on the list of properties|methods.

The problems start when I configure the same setup for the o variable:

/********************************************************/
Object.defineProperty(
    Number.prototype,'len',
    {get:function(){
        str=this.toString()
        return str.length
    }}
)
/******************************/
Object.defineProperty(
    Object.prototype,'len',
    {get:function(){
        cnt=0
        for(i in this)  cnt++;
        return cnt
    }}
)
/********************************************************/
n=123
o={123:'abc',abc:123}
/********************************************************/
console.log(
    'n              ⇒ ',n,
    '\n n.len       ⇒ ',n.len,
    '\n n.__proto__ ⇒ ',n.__proto__
)
/******************************/
console.log(
    'o              ⇒ ',o,
    '\n o.len       ⇒ ',o.len,
    '\n o.__proto__ ⇒ ',o.__proto__
)
/********************************************************/

The first thing I notice is that when I now type n. or o. into the console the popup list of properties|methods no longer contains a reference to the len property, but if I type in the full extension n.len or o.len I get the desired result of 3 or 2...

So I know the code is legit but I need the console popup as there is about 40 different properties & methods for each of the 7 foundation objects...

So I wrote a test block to try & identify the problem:

/********************************************************/
Object.defineProperty(
    Object.prototype,'dis',
    {get:function(){return this}}
)
/******************************/
Object.defineProperty(
    Number.prototype,'len',
    {get:function(){return this.length}}
)
/********************************************************/
o={123:'abc',abc:123}
n=123
e=document.createElement('option')
/********************************************************/
console.log(
    'o              ⇒ ',o,
    '\n o.__proto__ ⇒ ',o.__proto__
)
/******************************/
console.log(
    'n              ⇒ ',n,
    '\n n.__proto__ ⇒ ',n.__proto__
)
/******************************/
console.log(
    'e              ⇒ ',e,
    '\n e.__proto__ ⇒ ',e.__proto__
)
/********************************************************/

Immediately after expanding the .__proto__ in the console for o, n and now e, I noticed that all 3 had been given the dis property I had originally tried to assign to solely the o object.

Then I cracked it: Number.prototype itself is an object, ergo it inherits the dis property from the Object.prototype

How can I append the dis property solely to the o object without it being inherited by n from Object.prototype?

halfer
  • 19,824
  • 17
  • 99
  • 186
LostInCyberSpace
  • 413
  • 4
  • 19
  • 1
    Wow. That is one *long* question. Am I correct in narrowing it down to **How can I add a property to Object.prototype without it being applied to Number.prototype**? – CodingIntrigue Jan 22 '15 at 08:25
  • 2
    All built–in constructor prototypes inherit from Object.prototype, so no surprise that properties added to it turn up on other objects. That's the reason modifying Object.prototype has been seen as a bad idea for a very long time. – RobG Jan 22 '15 at 08:39
  • yeah sorry @RGraham ur correct, I just thought a bit of case history would help yz understand what I'm tryin to achieve, I'm tryin to avoid the simple solutions I've already tried like the first answer below... – LostInCyberSpace Jan 23 '15 at 00:14
  • @RobG: I kinda knew this already! Thing is I'm just learning why it's sooooo true. – LostInCyberSpace Jan 23 '15 at 00:19

2 Answers2

3

A subsection of this file is dedicated to customizing the prototypes of the foundation objects

Oy vey. Not the greatest idea IMHO. Especially modifying the Object prototype. Yeesh.

So I know the code is legit but I need the console popup as there is about 40 different properties & methods for each of the 7 foundation objects...

Why? Are you doing your development in a browser console?

Do you have the nous to show me how to append the dis property solely to the o object without it being inherited by n from Object.prototype?

Ok...

Object.defineProperty(
    o, 'dis',
    { get:function(){ return this; } }
);

How's that?

Anything you add to the Object prototype is going to show up on pretty much everything (that's why it's a bad idea).

Since o only inherits from Object, there's no way to define a property that would only show up on plain objects and not on everything else. Your choices are to:

  • Define the property directly on o, or
  • Instead of using a plain object for o, create o from your own custom type and put your property on the prototype of that custom type (much better than modifying the built-in types' prototypes).


Note: Of course, you could modify Number.prototype to have a dis property of undefined:
Object.defineProperty(Number.prototype, 'dis', {
    value: void 0
});

console.log((9).dis);

That would solve your problem as far as numbers go, but that dis property is still going to be on pretty much everything else in existence.

And please, for goodness' sake, use semicolons. Think of the children.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • geesh @JLRishe, you sound like the professor offov the simpsons in yer openin statement. lol. I do get what ur sayin, but the solutions you propose still discount the availability of being able to request `{}.len` on any object being used in js... the original __ms.js__ `.len` code was `ms.len(obj)`, `obj.len` just seemed tidier. Any other workarounds welcome tho! – LostInCyberSpace Jan 23 '15 at 00:31
  • ps. ***Why? Are you doing your development in a browser console?*** I'm not, but I am using the console to more clearly view the objects properties I'm adding by simply extending the object in the console rather than writing a code block to list all properties. – LostInCyberSpace Jan 23 '15 at 00:42
0

Check this out:

/********************************************************
⇒   create the master objects.
/********************************************************/
function MasterObject(dis){
    Object.defineProperty(
        this,'this_object',
        {get:function(){return dis}}
    )
}
/******************************/
function MasterArray(dis){
    Object.defineProperty(
        this,'this_array',
        {get:function(){return dis}}
    )
}
/********************************************************
⇒   define the master properties.
/********************************************************/
Object.defineProperty(
    Object.prototype,'_',
    {get:function(){return new MasterObject(this)}}
)
/******************************/
Object.defineProperty(
    Array.prototype,'_',
    {get:function(){return new MasterArray(this)}}
)
/********************************************************
⇒   example to expand in the console.
/********************************************************/
x={a:1,b:2,c:3,d:4,e:5}
y=[]
    y['a']=1
    y['b']=2
    y['c']=3
    y['d']=4
    y['e']=5
z=[x,y]
/********************************************************
⇒   open the console, type [z], hit [enter] and expand...
/********************************************************/

Rundown:

  • Let's say for example we define a property on Object.prototype called len & set its value to 5.
  • Now if we call {}.len, we get a result of 5 & if we call [].len or "".len or #.len etc, we get the same result due to inheritance from Object.prototype on instantiation.
  • But let's say we then define a property on Array.prototype with the same name:- len & set its value to 50.
  • Now if we call {}.len etc, we get the same result of 5, but if we call [].len we get 50, as the Array.prototype was created most recently and its definition of len overwrites Object.prototype's version.

Solution:

  • So if we define only 1 property to Object.prototype called for simplicity's sake _, & set its value to a substructure object that contains the handlers specific to objects only.
  • Then if we do the same for Array.prototype, but set the value of this _ property to another substructure that contains handlers specific to arrays only.
  • Then as with the .len property in the rundown above Array.prototype's version of _ overwrites Object.prototype's version ergo we have 2 completely individual _ properties with no miscellaneous inheritances.

Drawbacks:

  • Can no longer access the properties the easy way {}.len, it now has to be prefixed {}._.len.

Benefits:

  • When defining properties on Object.prototype the whole task can become a paradoxical nightmare, where even errors thrown to the console inherit the properties, and if you've added 100 new properties|methods to Object.prototype then each is visible when you expand any error in the console!
  • This method ensures that only 1 property is ever visible _, and that property is customizable to the type of owner object.

Expansion:

  • I'm looking into modifying this code to accommodate the varying objects that do NOT conform to this standard, like maybe a handler for:
x=document.getElementsByTagName('td')
y=x._.len

Like:

function MasterObject(dis){
    if(dis.constructor.name=='HTMLCollection'){
        Object.defineProperty(
            this,'len',
            {get:function(){
                cnt=0
                for(ia in dis) cnt++;
                return cnt
            }}
        )
    }
        else{
            Object.defineProperty(
                this,'this_object',
                {get:function(){return dis}}
            )
        }
}

So x._.len would be available to any list of objects but not say {a:1} as this has a constructor.name of object not HTMLCollection.

This is a pet project. It's only in its own prototype phase and I'm looking for ideas on how to expand this concept, from those with experience on the topic, before I either go back to the old ways or break through this stigma surrounding prototype modification and come up with a new more efficient way!

halfer
  • 19,824
  • 17
  • 99
  • 186
LostInCyberSpace
  • 413
  • 4
  • 19