Set property value - javascript

I need to change the value of a javascript property but nothing seem to work. This is what I tried:
var test = allProducts[i]; // allProducts[i] comes from the database
console.log("TestProp BEFORE = " + test.get("TestProp"));
This prints out my TestValue.
Now I try to change the value and I tried all 3 syntax suggestions below (not at the same time of course):
test.TestProp = "kisses";
test["TestProp"] = "kisses2";
test['TestProp'] = "kisses3";
console.log("TestProp AFTER = " + test.get("TestProp"));
But this once again prints my TestValue.
What am I missing? Could it be that the object is somehow locked?

Usually, when you see something like SomeObject.get('attrName') in the code, it's a sure-sign SomeObject is actually not a plain JS object. Many popular frameworks (including Backbone) and libraries (jQuery) use the following approach: instead of enhancing native/host Objects, they put those into properly formed containers ('favor composition over inheritance' principle).
The bottom line is that while it might be possible to assign properties to these wrapper-objects (with bracket or dot notation), it's meaningless. Instead one has to use proper setter methods - most commonly, it's set().
In your case, that resolves to...
test.set('TestProp', 'some_kisses_value');
... where the first param is the name of attribute/property, the second one is its value.

Related

Haxe Javascript: get and set property by its name without using Reflect

I want to be able to set and get a property value by its name without using the Reflect API.
I'm making some sort of a tween engine, animating hundreds of objects and the call to the function Reflect.getProperty and setProperty is taking quite some CPU time.
Is there a way to bypass the Reflect API without having to inject raw javascript inside my Haxe code ? (so it can also be used on other platforms than js)
So instead of doing this:
finalValue = Reflect.getProperty(object, propertyName);
I would like to be able to do this:
finalValue = object[propertyName];
thanks.
What about going untyped?
// set
untyped object[propertyName] = 15;
// get
var value = untyped object[propertyName];
Try it yourself: http://try.haxe.org/#5b61e
Warn Going untyped lets you omit the type system and is more error prone. If you use instances with Haxe properties (getter/setters) it might give unexpected results. That's why using Reflect is considered safer.
You need to be careful when using "untyped" with properties that are getters/setters and standard properties, because the calls are slightly different.
eg:
// set
untyped object["set_" + propertyName] = 15;
// get
var value = untyped object["get_" + propertyName];
Typically what we do with our tween library is do a check up front when the property is mapped to see if it is a getter/setter and store this information for runtime use.

Dynamically Setting a JavaScript Object's Method's Source

I've recently been working on a nice little JavaScript game engine that works a lot like Game Maker, but lets people create basic JavaScript games within a browser. Every instance of every object will have it's own preset methods, which the runner will iterate through and execute. I'm trying to find a way to let the user / creator dynamically edit any of the methods source code. When I say 'preset methods', I mean blank methods stored under specific preset names within the objects / object instances. Here's a basic example:
var newObject = object_add("object_name"); // Adds a new object 'blueprint' and returns the reference.
The function object_add(); creates a JavaScript object, and adds a number of preset methods to it, such as:
create
destroy
step
draw
.. and many more
Each of these methods will have no code in them to start with. I need to let the creator dynamically change any of the methods source code. I could simply overwrite the variable that points towards the method, with a new method, but how can you set method's source code using a string?
I know that something like:
newObject.create = function(){textbox.innerHTML};
definitely wouldn't work. Any ideas?
Many thanks,
Dan.
Looks like you want to use eval function, but it's generally a bad idea.
The answer was found at: Creating functions dynamically in JS
Here's the answer (copied from the other page).
Well, you could use Function, like in this example:
var f = new Function('name', 'return alert("hello, " + name + "!");');
f('erick');
//This way you're defining a new function with arguments and body and assigning it to a variable f. You could use a hashset and store many functions:
var fs = [];
var fs['f1'] = new Function('name', 'return alert("hello, " + name + "!");');
fs['f1']('erick');
//Loading xml depends if it is running on browser or server.
Thanks, #CBroe https://stackoverflow.com/users/1427878/cbroe

Change meaning of ["foo"] in Javascript?

I'd like to make foo["bar"] return the bar field value normally, but if it doesn't exist, look it up in another object to find it there. Is it possible to replace how [] works?
Why? I am porting a 6 year old Javascript application to AngularJS. In the existing app, there's (of course) one global variable (let's call it i2) that's used as a namespace that has everything in the app attached to it.
i2.models.fooModel.bar += 1; //and the rest of the app is similar
If that's not enough responsibility, i2 is also used as a registry of application "cells" like so:
var myCell = i2["MyCell"];
I'm breaking the global's fields into AngularJS services. The cell lookup feature is also broken out into another servicer "cell registry" service. Since this application has existing plugins that we'd like to be backwards compatible with, I'd like the code in the existing plugins like:
var myCell = i2["MyCell"];
... to still work (though deprecated). Is there a way I can replace the [] function in i2 to look up the field in i2, and if it doesn't exist, look it up in another object (the cell registry)?
No, you cannot directly and literally change the meaning of
i2["MyCell"]
because this is the design of the language and that typically can't be changed (and it would be terrible if you could). However, you can do something like this:
function lookupVar(key) {
var value = i2[key];
if(typeof value !== "undefined") {
return value;
}
// do whatever you want to do now that it couldn't be found
}
var myCell = lookupVar("MyCell");
Of course this can be extended to handle other things than just a single variable i2. It might also not be needed at all and a simple
var myCell = typeof i2["MyCell"] !== "undefined" ? i2["MyCell"] : somethingElse["MyCell"];
might be enough (though it contains annoying duplication). If you know that if they key exists in i2["MyCell"], it won't be a falsy value (0, "", false, …), then this will suffice
var myCell = i2["MyCell"] || somethingElse["myCell"];
Though it's not very future-proof.
Yes, you can use getters (don't work in IE8) or Proxy (not recommended for production code)...
Is there a way I can replace the [] function in i2 to look up the field in i2, and if it doesn't exist, look it up in another object (the cell registry)?
Or just think about prototypes.

Javascript/jQuery variable, what is the proper way to use a var?

I am sorry if this is a dumb or easy question but I am fairly new to Javascript/jQuery. The past month I have really started to delve into the land of scripting and have seen two different, maybe three, ways people use var in Javascript/jQuery.
The way I use a var is like so,
var nav = $('nav');
nav.hide();
A very common way I have seen people use vars,
var nav = $('nav');
$(nav).hide();
From the answers,
var $nav = $('nav');
$nav.hide();
From what I have learned from searching through Google is what you typed inside the variable is saved there to later be used. I then figured if I wrote the $() around the var when I was using it, it would duplicate the $(). Yet both ways seem to work so I know it does not duplicate it and therefore can tell that it is the same thing.
Is there a correct way to use vars or are both equally the same and it doesn't matter?
I apologize again if this is a known answer and will be happy to remove it if someone can show me the original question but I couldn't find anything on it.
A great bit of information from an answer that I didn't mark as the answer but I find to be very important.
var element = document.createElement("div");
$("body").append(element);
$(element).hide();
In the example above, $(element) is necessary, because it takes a DOM
object and converts it to a jQuery selector. jQuery functions only
work on jQuery selectors, so you couldn't simply do element.hide().
$() creates a new jQuery object. If you save a jQuery object to a variable it is pointless to create another jQuery object from it, although it still works. You will often see people wrap variables that were previously created as jQuery objects in $() purely due to bad practice and either forgetting it's already an object...or not understanding what they just created in the first place
Perhaps you may have seen
var $nav = $('nav');
$nav.hide();
Using the $ prefix is a common practice to denote that the variable is a jQuery object for code readability mostly
Both variables store a jQuery object, which has access to jQuery methods. The latter approach unnecessarily tries to re-wrap that jQuery object in another jQuery object. The former approach is 'correct,' in that it's more efficient and less, to be frank, silly.
I've seen this issue in a lot of places. People use a lot of $ when they don't need to. Some use it just as an ornament on their variable name, which adds to the confusion.
First of all, there are no jQuery variables, only JavaScript variables, and as you said, variables store information. When the right hand side begins with $(), you're storing the results of a jQuery function in the variable. In the vast majority of cases, what you'll be storing is called a jQuery selector.
In the case of var nav = $('nav'), what you're storing is a selector representing all the elements in the DOM that are nav tags, i.e. that look like <nav></nav> (or equivalent).
As others already mentioned, the $(nav) is taking the stored selector, and creating a new selector out of it. It accomplishes nothing and is redundant, and is a poor programming practice, even if it is a pervasive one.
However, there is a similar syntax that makes sense:
var element = document.createElement("div");
$("body").append(element);
$(element).hide();
In the example above, $(element) is necessary, because it takes a DOM object and converts it to a jQuery selector. jQuery functions only work on jQuery selectors, so you couldn't simply do element.hide().
As I mentioned at the top, some people also use $ as a decorator on their variable names, e.g. var $selector = $("nav"). The $ on the left hand side means nothing - it's just a character in a variable name, but they use it as a convention to remind themselves that they're storing a jQuery selector. I'd avoid it, simply because it adds to the confusion, but it's out there, so I just wanted to mention it.
var is used to create any kind of variable. Could be var diceRoll = 4 or var myMessage = "Hello!", or anything else.
$ is a function that jQuery provides, which behaves in different ways depending on what you pass to it. For example, if you pass it a string (e.g. 'nav'), it will find every nav element in the document and return a set of jQuery objects (elements) - one for each DOM element it finds. When you say var nav = $('nav');, you are assigning this set of jQuery objects to your nav variable, so you can work with it later. So far so good.
Instead of passing a string to $, you technically could pass jQuery objects back into the $ function, which is what you are doing when you say $(nav).hide();. DOING THIS MAKES LITTLE SENSE - it will just return the same array of jQuery objects, nav, which you put into it in the first place!!
Personally, I like to prefix any variable which holds a jQuery object with a $ sign, i.e. var $nav = $('nav');. This is just a convention that allows me to see at a glance that this variable holds a jQuery object (element) rather than a native DOM element, or integer, or so on. If I ever see $($myVar) in my code, I know it's probably time for bed...
Update: there are other things that it DOES make sense to pass into the $() function, apart from strings. Passing in a DOM element, for example (such as saying $(document)) creates a jQuery object representation of that DOM element, which can be very useful.
All of these answers are pieces to the entire answer . . . let me add yet another piece. :)
As others have said, the $(...) notation is a JQuery function that returns a JQuery object. Depending on what "..." is, determines how that is done.
Some examples:
if you put a selector, such as "div", in there, you will get a JQuery object that contains all of the DOM elements that match the selector pattern . . . in this case, all of the <div> elements.
if you pass a string representation of an HTML element (e.g., "<div></div>"), you will get a JQuery object that points to a newly created <div> element.
if you put a DOM node reference in there (e.g., one created by using document.getElementsByTagName("div")), it will create a JQuery object that points to that node(s) in the reference.
The whole point of this is that JQuery works with JQuery objects, so these various functions help programmers create them.
Now this is where we get to your question . . .
Each time you use $("..."), you are creating a brand new object, so, for example the following code will produce two unique JQuery objects, each of which pointing to the identical DOM elements:
var $firstObject = $("div");
var $secondObject = $("div");
So, if you do a comparison of them (like this ($firstObject === $secondObject)), they will not be seen as equal, because they are not the same object.
Now, let me do a slight variation of your second example to add a little more clarity. If you create a third variable and set it equal to the second one, like this:
var $thirdObject = $secondObject;
. . . you have two elements that are actually pointing to the same JQuery object, so they ARE actually equal (i.e., ($secondObject === $thirdObject) will evaluate as true).
Now finally, what you've shown with this peice of code:
$(nav).hide();
. . . is simply another example of trying to create a JQuery object . . . this time using another JQuery object. Doing this with that third variable that I created above, however, will now break the relationship that it has with the second variable . . . ($secondObject === $($thirdObject)) . . . they are no longer equal, because the two sides of the comparison no longer point to the same object. Much like the comparison between $firstObject and $secondObject from earlier, that comparison is using two unique JQuery objects.
However . . .
Unlike some of the other answers, I would disagree that it is a completely incorrect form of coding . . . while I would never use it in the situation that you provide in your example, passing a JQuery object into the $(...) function is essentially the same thing as using .clone(). The two $bar assignments below are functionally equivalent:
var $foo = $("<div></div>");
var $bar = $($foo);
var $bar = $foo.clone();
The JQuery API even makes the same point (http://api.jquery.com/jQuery/):
Cloning jQuery Objects
When a jQuery object is passed to the $() function, a clone of the object is created. This new jQuery object references the same DOM elements as the initial one.
EDIT :
Out of curiosity, I set up a quick test at jsPerf and the $($foo) approach is pretty significantly faster than .clone() in Firefox, IE9, and Chrome: http://jsperf.com/clone-technique-test
var nav = $('nav');
$(nav).hide();
nav is already a jQuery object so $(nav) is useless.

Can you add a function to a hijacked JavaScript Array?

This question is related to What are the best practices to follow when declaring an array in Javascript?
Let's say a client, let's call them "D. B. Cooper", has a first requirement that the following code must run before any other JavaScript code:
Array = function(){
alert('Mwahahahaha');
};
Furthermore, Cooper requires that custom functions must be added to the built in Array object (not the hijacked one). For example, if Array was unhijacked, this would be done with:
Array.prototype.coolCustomFunction = function(){
alert('I have ' + this.length + ' elements! Cool!');
};
Which would afford:
var myArray = [];
myArray.coolCustomFunction();
However, this is not compatible with the first requirement. Thus, how can you best fulfill both of D. B. Cooper's requirements?
Note: D.B. even wrote a test fiddle to help make sure solutions meet his requirements...what a guy!
Update:
For those of you who like a challenge: please try to find an unhijackable cross-browser solution to this problem. For example, here's an even more hijacked test case (thanks for reformatting this Bergi) that hijacks Array, Object, Array.prototype.constructor, and Object.prototype.constructor. Thus far, it looks like there may be a browser-specific solution to this (see Bergi's comment on his answer, and let us know if you find a way to hijack it in FF), but it is unclear at this point if there is a cross-browser solution to this.
Whatever your Array function/constructor is, the literal syntax for arrays will always generate "real" arrays with their [[prototype]] set to the native array prototype object (once, this was a security vulnerability). So, you can always access that by using
Object.getPrototypeOf([])
even if Array or [].constructor are hijacked. (Will of course not work when Object is hijacked, then it get's really complicated)
(Brought D.B. down!)
If you want to use a workaround, in FF the following line will always work (and is not hijackable):
[].__proto__.coolCustomFunction = coolCustomFunction;
Since Array is not necessarily equal to [].constructor, you could use [].constructor to refer to the original Array function since this is hardwired and Array = function(){} won't alter it.
Array = function () { alert("foo")};
// this will always point to the original Array
[].constructor.prototype.foo = "bar";
var myArray = [0, 1];
alert(myArray.foo) // alerts "bar"
http://jsfiddle.net/yXPJ8/5/
Yes ... you just did ... but you created the array using [] .. if you use new Array() it works fine ...
See example here

Categories

Resources