Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to HIDE Javascript Object's prototype! What's the MYSTERY behind this?

I'm using openui5. There is a constructor Function for UI control Button,unable to see the prototype properties of the Button but the same thing when executed in browser console, shows up!

 sap.m.Button.prototype.Move = function(){
  console.log('Move');
} 
var oButton = new sap.m.Button({text:"Hello"});
oButton.Move(); // throws undefined function! 

The same code when executed browser in console, it works!

jsbin --> http://jsbin.com/tepum/1/edit

like image 269
ikiw Avatar asked Apr 11 '14 06:04

ikiw


2 Answers

After running the code I find that creating the first instance of sap.m.Button causes script to change the prototype of sap.m.Button. It's valid in JavaScript but not very smart if you ask me.

A first creation causes a synchronous request (no no as well) to fetch library-parameters.json.

If you run the code the second time it will have prototype.move because creating an instance of Button will not change the Button.prototype.

The capital M in Move would suggest a constructor function so I would advice changing it to lower case.

Since fetching the parameters is synchronous you can create the first instance and then set the prototype:

console.log("First Button creation changes Button.prototype");
var oButton = new sap.m.Button({text:"Hello"});
sap.m.Button.prototype.move = function(){
  console.log('Move');
} 
oButton.placeAt('content');
oButton.move(); // logs Move

My guess is that this is done to lazy load controls, if a Button is never created then the json config files are never loaded for these unused controls. It has a couple of drawbacks though.

  1. You have to create an instance first before you can set the prototype.
  2. The config files are synchronously loaded so when creating first instance of many controls with a slow connection would cause the app to be unresponsive.

A better way would be for a factory function to return a promise so you create the control the same way every time and the config files can be fetched asynchronously.

[update]

Looking at the config it seems to be config for the whole gui library so I can't see any reason why this is loaded only after creating a first instance. A library that changes it's object definitions when creating instances is not very easy to extend because it's unpredictable. If it only changes prototype on first creation then it should be fine but it looks like the makers of the library didn't want people to extend it or they would not make the object definition unpredictable. If there is an api documentation available then maybe try to check that.

[update]

It seems the "correct" way to extend controls is to use extend.

like image 70
HMR Avatar answered Oct 01 '22 21:10

HMR


@HMR is right the correct way to extend a control is by using the extend function provided by UI5 managed objects, see http://jsbin.com/linob/1/edit

in the example below when debugging as mentoned by others you will notice that the control is lazy loaded when required, any changes you make prior are lost when loaded

    jQuery.sap.declare("my.Button");
    jQuery.sap.require("sap.m.Button");
    sap.m.Button.extend("my.Button", {
        renderer: {} 
    });

    my.Button.prototype.Move = function() {
        console.log('Move');
    };

    var oButton = new my.Button({
        text: "Hello"
    });
    oButton.placeAt('content');
    oButton.Move();
like image 42
Jasper_07 Avatar answered Oct 01 '22 21:10

Jasper_07