Javascript defineGetter - javascript

var a = {};
a.__defineGetter__('test',function() {return 5;});
var i ="test";
Is there any other way I can execute the getter besides a[i] (while using var i to do it)
EDIT:
I was asking ways to use var i to do it. I'll explain the real problem a bit better.
I am using getters on my namespace object to load modules only when needed.
MyNameSpace.__defineGetter__('db',function(){MyNameSpace.loadModule('db');});
In this case I am trying to load all modules:
for (var i in MyNameSpace){
MyNameSpace[i];
}
I use Google closure compiler on my code, and it reduces that loop above to:
for(var i in MyNameSpace);
No modules get loaded. I am trying to "trick" gcc into letting me load the modules.

You can do either a.test or a['test'] - both will access the test property of a and hence call the getter.
Edit: Ah, I see exactly what you want now. What you're doing is a clever use of getters, but unfortunately getters and setters aren't part of the current JavaScript standard (they are in ECMAScript 5 which isn't widely supported yet). Google Closure Tools seems to assume that reading a variable can't have any side-effect, which is true in the current versions of JavaScript, so I see no way to get around that. You'll have to edit the output to insert that stuff back.
Also, this isn't related to your question, but I do hope you're doing an additional hasOwnProperty check within the for-in construct.

I guess closure compiler optimizes out the code because it doesn't actually do anything but access the properties. this should work:
module = {}; // global
for (var i in MyNameSpace){
module = MyNameSpace[i];
}

Looking at your module example, seems like you just want a little refactoring there.
var moduleNames = { 'db', 'input', 'etc' };
for ( var name in moduleNames ) {
MyNameSpace.__defineGetter__(name,function(){MyNameSpace.loadModule(name);});
}
function loadAll() {
for ( var name in moduleNames ) {
MyNameSpace.loadModule(name);
}
}
If the functions themselves are less trivial than that, then you similarly want to collect the functions into a handy dictionary ahead of time, then loop over those to create the getter, and loop again to create the load all function.

Related

Searching local javascript variables by name patterns

In Javascript, local variables do not live on any object that I'm aware of. That is,
function foo() {
const x = 2;
self.x; // undefined
this.x; // undefined
window.x; // undefined
x; // 2, obviously
eval('x'); // 2
}
The last option eval('x') shows that it is possible to refer to these variables by name. I'm looking to extend this and access a variable using a name pattern:
function foo() {
// Code not under my direct control
function foobar_abc() {}
function other_functions() {}
// Code under my control
const matchingFunction = // find the function with name matching 'foobar_*'
}
If this lived on an object, I would use something like myObject[Object.keys(myObject).find((key) => key.startsWith('foobar_'))]. If it were in the global scope, myObject would be window and everything works.
The fact that eval is able to access the variable by name implies that the value is available somewhere. Is there any way to find this variable? Or must I resort to techniques which re-write the (potentially very complex) code which is not under my direct control?
I'm targeting modern browsers, and in this use case I don't mind using eval or similarly hacky solutions. Arbitrary code is already being executed, because the execution of user-provided code is the purpose.
Another option is to use code parsing to deduce the function names using a javascript AST (abstract syntax tree) library. The "esprima" package will probably be good place to look:
https://www.npmjs.com/package/esprima
So you can do
import esprima from 'esprima'
const userCodeStructure = esprima.parseScript( userProvidedJavascriptString );
const allTopLevelFunctionDeclarations = userCodeStructure.body.filter( declaration => declaration.type === "FunctionDeclaration" );
const allTopLevelFunctionNames = allTopLevelFunctionDeclarations.map( d => d.id );
I haven't tried this myself by the documentation suggests it should work (or something like it):
http://esprima.readthedocs.io/en/latest/
One possible approach that might help you here is to evaluate at global scope rather than in a function, and that might put the functions on the window object instead of in local scope.
Easiest way to do this is probably to write a new tag into the document and inject the user-provided code.
Relying on variable names is the wrong approach.
eval is evil. It may not be available under CSP. Considering that the code is supposed to run in browser, the biggest problem is that variables don't have expected names in minified code. They are a, b, c...
In order to maintain their names, they should be object properties - and so they will be available on the object.
Or must I resort to techniques which re-write the (potentially very complex) code
This is refactoring and that's what should be done to avoid bad code that smells and creates major problems.

What's this type of jquery coding style called?

I've always used jquery with a
$(document).ready(function {
....
});
But i've recently just inherited a complete site with the script file opening like the following:
var gc = gc || {};
gc.header = {
mobileNav: function () {
...
},
headerLink: function () {
...
}
};
gc.header.headerLink();
I've never seen it structured in this way - it's actually quite easy to use and would love to learn more about to help improve my coding styles.
If somebody could help me by providing me with what this type of coding style is? And - if you know of any, some learning resources?
Thanks in advance!
Lew.
It is usually referred to as namespacing. It has absolutely nothing to do with jQuery.
This style of JavaScript syntax is a little more object oriented. This makes it easier to edit and read but also helps your JavaScript stay 'clean' by namespacing your JavaScript. This means that you basically try to keep as much of your JavaScript out of the Global Object as possible - thereby reducing collisions in your code.
Line by line:
var gc = gc || {}; // If a 'gc' object exists, use it. Otherwise create an empty object.
gc.header = { // In the gc.header object create 2 methods, mobileNav and headerLink
mobileNav: function () {
...
},
headerLink: function () {
...
}
};
gc.header.headerLink(); // Reference the headerLink() method inside gc.header
This is far preferable to creating a more flat pattern where mobileNav and headerLink are global functions because mobileNav and headerLink are very generic functions that may be used and named identically in other plugins. By namespacing you reduce the risk of breaking your code and running into collisions because gc.header.headerLink() is much more unique.
It`s just ordinary JavaScript, it's a technique called namespacing: How do I declare a namespace in JavaScript?

Alternative methods for extending object.prototype when using jQuery

Some time ago I tried to extend Object.prototype... I was surprised when later I saw errors in the console which comes from jQuery file. I tried to figured out what is wrong and of course I found information that extending Object.prototype is a "evil", "you shouldn't do that because JS is dynamic language and your code will not work soon" and information that jQuery will now add hasOwnProperty method to their for in loops.
Because I didn't want to leave jQuery, I drop the idea about extending Object.prototype.
Till now. My project getting bigger and I am really annoyed because I have to repeat many times some parts of the code. Below is a bit of the structure which I am using in my projects:
charts.js:
CHARTS = {
_init: function () {
this.monthlyChart();
/*
*
* more propertys goes here
*
*/
return this;
},
monthlyChart: function () {
//create my chart
return {
update: function () {
// update chart
}
};
}()
/*
*
* more propertys goes here
*
*/
}._init;
dashboard.js
NAVBAR = {
_init: function () {
/*
*
* more propertys goes here
*
*/
return this;
},
doSomething: function(){
$(document).ready(function(){
$('.myButton').on('click', function(){
var data = [];
// calling property from charts.js
CHARTS.monthlyChart.update(data);
});
});
}
}._init
As I mentioned project is really big now - it's over 40 js files and some of them has a few thousands line of code. It is really annoying that I have to repeat _init section every time, as well as I many functions I have to repeat $(document).ready && $(window).load.
I tried to find another solution for my problem. I tried to create class with init property (more you can find here) but I this solution forced me to add another "unnecessary" piece of the code to every file and accessing other file object property makes it to complicated too (return proper objects everywhere etc). As advised in the comment I started reading about getters and setters in JS.
After all I created something like that:
//Auto initialization
if (typeof $document === 'undefined') {
var $document = $(document),
$window = $(window),
$body = $('body');
}
Object.defineProperty(Object.prototype, '_init', {
get: function () {
// if object has no property named `_init`
if (!this.hasOwnProperty('_init')) {
for (var key in this) {
// checking if name of property does starts from '_' and if it is function
if (this.hasOwnProperty(key) && key[0] === '_' && typeof this[key] === 'function') {
if (key.indexOf('_ready_') > -1) {
//add function to document ready if property name starts from '_ready_'
$document.ready(this[key].bind(this));
} else if (key.indexOf('_load_') > -1) {
//add function to window load if property name starts from '_load_'
$window.load(this[key].bind(this));
} else {
// else execute function now
this[key].bind(this)();
}
}
}
return this;
}
}
});
and my object:
var DASHBOARD = {
_runMe: function(){
},
_ready_runMeOnReady: function(){
},
_load_runMeOnLoad: function(){
},
iAmAString: ''
}._init
It seems that this solution works with jQuery. But is it safe to use? I don't see any problem the code can cause and I don't see any further problems that it may cause. I will be really happy if somebody will tell me why I shouldn't use this solution.
Also I'm trying to understand how it works in details. Theoretically I defined property for the Object.prototype by defineProperty, without assigning value to it. Somehow it doesn't cause any errors in jQuery fore in loop, why? Does that mean that property _init is not defined at some point or at all because I am defined only getter of it?
Any help will be appreciated :)
By not including the descriptor in Object.defineProperty(obj, prop, descriptor) JavaScript defaults all the Boolean descriptor attributes to false. Namely
writable, enumerable, and configurable. Your new property is hidden from the for in iterators because your _init property is enumerable:false.
I am not a fan of JQuery so will not comment on why in regard to JQuery
There is no absolute rule to adding properties to JavaScript's basic type and will depend on the environment that your code is running. Adding to the basic type will add it to the global namespace. If your application is sharing the namespace with 3rd party scripts you can potentially get conflicts, causing your code or the third party code or both to fail.
If you are the only code then conflicts will not be an issues, but adding to object.prototype will incur an addition overhead on all code that uses object.
I would strongly suggest that you re examine the need for a global _init. Surely you don't use it every time you need a new object. I am a fan of the add hock approach to JavaScript data structures and try to keep away from the formal OOP paradigms
Your question in fact contains two questions.
It seams that this solution works with jQuery. But is it safe to use? I don't see any problem the code can cause and I don't see any further problems that it may cause. I will be really happy if somebody will tell me why I shouldn't use this solution.
First of all, there are three main reasons to avoid modification of built-in prototypes.
For-in loops
There is too much code using for-in loop without hasOwnProperty check. In your case that is jQuery code that does not perform check.
Solutions
Don't use for-in loop without .hasOwnProperty check.
Doesn't apply in this case because it's third-party code and you can't modify it.
for-in loop traverses only enumerable keys.
You have used that solution. Object.defineProperty creates non-enumerable properties by default (ECMAScript 5.1 specification)
Not supported by IE8.
Conflicts
There is risk of property name. Imagine that you use jQuery plugin that checks for existence of ._init property on objects - and it can lead to subtle and hard to debug bugs. Names prefixed with underscore are widely used in modern JavaScript libraries for indicating private properties.
Encapsulation violation (bad design)
But you have worser problem. Definining global ._init property suggests that every object have universal initialization logic. It breaks encapsulation, because your objects don't have full control over their state.
You can't rely on presence of _init method due to this. Your coworkers can't implement their own class with
Alternative designs
Global initializer
You can create global function initialize and wrap all your objects that require initialization in it.
Decouple view and logic
Your objects should not merge logic and view in one object (it violates single responsibility principle) and you are victim of spaghetti code.
Moreover - object initialization should not bind it to DOM, some controller objects should be a proxy between your logic and display.
It can be good idea to inspect how popular client-side MVC frameworks have solved this problem (Angular, Ember, Backbone) have solved this problem.
Is it safe to use getters and setters?
Yes. But if you only support IE9+.
Is it safe to modify Object.prototype?
No. Create another object to inherit all of your application objects from.
Why extending basic JavaScript objects is eval evil?
Because EVERY SINGLE object created on the webpage where your script is loaded will inherit that property or method.
There is a lot cons like collisions and performance overhead if you do it that way.
There is a lot of ways to make it better, let me show you the one I use.
// Here we create the base object:
var someBaseObject = {};
someBaseObject.someMethod = function () {
// some code here
}
someBaseObject.someProperty = "something";
// And inherit another object from the someBaseObject
someObject = Object.create(someBaseObject);
someObject.someAnotherMethod = function () {
// some code here
}
This approach allow us to leave the Object prototype alone, and build a prototype chain where someObject inherits from someBaseObject, and someBaseObject inherits from Object.
The only thing I want to say by this post: leave base objects alone and build your own, so you will have much less headache.
Note: Object.create is supported in IE9+. Here is shim for IE8 and lower by Douglas Crockford:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}

What is the point of declaring variables without assignment?

I'm studying some CreateJS samples and in one of them I've seen this and I'm wondering what use it's for
(function() {
var c = createjs;
var a = function(blabla) {
this.blabla = blabla;
var p = Game.prototype;
p.a;
p.b;
p.c;
p.d;
/*
... 15 variables like that ...
*/
p.init = function(param) {
/* blabla */
}
/*
...
long code after that
...
*/
})();
It's on the github samples, in the /createjs/sandbox-master/PlanetaryGary directory, it's the file js/Game.js
I'm the original author of the code in question. This pattern comes down to the simple philosophy that good code is self-documenting.
It's worth a quick mention for those coming into this blind that those properties are not actually named a,b,c, etc. It's also worth mentioning that they are usually assigned a default value (though not in this particular case).
The up-front variable declarations explicitly define the fields that will be associated with the "class". This allows a developer to scan from the top down, and establish a mental model of the data the class operates on prior to looking at the methods that operate on it.
It provides a convenient, contextual place to hook doc comments, though the referenced code is not documented.
/**
* Docs for firstName here.
**/
p.firstName = "default";
/**
* lastName docs.
**/
p.lastName = "default";
Lastly, I've found it encourages a more thoughtful approach to data and documentation. The act of defining a new property becomes an opportunity to view the existing properties and evaluate the necessity of the new field. I've seen a lot of bugs and poor code result from devs appending properties to classes willy-nilly.
It's also a lot harder to forget to document new properties (and much easier to quickly spot undocumented properties) when you're explicitly defining them in a dedicated area of your code.
Without knowing too many specifics about the alphabetical data members of some Game object, mentioning p.a, p.b, etc. in the way that you have shown is a good way to expose exactly how the variable p is structured.
In the control flow of the code snippet you've shared, we can see exactly what fields the variable p has before performing any initialization or other operations on it.
It is possible that the object p has getters assigned to it with side effects:
Object.defineProperty(p, 'a', { get: function() {
window.universalConstant = 42;
return p._a;
});
Possible, but unlikely. Probably it's a misguided attempt at documentation as #PaulD suggests.

Generation of getters and setters in Javascript compatible with Closure Compiler

I'm writing a library that I hope to be compatible with Closure Compiler in Advanced mode. Most objects in the library maintain an internal object of attributes that are frequently part of the API, which leads to my source files being filled with lots and lots of functions like this.
/*
* Get name.
*/
Layer.prototype.getName = function() {
return this.attrs.name;
}
/*
* Set name.
*/
Layer.prototype.setName = function(name) {
this.attrs.name = name;
}
I can think of a billion ways to optimize this to declutter my code a bit. One example: KineticJS, as per this related question, does something a bit like this:
Global.addGettersSetters = function(obj, property) {
obj['get'+property] = function() { return this.attrs[property] }
obj['set'+property] = function(val) { this.attrs[property] = val }
}
// Later that day, in our original object, we have:
Global.addGettersSetters(Layer, 'name');
My understanding is that this is a no-no with Closure Compiler--the names won't be shortened and the functions won't be optimized because I'm specifying the properties of Layer as strings.
So, is there a way for me to fully and properly define the interface without cluttering up my code? Something in the Closure Library I've overlooked, perhaps?
An alternative solution: is there a way to do C#-style properties in modern JS? In a way Closure Compiler finds permissible? I have the luxury of targeting Webkit and only Webkit with this library, so stuff that's not yet fully implemented is fine.
If the getters/setters are public anyway, then you need them to not be renamed in the minified js. That means having them use strings for names is fine - they won't be minified but that's what you wanted.
Yes, modern JS has getters/setters.
You cannot dynamically add a function which could then be compiled (and minified/obfuscated) by the Closure Compiler because that dynamic "addGettersSetters" function would only be used at runtime, so the compiler has no knowledge of what it could be creating. The downside of using the compiler is a lot of duplicate pre-compiled code, but the benefit is that the majority of the places where your getters and setters are used will either be minified or just changed to inline references to the variables.
Also, by putting in explicit getters/setters and properly annotating them with JsDoc annotations:
/*
* Set name.
* #param {string} name
*/
Layer.prototype.setName = function(name) {
this.attrs.name = name;
}
you can add some level of type safety to your code to ensure you get a warning during compilation if someone calls "setName(5)".
Otherwise I would follow Chris's suggestion and look into JS getters / setters (other reference here). I have not used these with the closure compiler though so I cannot vouch for them.
Sorry, I don't get the ne8il answer and why it was marked as the correct one.
You can do what you want by just adding .prototype between obj and [ like this:
function addGettersSetters(obj, property) {
// You can also add this if you don't want to declare attrs = {} each time
// if (!("attrs" in obj.prototype)) obj.prototype.attrs = {};
obj.prototype['get'+property] = function() { return this.attrs[property] }
obj.prototype['set'+property] = function(val) { this.attrs[property] = val }
}
And also writing the property name with capital letter. Then you can use it like this:
var Layer = function() { this.attrs = {}; };
// Or just: 'var Layer = function(){};' if you use the line commented above
addGettersSetters(Layer, 'Name');
var layer = new Layer();
layer.setName("John");
alert(layer.getName()); // "John"
Not a complete answer of the original question, just adding some info.
You can see how various JavaScript OOP frameworks handle getters/setters e.g. here: jsPerf.com - JavaScript Object Oriented Libraries Benchmark with getters and setters
is there a way for me to fully and properly define the interface without cluttering up my code?
Tan Nhu (original author of the benchmark) created his own OOP library jsface which is available at: https://github.com/tnhu/jsface
I like it, I use it for exactly this reason
EDIT: how are the getters/setters generator solved in TypeScript is mentioned e.g. in SO article get and set in TypeScript
For more complete list of other frameworks and their way of encoding getters/setters you can check List of languages that compile to JS · jashkenas/coffeescript Wiki · GitHub

Categories

Resources