So I'm trying to make a function that will have a random name generated on page load, but I'm having problems calling the method later.
This is what I got so far:
var methodName = Math.floor(Math.random()*1000001);
window[methodName] = function(){
alert("It works!");
}
window.onload = function start() {
methodName();
}
But I'm having problems calling it, since methodName(); would actually be a random number. So how could I call the methodName() function?
You can reference the property the same way that you set it:
window[methodName]();
If you're trying to make a function that can't be found by code loaded later in the page for security reasons, you should know that properties are of window are enumerable by default, and JavaScript's PRNG is not crypto-strong.
#MikeSamuel that's exactly what I'm trying to do.
If you had a crypto-strong source of randomness then you can use a lock&key approach to make a function that can only be called by someone who knows the secret.
For example,
(function () {
// Multiple calls to a secure source of randomness could get you more entropy than 64B.
var key = Math.random() + '/' + Math.random() + '/' + Math.random();
var sensitiveFunction = function () { alert("Don't leak me"); }
var slice = [].slice;
function lock(f) {
var g = f;
f = null; // arguments is widgy and leaky in non-strict mode.
return function (unlocker, var_args) {
if (key !== unlocker) { throw new Error(); }
return g.call(this, slice.apply(arguments, 1));
};
}
myGlobal = lock(sensitiveFunction);
})();
which uses the secret to wrap a function in one whose toString() does not return sensitive code, and which will only be callable by code that can read var key.
Is Math.random() cryptographically secure? discusses some alternatives to Math.random for strong nonces in JavaScript but I don't have personal experience with any of them.
This isn't practically useful unless you can get key out of this closure to code that needs it, so you need to have a secure communication channel to that code. You probably also want to have any script that defines this go through <script> elements and delete their text content from the DOM so that the body of the sensitive function can't be read that way.
I believe some frameworks like waterken use the URL fragment to seed web applications with secrets and then use techniques like this within the page to keep them from prying code.
Note that making properties with unpredictable names un-enumerable does not protect them.
In EcmaScript 5, getOwnPropertyNames does not respect enumerability. The only standardized way to get truly un-enumerable properties is with weak maps and a closely held object token and that will have to wait for EcmaScript 6 to be in an actual spec though browser vendors are implementing a lot of ES6 speculatively.
Related
This code from ryan niemeyer on this blog bost declares an empty function(named result) and then adds properties to the function:
ko.dirtyFlag = function(root, isInitiallyDirty) {
var result = function() {},
_initialState = ko.observable(ko.toJSON(root)),
_isInitiallyDirty = ko.observable(isInitiallyDirty);
result.isDirty = ko.computed(function() {
return _isInitiallyDirty() || _initialState() !== ko.toJSON(root);
});
result.reset = function() {
_initialState(ko.toJSON(root));
_isInitiallyDirty(false);
};
return result;
};
What advantage does this serve over simply creating an object and assigning the same properties before returning the object?
edit
in response to the comment requesting how i would expect it to look:
either declaring
var result={};
in the declarations, or as a style thing:
ko.dirtyFlag = function(root, isInitiallyDirty) {
var _initialState = ko.observable(ko.toJSON(root)),
_isInitiallyDirty = ko.observable(isInitiallyDirty);
return {
isDirty : ko.computed(function() {
return _isInitiallyDirty() || _initialState() !== ko.toJSON(root);
}),
reset : function() {
_initialState(ko.toJSON(root));
_isInitiallyDirty(false);
}
};
};
but the semantics are irrelevant - what does a shell of a function returned provide to the consuming code/developer calling the function?
In the link you posted, the author states
When ko.toJS runs, it will just see a plain function and ignore it.
In other words, he is using the fact that the framework he is using will ignore functions in the context where he is using it, whereas if he had used an object the framework would not ignore it.
He never intends to call the function, just to use it as a place to store his dirty flag while tricking the knockout framework into ignoring it.
It's just another way to create an object, I do not believe it has any difference to doing it one way or another. sometimes just a style preference, sometime just the way a programmer likes to do something. (just like using var that = this, or using a function's bind method. both legit and both ways of passing context).
Here is a detailed post on creating objects in JavaScript from MDN
Creating an object and declaring an empty function in JavaScript are way to create an object. In JavaScript things are objects and there are many ways to create them. No one way is much better than the other. Although from ECMAScript5 the better way to do it is Object.create.
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();
};
}
I need to transfer JavaScript Objects through JSON and transfer it's functions as well. I found a working version of getting the Strings of Functions and transfering them. Then i can evaluate them again.
//Create the function
var myFunction = function(){alert('Hello, my Function!');}
//get the functions String reprensentation
var myFunctionTransferString = myFunction.toString();
//Now we transfered the object and want to have a function back
var myTransferedFunction = eval('(' + myFunctionTransferString + ')');
//call the transfered function
myTransferedFunction();
Here i have a jsfiddle for this: http://jsfiddle.net/bMjug/
This is working in Firefox, Chrome, and Safari as it should (but as you can guess not in that great pieace of microsoft software called Internet Explorer).
At the line where i want to evaluate the function i get the message fn is null or not an object in IE8.
Actually i found a solution for this but i really don't like this solution. If i put the variable declaration into the String i'm evaluating and remove the parantheses because i'm not expecting an object anymore that would do what i want:
eval('var myTransferedFunction = ' + myFunctionTransferString);
But i find this kind of hacked and bad solution.
Does anyone now a better one for this problem?
Thanks in advance
For what it's worth, the problem is caused by JScript incorrectly interpreting this:
(function x() {})
as a FunctionDeclaration and not a FunctionExpression, so doing a statement-eval instead of an expression-eval. Similar to what happens with {} object-literals without the wrapping brackets. You could get around it by doing something to more explicitly push it into parsing an expression, eg:
eval('['+myFunctionTransferString+'][0]');
But seriously don't. Never rely on the string representation of a function, it is not standardised and there are many browser differences.
You couldn't usefully preserve a function even if function decomposition were reliable, since there is much more to a function than the textual representation of its source. The closures it includes cannot be represented, and closures are ever-more common in real-world JavaScript.
I'm afraid there is no cheap way to serialise/re-instantiate JavaScript objects in general. The JSON subset is the reliable subset, the rest you'll have to code your own ad hoc serialisation formats for.
Functions are not part of the JSON specification. Remember the JSON specification is a subset of JavaScript's syntax.
So your 'hacked' solution is actually the more correct one.
Heres some hacked solutions:
var fn = function() { alert("some text"); }
var fnFromString = new Function("return " + fn.toString()); // function anonymous() { return function() { ... } }
fnFromString = fnFromString(); // function() { alert("some text"); }
and if you executing script immediately:
eval("(" + fn.toString() + ")()"); // fn executed.
So, first question here - please be gentle.
I'm working on a fairly JavaScript heavy project with a few other developers from various non-web programming backgrounds and we've decided to try and use public and private methods and properties in our JavaScript psuedo-classes purely as a good coding practice (ie. we know theres no actual advantage or security in it)
We've toyed with a few different ways of doing public & private (ie. using locally scoped variables and functions with privileged methods for public consumption) and we've currently settled on having our JavaScript class constructors actually return an object that represents only their public interface, effectively hiding everything else.
Here's an example:
function MyObject()
{
var _this = this;
this._privateProperty = 'somevalue';
this._privateMethod = function()
{
// Do Something
}
this.public =
{
publicProperty : _this._privateProperty,
publicMethod : function(){ return _this.privateMethod() }
}
return this.public;
}
Which when instantiated and logged in Chrome:
var obj = new MyObject();
console.log(obj);
Outputs:
> Object
> publicMethod: function (){ return _this.privateMethod() }
> publicProperty: "somevalue"
>__proto__: Object
Now to my question:
Because were returning the public interface from the constructor as new object, when you console.log you'll notice that it identifies itself as > Object - whereas if we don't return that public interface it is identified as > MyObject.
Ideally, we'd like to have the latter displayed for debugging purposes and I know how to access the "MyObject" name of the contstructor with _this.constructor.name, but have no idea how to set it so its recognized that way.
Does anyone know how to manually set this?
Note:
I know this is in some ways a bastardization of JavaScript convention and trying to fit a square peg in a round hole, but we found it to be a very obvious and readable way to accomplish what we were trying to do. I'm open to suggestions on how to accomplish this with a different design, but I'm ultimately looking for an answer that fits our current design.
You should be able to set the 'toString' function of the obj. E.g.
obj.constructor.prototype.toString = function() { return "MyObject"; }
This will make the console.log display 'MyObject' instead of Object.
Despite the valiant efforts of my team members and the very helpful users of this site who offered solutions we've decided that this design is ultimately unmaintainable and have instead opted for a design that is a little less obvious, but achieves the same result.
function MyObject()
{
var _privateProperty = 'somevalue';
function _privateMethod()
{
// Do Something
}
// Public Interface
this.publicProperty = _privateProperty;
this.publicMethod = _privateMethod;
}
With this approach we are basically making EVERY property and method private by default, and at the bottom of our "classes" we expose the ones we want available publicly. I think most would agree that this follows the normal JavaScript convention better than our initial design, which hopefully means it will be easier to read and maintain for others.
Thanks again for those who took the time to try a come up with a solution.
This is kind-of weird (but then, you're probably used to that by now :-) but you could override the actual "MyObject" constructor with a local one:
function MyObject() {
function MyObject(p) {
for (var k in p) if (p.hasOwnProperty(k)) this[k] = p[k];
}
this.public = new MyObject({
publicMethod: function() { /* whatever */ },
publicProperty: "something"
});
return this.public;
}
Clearly you could factor out the code for most of that, so that you could have a function that, given a function to perform the initialization for a particular class, would set all that up for you. (Having to maintain a system like you're proposing without some library support to handle the details seems like a real chore, and long-term a very hard thing to keep working, and even harder to change.)
I'm pretty new to Javascript, as my SO profile will attest.
I've just been reading up on a few tutorials and come across something I don't totally understand in regards to Object Orientation and Encapsulation when applied with Javascript.
The tutorial stated that Javascript objects can be declared like this:
var myCustomObject = new Object();
And that you can give it instance variables like this:
myCustomObject.myVariable = "some value";
myCustomObject.myOtherVariable = "deadbeef";
Finally, it states that you can create a template function to create new objects like this:
function CustomObject(myVariable, myOtherVariable)
{
this.myVariable = myVariable;
this.myOtherVariable = myOtherVariable;
}
I also know that you can create and assign values to variables that do not yet exist and as a result are declared implicitly, as is seen in the example, where myCustomObject didn't have a myVariable, but now it does.
So, my question is: What is there to prevent new variables from being added at some other point in the code. If I'm trying to learn how an object works and what I can/should do with it, I may never see the variable additions that could well be in some other .js file, and thus not have a full understanding of the object...
Also, how do I know that some object that has just been created won't suddently turn out to have 60 more variables added later on in code that weren't mentioned at all at creation time?
How are you meant to be able to understand what an object can contain at a glance if more can just be added to it "willy nilly"?
I can't quite believe that I'm about to quote Spiderman but …
With great power comes great responsibility
JavaScript is powerful and flexible and gives programmers lots of freedom. It doesn't come with features designed to stop programmers writing bad code. When you write JavaScript, you are responsible for making sure the code is good, not the language.
You can't, there's nothing that stops me from doing whatever I want with your objects ;) However, you don't have to use those variables..
One thing you can do is to play with scopes, example:
function myConstructor()
{
var myState = {}; //Create new, empty object
myState.text = "Hello World!";
this.say = function() {
alert(myState.text);
};
}
In this simple example you can store you internal variables in myState (or "var text = '';" etc) and they aren't accessible from outside since they are not members of an object, they are just private variables in your function. And, as you can see, the function say still has access to it.
Short answer: Absolutely nothing.
Long answer:
Javascript is a dynamic language in more ways than just the type system. Every object like thing in the language is basically an associative array which can be added to as you please. Variables (which can obviously contain these object like things) exist only within their function scope.
You can use this point to simulate private members which can tame the situation somewhat. I've posted examples of this several times before so I'll just refer you to the definitive guide on the subject: http://javascript.crockford.com/private.html.
As far as adding new members to objects in a way you did not intend goes, there's really nothing to be done that's just the way the language is.
Afterthought:
When approaching javascript try to remember it's really not an OOP language it's a weird and wonderful mix of functional / prototypical with a few OOP ideas. Don't be fooled by the java like syntax, you'll have a much better time if you play to the languages strengths rather than ape java.
Javascript objects are transformers (TM), they can turn from one form to another.
In practise this only happens to enrich objects, never to cause harm. It allows one to for example upgrade an existing 'class' rather then subclassing or to decorate instances again removing the need to create even more 'classes'. Take the following example:
var Vehicle = function(){}
var factory = {
create: function(name, props){
var v = new Vehicle();
v.type = name;
for(var prop in props) {
v[prop] = props[prop];
}
}
}
var bike = factory.create('Bike', {
wheels: 2
});
var car = factory.create('Car', {
wheels: 4,
doors: 5,
gear: 'automatic'
});
var plane = factory.create('Airplane', {
wings: 2,
engines: 4
});
Imagine what the code above would take without dynamic objects and you couldn't do this:
// lets paint our car
car.color = 'candy red';
// bling!
car.racingStripes = true;
car.mirrorDice = true;
car.furryChairs = true;
You get to enrich/personalize objects in a much easier way.