New to javascript here.
So I've been trying to learn to use Raphael.js and came across this http://jsfiddle.net/terryyounghk/AeU2r/ snippet of code.
Now if you look at line 167, there is this "if" statement I just don't understand.
Raphael.el.style = function (state, style, aniOptions)
{
if (!this.class)
{
this.class = style ? style : 'default';
this.aniOptions = aniOptions ? aniOptions : null;
// start assigning some basic behaviors
this.mouseover(function () { this.style('hover'); });
....
What class? What is it returning? Who is returning it?
What is it even checking? That it's a class?
From the Raphael documentation, Raphael.el is a way of adding one's own methods to the Raphael.element class. In general, the purpose of this class is to make it easier to manipulate SVG elements.
this.class in the code example has nothing to do with the the word class in the programming sense, as used in the preceding sentences. Nor (as far as I can see) is it part of the standard Raphael framework. Nor does it refer to the class attribute that HTML and SVG elements can have, and which is usually accessed in javascript using element.className or element.setAttribute('class', '...').
this refers to the element wrapper object (an instance of Raphael.element), and it seems that the person who wrote this method has simply used the name class to store some additional information in the element wrapper. (As pointed out in comments, this might be a bad idea because class is a reserved keyword in javascript; but anyway, it works.)
Specifically, in the example, this.class is initially undefined because it has not been assigned a value anywhere else in Raphael or in the code. In the if clause, !undefined evaluates to true, and in the following line, no value has been passed to the function for style, so that style ? style : 'default' evaluates to 'default'. So this.class is assigned the value 'default'. Afterwards, if you right-click on a shape and choose Use custom style, the class for that shape becomes 'custom'.
Note that javascript very easily lets you refer to, and assign values to, properties of an object that have not been initialised anywhere. It does not throw an error but simply returns undefined if no value has been assigned.
You can see all this by inserting a line that logs what's going on to the browser console:
console.log('style', state, style, aniOptions, this, 'class:', this.class);
and then using your browser's developer tools to see the output (JSFiddle).
It checks if a property class is defined and if not, it will assign it to style ? style : 'default'.
What you're seeing is simply a conditional statement, look at it as an abbreviated if-else-clause which checks if style evaluates to true or false, if it's true this.Class will have the value of style, if it's not it will get the value of 'default'.
I don't know how raphael.js works, but it looks to me like it is simply a html element class.
Related
My understanding is there are two equivalent ways to set CSS rules via JavaScript:
#1: element.style.setProperty(propertyName, value)
#2: element.style.propertyName = value
I have always favored the second, shorter method.
When it comes to CSS variables, I find I have to use an explicit setProperty call:
element.style.setProperty('--varName', value)
This approach has no effect on variables:
element.style['--varName'] = value
Why is this?
It's because DOM's Style function only understands HTML properties and not CSS properties. Defining CSS properties are listed in style's setProperty Function.
The .style[propertyName] expects a property name inside but does not support a custom property like .setProperty() does. If you pass --varName, you are passing the value assigned to the brackets.
For example, if --varName: 'blue', by saying .style['--varName'] = value, you are saying change the blue property to value. Since blue is not a property, it will not work.
You need to retrieve it from getComputedStyle
see : https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties#Values_in_JavaScript
To use the values of custom properties in JavaScript, it is just like standard properties.
// get variable from inline style
element.style.getPropertyValue("--my-var");
// get variable from wherever
getComputedStyle(element).getPropertyValue("--my-var");
// set variable on inline style
element.style.setProperty("--my-var", jsVar + 4);
document.body.style.setProperty('--varName', 'see i got stored even i`m a useless value');
let root = window.getComputedStyle(document.body );
let varNameValue= root.getPropertyValue('--varName');
console.log(varNameValue);
I have an odd situation in my Javascript code which I cannot explain. So far it has been observed only on Safari/Mac.
I have a line like this:
dict[id].sliceHovered = true;
And sometimes it throws an error:
Attempted to assign to readonly property.
Also:
dict is a bare blank object which I create myself with dict={}.
id is supplied by outside data, so it can be anything (I don't yet know which particular value causes this).
sliceHovered is obviously not a name of something that Javascript has built
in.
The objects in the dict are of my own type. They have a sliceHovered member, but it's not a Javascript defined property (as in Object.defineProperty()), just a regular property (the constructor executes this.sliceHovered=false).
"use strict" is on.
Object.freeze(), Object.seal(), Object.preventExtensions() and const are not used anywhere in the entire codebase.
Thus it's extremely puzzling as to how such an error could be thrown here. If I had an indexing error and dict[id] would be undefined or null, the error would be different. My only idea is that since the dict is created as dict={} then it inherits from Object and maybe id maps to some inherited property. But that means that the object returned from dict[id] would have to be read-only itself, because sliceHovered is definitely not a name of an existing Javascript property.
However I cannot think of any Javascript objects that would be intrinsically read-only like that.
Any ideas what could be wrong here?
You can check this situation
My only idea is that since the dict is created as dict={} then it inherits from Object
with: var dict = Object.create(null);
Also try to use Object.getOwnPropertyDescriptor(dict, id) to make sure descriptors have right values.
So I learned a bit about the hidden class concept in v8. It is said that you should declare all properties in the constructor (if using prototype based "pseudo classes") and that you should not delete them or add new ones outside of the constructor. So far, so good.
1) But what about properties where you know the type (that you also shouldn't change) but not the (initial) value?
For example, is it sufficient to do something like this:
var Foo = function () {
this.myString;
this.myNumber;
}
... and assign concrete values later on, or would it be better to assign a "bogus" value upfront, like this:
var Foo = function () {
this.myString = "";
this.myNumber = 0;
}
2) Another thing is with objects. Sometimes I just know that an object wont have a fixed structure, but I want to use it as a hash map. Is there any (non verbose) way to tell the compiler I want to use it this way, so that it isn't optimized (and deopted later on)?
Update
Thanks for your input! So after reading your comments (and more on the internet) I consider these points as "best practices":
Do define all properties of a class in the constructor (also applies for defining simple objects)
You have to assign something to these properties, even if thats just null or undefined - just stating this.myString; is apparently not enough
Because you have to assign something anyways I think assigning a "bogus" value in case you can't assign the final value immediatly cannot hurt, so that the compiler does "know" ASAP what type you want to use. So, for example this.myString = "";
In case of objects, do assign the whole structure if you know it beforehand, and again assign dummy values to it's properties if you don't know them immediatly. Otherwise, for example when intending to use the Object as a hashmap, just do: this.myObject = {};. Think its not worth indicating to the compiler that this should be a hashmap. If you really want to do this, I found a trick that assigns a dummy property to this object and deletes it immediatly afterwards. But I won't do this.
As for smaller Arrays it's apparently recommended (reference: https://www.youtube.com/watch?v=UJPdhx5zTaw&feature=youtu.be&t=25m40s) to preallocate them especially if you know the final size, so for example: this.myArray = new Array(4);
Don't delete properties later on! Just null them if needed
Don't change types after assigning! This will add another hidden class and hurt performance. I think thats best practice anyways. The only case where I have different types is for certain function arguments anyways. In that case I usually convert them to the same target type.
Same applies if you keep adding additional properties later on.
That being said, I also think doing this will lean to cleaner and more organized code, and also helps with documenting.
Yeah, so one little thing I am unsure remains: What if I define properties in a function (for example a kind of configure() method) called within the constructor?
Re 1): Just reading properties, like in your first snippet, does not do anything to the object. You need to assign them to create the properties.
But for object properties it doesn't actually matter much what values you initialise them with, as long as you do initialise them. Even undefined should be fine.
The concrete values are much more relevant for arrays, where you want to make sure to create them with the right elements (and without any holes!) because the VM tries to keep them homogeneous. In particular, never use the Array constructor, because that creates just holes.
Re 2): There are ways to trick the VM into using a dictionary representation, but they depend on VM and version and aren't really reliable. In general, it is best to avoid using objects as maps altogether. Since ES6, there is a proper Map class.
I was trying to determine the best way to observe a variable's value and track its changes, for example 'language' or 'time-zone', then when it will be changed take some actions depending on the new value.
I thought of using setInterval, but I have many 'interval's in my website, so I don't want to overuse it, I'm worried that it may affect the user experience. Instead I found my self compelled to trigger the actions which I want to be done after the value changes in each method may change the variable's value, this is simple but makes my code a bit tightly coupled.
what do you suggest for that.
It seems like Object.observe would be pretty much exactly what you need; unfortunately it is currently proposed as a "post ECMAScript 6" spec, so it will be a while until it is widely available in browsers. There are shim implementations though (e.g. here or here), which could give you the same functionality in current browsers.
An alternative approach would be wrapping the object in question in a direct proxy, but those are part of ES6, and also not widely adopted by browsers yet.
In languages like C++, you'd do this with accessor methods.
For example, instead of accessing a property of a class with something like foo.bar, you'd say foo.getBar().
getBar() would look something like this:
this.getBar = function(){
console.log("bar was accessed");
return bar;
}
You should also have a method to set the value of bar, i.e.
this.setBar = function(newBar){
console.log("Setting the value of bar");
bar = newBar;
}
These methods will give you more control of your variables, too. For example, if someone tries to assign a string to something that should be an integer, you could throw an error. Or if you have a variable called "length", you could throw an error if someone tries to make it less than zero.
You should use Object.prototype.watch() to track variable's change
The watch() method watches for a property to be assigned a value and
runs a function when that occurs.
Watches for assignment to a property named prop in this object,
calling handler(prop, oldval, newval) whenever prop is set and storing
the return value in that property. A watchpoint can filter (or
nullify) the value assignment, by returning a modified newval (or by
returning oldval).
If you delete a property for which a watchpoint has been set, that
watchpoint does not disappear. If you later recreate the property, the
watchpoint is still in effect.
To remove a watchpoint, use the unwatch() method. By default, the
watch method is inherited by every object descended from Object.
there is not standard, but you can use the gist polifill created by eli-grey
Anyway this is a duplicate of Listening for variable changes in JavaScript or jQuery
I wrote an own document method and it works. Consider the use of it like this:
document.myMethod();
How can I dynamically find out what dot notations were used before myMethod?
document.getElementsByTagName('div')[0].myMethod();
I tried this but it does not work. Any ideas?
Update: I'm making my own getElementsByClass('class'). So I have to know what elements should be checked. document.myMethod() should check all of the elements but document.getElementById('id').myMethod() only the childs of #id. How do I do that?
First of all, myMethod does not exist on 'all' DOM Elements unless you put it on Element.prototype etc, and you really don't want to go down this path.
But if you do, then this will refer to the Element on which the method is invoked on.
Chaining dot notation functions is (I think) just syntactic sugar - you're basically calling the last function on the output of the previous function. As far as I'm aware myMethod() would have no way to know what the function was that provided it's input was, unless you provided it as some kind of parameter on the function, for instance:
document.getElementsByTagName('div')[0].myMethod('getElementsByTagName');
Why do you want this information?