Things will be clear when you see the following example.
function AddStyle(prob, value) {
Elem = document.getElementById('box');
Elem.style.prob = value;
}
// Here is, when usage.
AddStyle('backgroundColor', 'red');
As you see in the previous example, we have two parameters (prob is the property Name), (value is the value of property).
That example doesn't work, There are no errors Occur also.
I'm certain that the problem in this line Elem.style.prob = value; and especially here style.prob.
Variables aren't resolved in that way. Basically, you're code is looking for a property of style literally called prob. You'll have to access the property using brackets, since objects are indexed by property name. Something like:
Elem.style[prob] = value; // Access the property of style equal to the value of prob
This would be equivalent to:
Elem.style['backgroundColor'] = value;
Which would be equivalent to:
Elem.style.backgroundColor = value;
Demo
Related
I would like to set a value to an object which is into a deep structure.
Let's say the value of myObject.language.settings.color should be red.
Out of my field of vision. Setting this value is based on the following way:
const myObject = {};
myObject.language = {};
myObject.language.settings = {};
myObject.language.settings.color = 'red';
That is a long process if the objects before do not exist yet.
I am looking for a shorter way to handle this. E.g. using myObject.language.settings.color = 'red'; but that would return an error, that says myObject is not defined.
Is there a simpler solution than that?
I'm currently reading this somewhat outdated but fine React tutorial, and I spent hours looking at this little piece of trouble, which might be more Javascript-related than React-related. At a certain point, the author starts building a small notepad app, and then there's this code:
var onChangeNote = function (id, value) {
var note = _.find(notepad.notes, function (note) {
return note.id === id;
});
if (note) {
note.content = value;
}
onChange();
};
In the app, which can be viewed in full at the forementioned article or on the respective fiddle, we have a list of notes (which by itself is an array assigned to the notes property on a notepad object defined at the top of the script), and the selected one may be changed by the user, all while using React.
What really gets me is that this is the function responsible for changing the content of the note, in the note.content = value; line, but note is a variable that got its value from _.find() (it's the lodash variant, but I already tried replacing it with the vanilla JS array.find() and nothing changed), and yet, changing it appears to be updating the actual array, I found nowhere in the code any other instance of the selected note being changed, and the onChange() function just updates the view layer (therefore it doesn't do anything to the notepad itself), so this has to be it. So is the variable note referencing the actual respective item on the notepad.notes array it got its value from even though Javascript doesn't usually do that?
Maybe I'm missing something really obvious, but I cannot put my finger on it.
Basing from the source we can check that _.find doesn't create a deep copy of the object, it returns the object from the array.
Taken from: https://github.com/lodash/lodash/blob/4.6.0-npm-packages/lodash.find/index.js
function createFind(findIndexFunc) {
return function(collection, predicate, fromIndex) {
var iterable = Object(collection);
if (!isArrayLike(collection)) {
var iteratee = baseIteratee(predicate, 3);
collection = keys(collection);
predicate = function(key) { return iteratee(iterable[key], key, iterable); };
}
var index = findIndexFunc(collection, predicate, fromIndex);
return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
};
}
So yes, it returns the object "reference", and not a clone, so changing a property in it, changes the one in the array.
============
Here's an example regarding your question if javascript is pass by value or reference. Javascript is always pass by value except if the value passed is an object or array. Changing the value of a property to the object will also affect the original one. But changing the whole object will not affect the original one.
var arr = [{a: 1}, {a: 2}];
var x = arr.find(v => v.a === 1);
x.a = 5;
console.log(arr); // you'll see a is 5 here
x = 100; // we changed variable directly (note that x is the object that we extracted from the find function)
console.log(arr); // it's not changed, 5 is still the value
x = arr.find(v => v.a === 5); // let's get that object again
x = {a: 10}; // we replaced it with another object with same property but another value
console.log(arr); // still not changed
If I use get with defineProperty
Object.defineProperty(Object.prototype,'parent',{
get:function(){return this.parentNode}
});
and I can call it like: document.body.parent, then it works.
When I use value with defineProperty
Object.defineProperty(Object.prototype,'parent',{
value:function(x){
var temp=this.parentNode;
for(var i=1;i<x;i++){temp=temp.parentNode};
return temp
}
});
I can call it like: document.getElementsByName("newtag").parent(2), means to find the parent node of newtag's parent node.
But when I put them together it says Uncaught TypeError: Invalid property. A property cannot both have accessors and be writable or have a value.
How can I do it so that I can call it both ways, .parent & .parent(n)?
No jQuery
MDN describes the reason for the error
Property descriptors present in objects come in two main flavors: data
descriptors and accessor descriptors. A data descriptor is a property
that has a value, which may or may not be writable. An accessor
descriptor is a property described by a getter-setter pair of
functions. A descriptor must be one of these two flavors; it cannot be
both.
There is reason for this: the way you want would be ambiguous: if parent() was a function, then parent would return that function and the getter?
Also do not change object that you don't own. Such code would not be maintainable: if someone would define its own Object.prototype.parent() in his library, you could not use it. Prior to any use of any code, you would need to track down what was changed. This would be the same effort as writing everything from scratch.
Object.prototype is particularly bad idea to change: by the prototype you add the parent() function to every array, JSON object, webAPI objects... they don't have parentNode, so that function is completely useless to them, it is just a performance burden.
The previous two paragraphs are the reason why we have Object.defineProperty and not Object.prototype.defineProperty. Note that if it would be so, you could code myAPI.defineproperty(...) in the code below, which is shorter, BUT... the performance and the design... schrecklich.
You could code something like this
var myAPI = {
node: document.body,
level: 1
};
Object.defineProperty(MyAPI,'parent',{
get:function(){
var temp=MyAPI.node.parentNode;
// some sanity check should be performed here
for(var i=1;i<MyAPI.level;i++){temp=temp.parentNode};
return temp;
}
});
myAPI.node = document.getElementById("myNode");
myAPI.level = 2;
var grandFather = myAPI.parent; // actually returns the grandparent
but I doubt it would be useful.
No, you can't unfortunately. Instead you can create a bit different function that returns the first parentNode by default(if no parameter specified), otherwise it counts n parents.
Object.prototype.parent = function (n) {
if (!this.hasOwnProperty('parentNode')) return null;
if (!n || n === 1) return this.parentNode;
var temp = this.parentNode;
for (var i = 1; i < n; i++)
temp = temp.parentNode;
return temp;
};
Some notes: first of all, you should check if the Object has a property parentNode, otherwise the script will raise an exception. I used hasOwnProperty, but you can remove that line if you extend just HTMLElement.
Also, if n is 0 or 1, or it is not defined it will return the element's parentNode. Use it as element.parent() or element.parent(2).
Actual Error Code
JSC_INEXISTENT_PROPERTY
Summary
I get this error for the code listed and commented below.
I make the call like this. o_p.page holds user input and one of the properties is indeed tag
Mo.AppBAdder.image_element = vDomBMAdd(o_p.page);
o_p.page is populated by calling the object which hold user input like this:
o_p.page = text_object.getArray();
Is there a way I can do this so Google Closure does not feel the property does not exist?
Setting options is O.K. Also, I don't mind modifying the code a bit if needed.
The constructor for text reads in the user input like this:
Su.text = function (form_elements) {
this.text_object = {};
var key;
for (key in form_elements) { //*u
if (form_elements.hasOwnProperty(key)) {
this.text_object[form_elements[key].name] = form_elements[key].value;
}
}
return this;
};
Snippet of Code
function vDomBMAdd(bookmark_object) {
var link_element = document.createElement('a'),
image_element = document.createElement('img'),
page_element = $a('#' + bookmark_object.tag + '_page'), // error here - inexistent property
Reference
Inexistent means same thing as nonexistent
You have two options: create an extern file that declares the 'tag' property or, perhaps more appropriately given how the property is defined, use a quoted property access:
bookmark_object['tag']
Both of these approaches allow you to access "external" properties and are both compatible with ADVANCED optimizations but using an extern file allows you to declare the expected type of the value held by the property and thus provides better type checking.
okay im working with a friend and he sent me js file which included a variable that included the ternary operator. I cant figure out how to change it to if..else. can you help please?
also i noticed ".length" didnt have the normal "()" after it, is there a reason why?
var nextRadioTab = activeRadioTab.next().length ? activeRadioTab.next() : $('#contentslider div:eq(0)');
Does this work?
if (activeRadioTab.next().length) {
var nextRadioTab = activeRadioTab.next();
} else {
var nextRadioTab = $('#contentslider div:eq(0)');
}
In JavaScript, objects are more-or-less just a list of names pointing to values. Each name-value pair is called a "property".
These values themselves can be any type of value, including a function. If the value of a property is a function, we call that a "method".
Say you want an object to track the x and y coordinates of a point.
var point = { x: 10, y: 20 };
In this case we can just use simple values, because we don't need any behaviour more advanced than getting a value (alert(point.x)) or setting one (point.x = 10).
jQuery is designed to let your code work on different browsers; different browsers behave differently in lots of situations, so jQuery can't just let you set
element.text = "hello world"
because depending on the type of object element is, it will need to modify different properties on different browsers. For this reason, jQuery makes you use methods for things like this:
element.text("hello world")
The .length attribute of a jQuery object is simple; it's controlled by jQuery itself and doesn't need to do any special things in different browsers. For this reason, you just use it directly. If they needed more complicated behaviour, they would use a function/method instead:
var myObject = { length: 2 }; // myObject.length
var myObject = { length: function() { return 2; } }; // myObject.length()
var nextRadioTab;
if (activeRadioTab.next().length)
nextRadioTab = activeRadioTab.next();
else
nextRadioTab = $('#contentslider div:eq(0)');
length is a property of whatever next() returns, which is most likely the same type of object as activeRadioTab.