Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

JavaScript: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=JavaScript Language Overview=
[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]<br />[[Category:Developing_with_Qt::Qt_Quick]]<br />[[Category:Developing_with_Qt::Qt_Quick::QML]]<br />[[Category:Developing_with_Qt::QtScript]]<br />[[Category:Developing_with_Qt::QtWebKit]]


This article provides an overview of the JavaScript language. The idea is to provide a thorough overview of all of the language’s features. You may want to read through this article from start to finish to learn about all the basic features of this language – especially when you are getting started with a JavaScript related technology.<br /> Whenever possible, you should try out the examples in an interactive console. Most Linux distributions ship with the [http://www.mozilla.org/js/spidermonkey/ SpiderMonkey] ''[mozilla.org]'' console (smjs). If you prefer using a native Qt-based console, try [https://github.com/unclefrank/qmlscriptconsole qtjs] ''[github.com]'' or [https://github.com/unclefrank/qmlscriptconsole qmlscriptconsole] ''[github.com]''. See the [[QML Script Console|<span class="caps">QML</span>_Script_Console]] article if you’re curious.
= JavaScript Language Overview =


==Introduction==
This article provides an overview of the JavaScript language. The idea is to provide a thorough overview of all of the language's features. You may want to read through this article from start to finish to learn about all the basic features of this language - especially when you are getting started with a JavaScript related technology.<br />Whenever possible, you should try out the examples in an interactive console. Most Linux distributions ship with the &quot;SpiderMonkey&amp;quot;:http://www.mozilla.org/js/spidermonkey/ console (smjs). If you prefer using a native Qt-based console, try &quot;qtjs&amp;quot;:https://github.com/unclefrank/qmlscriptconsole or &quot;qmlscriptconsole&amp;quot;:https://github.com/unclefrank/qmlscriptconsole. See the [[:QML_Script_Console]] article if you're curious.


JavaScript is a minimalistic dynamically typed scripting language. It is truly object-oriented, although it lacks support for classes. Frequently associated with client-side web development, JavaScript is a language of its own. Originally developed at Netscape and nowadays standardized as [http://www.ecma-international.org/publications/standards/Ecma-262.htm <span class="caps">ECMAS</span>cript-262] ''[ecma-international.org]'' , the language has found wide-spread use and circulates under various names. “JScript” is Microsoft’s derivative of the language. “JavaScript” was the original name chosen by Netscape when the language was introduced with Netscape 2. Adobe’s ActionScript was also based on <span class="caps">ECMAS</span>cript-262 before version 3 was released.
== Introduction ==


Qt has been supporting a JavaScript engine compatible with <span class="caps">ECMAS</span>cript-262 since Qt 4.3. This engine is called “QtScript” and was originally an independent implementation. Since Qt 4.5, QtScript has been based on JavaScriptCore from WebKit. Qt’s new markup language(<span class="caps">QML</span>) makes intense use of QtScript. Property values in <span class="caps">QML</span> are JavaScript expressions and are evaluated using QtScript.
JavaScript is a minimalistic dynamically typed scripting language. It is truly object-oriented, although it lacks support for classes. Frequently associated with client-side web development, JavaScript is a language of its own. Originally developed at Netscape and nowadays standardized as &quot;ECMAScript-262 (3rd and 5th edition)&quot;:http://www.ecma-international.org/publications/standards/Ecma-262.htm , the language has found wide-spread use and circulates under various names. &quot;JScript&amp;quot; is Microsoft's derivative of the language. &quot;JavaScript&amp;quot; was the original name chosen by Netscape when the language was introduced with Netscape 2. Adobe's ActionScript was also based on ECMAScript-262 before version 3 was released.


==The Type System==
Qt has been supporting a JavaScript engine compatible with ECMAScript-262 since Qt 4.3. This engine is called &quot;QtScript&amp;quot; and was originally an independent implementation. Since Qt 4.5, QtScript has been based on JavaScriptCore from WebKit. Qt's new markup language(QML) makes intense use of QtScript. Property values in QML are JavaScript expressions and are evaluated using QtScript.


JavaScript supports the following fundamental types:
== The Type System ==


* boolean
JavaScript supports the following fundamental types:<br />* boolean<br />* number<br />* string<br />* object<br />* function
* number
* string
* object
* function


New variables are introduced into the current scope using the ''var'' statement:<br />
New variables are introduced into the current scope using the ''var'' statement:<br /><code><br />var flag = false // a boolean<br />var x = 1., y = 2 // numbers can be integers and reals<br />var s1 = 'abc'; // a string<br /></code>


To query the type of a variable, use the ''typeof'' keyword. ''typeof'' returns the name of the type as a string.<br />
To query the type of a variable, use the ''typeof'' keyword. ''typeof'' returns the name of the type as a string.<br /><code><br />var x = 0; typeof x // 'number'<br />typeof { x: 1 } // 'object'<br />typeof typeof { x : 1 } // 'string'<br />typeof JSON.parse('{&quot;a&amp;quot;: 7}') // 'object'<br /></code>


Everything in JavaScript acts like an object.<br />
Everything in JavaScript acts like an object.<br /><code><br />1.3333333.toFixed(2) // '1.33'<br />7..toString() // '7'<br /></code>


Note that in JavaScript the expression ‘7.toString()’ can’t be interpreted correctly. ‘7.is parsed into a number and thereafter results in a syntax error.
Note that in JavaScript the expression '7.toString()' can't be interpreted correctly. '7.' is parsed into a number and thereafter results in a syntax error.


The primitive types ''boolean'', ''number'' and ''string'' are implicitly converted into objects when needed. For this purpose, the global object provides special constructor functions which can also be invoked manually:<br />
The primitive types ''boolean'', ''number'' and ''string'' are implicitly converted into objects when needed. For this purpose, the global object provides special constructor functions which can also be invoked manually:<br /><code><br />typeof 1. // 'number'<br />typeof new Number(1.) // 'object'<br />typeof new String('Hi!') // 'object'<br /></code>


Functions are special kinds of objects. They only differ from objects because they can be called and used as constructors. Properties can be added to functions dynamically:<br />
Functions are special kinds of objects. They only differ from objects because they can be called and used as constructors. Properties can be added to functions dynamically:<br /><code><br />function f(x) { return f.A * x * x }<br />f.A = 2.7
 
function Buffer() {}<br />Buffer.MAX_LINE_LENGTH = 4096<br /></code>


Usually those properties serve as global constants and therefore are written in uppercase.
Usually those properties serve as global constants and therefore are written in uppercase.


Objects themselves can be expressed using an array or object literal. Arrays have no separate type, but are specialized objects which use array indexes as properties:<br />
Objects themselves can be expressed using an array or object literal. Arrays have no separate type, but are specialized objects which use array indexes as properties:<br /><code><br />var o = { name: 'Werner', age: 84 } // allocate simple object<br />print(o.name, o[age])<br /> // both notations are valid, but [] notation allows generated strings<br />var a = ['a', 'b', 7, 11.]<br /> // an array, equivalent to {'0': 'a', '1': 'b', '2': 7, '3': 11.}<br />typeof o, a // 'object', 'object'<br /></code>


==Expressions==
== Expressions ==


The expression syntax follows mostly “C” syntax (as in C++ or Java). As a major difference, there is no sharp distinction between statements and expressions. Basically everything evaluates to something. Function declarations and compounds can be included on-the-fly:<br />
The expression syntax follows mostly &quot;C&amp;quot; syntax (as in C++ or Java). As a major difference, there is no sharp distinction between statements and expressions. Basically everything evaluates to something. Function declarations and compounds can be included on-the-fly:<br /><code><br />function f() {} // evaluates 'undefined'<br />function f() {} + 1 // evaluates to 1, because 'undefined' is casted to 0<br />(function() {}) // evaluates to a function object<br />(function() { return 0; })() // evaluates to 0<br />{1;2;3} * 2 // evaluates to 6<br /></code>


Expressions are separated by semicolons or line breaks.
Expressions are separated by semicolons or line breaks.


==Control Flow==
== Control Flow ==


===Branching===
=== Branching ===


Conditional branches follow “C” syntax.<br />
Conditional branches follow &quot;C&amp;quot; syntax.<br /><code><br />if (&amp;lt;expression&amp;amp;gt;)<br /> &lt;statement1&amp;gt;<br />else // optional<br /> &lt;statement2&amp;gt; // optional<br /></code>


The switch statement follows the same fall through semantics as in “C”:
The switch statement follows the same fall through semantics as in &quot;C&amp;quot;:


===Repetitions and Iterators===
<code><br />switch(expression) {<br /> case &amp;lt;expression1&amp;amp;gt;:<br /> &lt;statement-list1&amp;gt;<br /> break;<br /> case &amp;lt;expression2&amp;amp;gt;:<br /> &lt;statement-list2&amp;gt;<br /> break;<br /> …<br /> default:<br /> &lt;statement-listn&amp;gt;<br />}<br /></code>


Repeated actions can be expressed using ''do'', ''while'' and ''for'' loops:<br />
=== Repetitions and Iterators ===


For iterating objects JavaScript provides a special ''for-in'' statement:<br />
Repeated actions can be expressed using ''do'', ''while'' and ''for'' loops:<br /><code><br />do &lt;statement&amp;gt; while (expression)<br />while (expression) &lt;statement&amp;gt;<br />for (&lt;init-expression&amp;gt;;&lt;test-expression&amp;gt;;&lt;step-expression&amp;gt;) &lt;statement&amp;gt;<br /></code>


The given expression needs to be suitable for the left-hand side of an assignment. In the simplest case, it is just a variable declaration. Consider the following example:<br />
For iterating objects JavaScript provides a special ''for-in'' statement:<br /><code><br />for (&amp;lt;expression&amp;amp;gt; in &amp;lt;object&amp;amp;gt;) &lt;statement&amp;gt;<br /></code>
 
The given expression needs to be suitable for the left-hand side of an assignment. In the simplest case, it is just a variable declaration. Consider the following example:<br /><code><br />var a = [1,2,3,4]<br />for (var i in a)<br /> print(i, a[i]*a[i])<br />// '0', 1<br />// '1', 4<br />// '2', 9<br />// '3', 16<br /></code>


Here the variable ''i'' is assigned to all keys of the array ''a'' consecutively. In the next example, the left-hand expression is dynamically generated:
Here the variable ''i'' is assigned to all keys of the array ''a'' consecutively. In the next example, the left-hand expression is dynamically generated:
<code><br />var o = {a0: 11, a1: 7, a2: 5}<br />var k = []<br />for(k[k.length] in o);<br /></code>


The keys of ''o'' are copied to ''k''. The loop statement itself is left empty. For each member in o, the name is assigned to another member of k.
The keys of ''o'' are copied to ''k''. The loop statement itself is left empty. For each member in o, the name is assigned to another member of k.


===Labeled Loops, Break and Continue===
=== Labeled Loops, Break and Continue ===


In JavaScript, loop statements can be given labels. The ''break'' and ''continue'' statements break or continue the current loop. It is possible to break an outer loop from the inner loop by using the label name as shown in the following example:<br />
In JavaScript, loop statements can be given labels. The ''break'' and ''continue'' statements break or continue the current loop. It is possible to break an outer loop from the inner loop by using the label name as shown in the following example:<br /><code><br />label_x:<br />for (var x = 0; x &lt; 11; +''x) {<br /> for (var y = 0; y &lt; 11;y) {<br /> if ((x'' y) % 7 == 0) break label_x;<br /> }<br />}<br /></code>


==Objects and Functions==
== Objects and Functions ==


Objects are created using an object literal or the ''new'' operator.
Objects are created using an object literal or the ''new'' operator.


In the following example, a point coordinate is expressed as object literal:<br />
In the following example, a point coordinate is expressed as object literal:<br /><code><br />var p = { x: 0.1, y: 0.2 }<br /></code>


Objects are entirely dynamic sets of properties. New properties are introduced on first assignment. They can be deleted again by using the ''delete'' operator. To query if an object contains a certain property, use the ''in'' operator.<br />
Objects are entirely dynamic sets of properties. New properties are introduced on first assignment. They can be deleted again by using the ''delete'' operator. To query if an object contains a certain property, use the ''in'' operator.<br /><code><br />'z' in p // false<br />p.z = 0.3 // introduce new property 'z'<br />'z' in p // true<br />delete p.z // remove 'z' from p<br />p.z // undefined<br /></code>


Property values can be of any type including the ''function'' type. Methods in JavaScript are just function properties. When a function is invoked in method notation, it gets passed a reference to the object as an implicit argument called ''this''.<br />
Property values can be of any type - including the ''function'' type. Methods in JavaScript are just function properties. When a function is invoked in method notation, it gets passed a reference to the object as an implicit argument called ''this''.<br /><code><br />p.move = function(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />p.move(1, 1) // invoke a method<br /></code>


JavaScript allows any function to be called as a method of any object by using the ''call'' method, however, there are only a few cases in which you would want to use the ''call'' method.<br />
JavaScript allows any function to be called as a method of any object by using the ''call'' method, however, there are only a few cases in which you would want to use the ''call'' method.<br /><code><br />p2 = { x: 0, y: 0 }<br />p.move.call(p2, 1, 1)<br /></code>


==Prototype based Inheritance==
== Prototype based Inheritance ==


The second way of creating objects is by using the ''new'' keyword together with a '''constructor function''':<br />
The second way of creating objects is by using the ''new'' keyword together with a '''constructor function''':<br /><code><br />var p = new Object<br />p.x = 0.1<br />p.y = 0.2<br /></code>


The ''new'' operator allocates a new object and calls the given constructor to initialize the object. In this case, the constructor is called ''Object'', but it could be any other function as well. The constructor function gets passed the newly created object as the implicit ''this'' argument. In JavaScript there are no classes, but hierarchies of constructor functions which operate like object factories. Common constructor functions are written with a starting capital letter to distinguish them from average functions. The following example shows how to create point coordinates using a constructor function:<br />
The ''new'' operator allocates a new object and calls the given constructor to initialize the object. In this case, the constructor is called ''Object'', but it could be any other function as well. The constructor function gets passed the newly created object as the implicit ''this'' argument. In JavaScript there are no classes, but hierarchies of constructor functions which operate like object factories. Common constructor functions are written with a starting capital letter to distinguish them from average functions. The following example shows how to create point coordinates using a constructor function:<br /><code><br />function Point(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />var p = new Point(1, 2)<br /></code>


Each function in JavaScript can be used as a constructor in combination with the ''new'' operator. To support inheritance, each function has a default property named ''prototype''. Objects created from a constructor inherit all properties from the constructor’s prototype. Consider the following example:<br />
Each function in JavaScript can be used as a constructor in combination with the ''new'' operator. To support inheritance, each function has a default property named ''prototype''. Objects created from a constructor inherit all properties from the constructor's prototype. Consider the following example:<br /><code><br />function Point(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />Point.prototype = new Object // can be omitted here<br />Point.prototype.translate = function(dx, dy) {<br /> this.x ''= dx<br /> this.y''= dy<br />}<br /></code>


First we declared a new function called ''Point'' which is meant to initialize a point. Thereafter we create our own prototype object, which in this case is redundant. The prototype of a function already defaults to an empty object. Properties which should be shared among all points are assigned to the prototype. In this case, we define the ''translate'' function which moves a point by a certain distance.
First we declared a new function called ''Point'' which is meant to initialize a point. Thereafter we create our own prototype object, which in this case is redundant. The prototype of a function already defaults to an empty object. Properties which should be shared among all points are assigned to the prototype. In this case, we define the ''translate'' function which moves a point by a certain distance.


We can now instantiate points using the Point constructor:<br />
We can now instantiate points using the Point constructor:<br /><code><br />var p0 = new Point(1, 1)<br />var p1 = new Point(0, 1)<br />p1.translate(1, –1)<br />p0 = p1 // false
p0.translate = p1.translate // true<br /></code>
 
The ''p0'' and ''p1'' objects carry their own ''x'' and ''y'' properties, but they share the ''translate'' method. Whenever an object's property value is requested by name, the underlying JavaScript engine first looks into the object itself and, if it doesn't contain that name, it falls back to the object's prototype. Each object carries a copy of its constructor's prototype for this purpose.
 
If an object actually contains a certain property, or if it is inherited, it can be inquired using the ''Object.hasOwnProperty()'' method.<br /><code><br />p0.hasOwnProperty(&quot;x&amp;quot;) // true<br />p0.hasOwnProperty(&quot;translate&amp;quot;) // false<br /></code>


The ''p0'' and ''p1'' objects carry their own ''x'' and ''y'' properties, but they share the ''translate'' method. Whenever an object’s property value is requested by name, the underlying JavaScript engine first looks into the object itself and, if it doesn’t contain that name, it falls back to the object’s prototype. Each object carries a copy of its constructor’s prototype for this purpose.
So far, we have only defined a single constructor with no real object hierarchy. We will now introduce two additional constructors to show how to chain prototypes and thereby build up more complex relationships between objects:<br /><code><br />function Point(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />Point.prototype = {<br /> move: function(x, y) {<br /> this.x = x<br /> this.y = y<br /> },<br /> translate: function(dx, dy) {<br /> this.x ''= dx<br /> this.y''= dy<br /> },<br /> area: function() { return 0; }<br />}


If an object actually contains a certain property, or if it is inherited, it can be inquired using the ''Object.hasOwnProperty()'' method.<br />
function Ellipsis(x, y, a, b) {<br /> Point.call(this, x, y)<br /> this.a = a<br /> this.b = b<br />}<br />Ellipsis.prototype = new Point<br />Ellipsis.prototype.area = function() { return Math.PI * this.a * this.b; }


So far, we have only defined a single constructor with no real object hierarchy. We will now introduce two additional constructors to show how to chain prototypes and thereby build up more complex relationships between objects:<br />
function Circle(x, y, r) {<br /> Ellipsis.call(this, x, y, r, r)<br />}<br />Circle.prototype = new Ellipsis<br /></code>


Here we have three constructors which create points, ellipsis and circles. For each constructor, we have set up a prototype. When a new object is created using the ''new'' operator, the object is given an internal copy of the constructor’s prototype. The internal reference to the prototype is used when resolving property names which are not directly stored in an object. Thereby properties of the prototypes are reused among the objects created from a certain constructor. For instance, let us create a circle and call its ''move'' method:<br />
Here we have three constructors which create points, ellipsis and circles. For each constructor, we have set up a prototype. When a new object is created using the ''new'' operator, the object is given an internal copy of the constructor's prototype. The internal reference to the prototype is used when resolving property names which are not directly stored in an object. Thereby properties of the prototypes are reused among the objects created from a certain constructor. For instance, let us create a circle and call its ''move'' method:<br /><code><br />var circle = new Circle(0, 0, 1)<br />circle.move(1, 1)<br /></code>


The JavaScript engine first looks into the ''circle'' object to see if it has a ''move'' property. As it can’t find one, it asks the prototype of ''circle''. The circle object’s internal prototype reference was set to ''Circle.prototype'' during construction. It was created using the ''Ellipsis'' constructor, but it doesn’t contain a ''move'' property either. Therefore, the name resolution continues with the prototype’s prototype, which is created with the ''Point'' constructor and contains the ''move'' property, whereby the name resolution succeeds. The internal prototype references are commonly referred to as the '''prototype chain''' of an object.
The JavaScript engine first looks into the ''circle'' object to see if it has a ''move'' property. As it can't find one, it asks the prototype of ''circle''. The circle object's internal prototype reference was set to ''Circle.prototype'' during construction. It was created using the ''Ellipsis'' constructor, but it doesn't contain a ''move'' property either. Therefore, the name resolution continues with the prototype's prototype, which is created with the ''Point'' constructor and contains the ''move'' property, whereby the name resolution succeeds. The internal prototype references are commonly referred to as the '''prototype chain''' of an object.


To query information about the prototype chain, JavaScript provides the ''instanceof'' operator.<br />
To query information about the prototype chain, JavaScript provides the ''instanceof'' operator.<br /><code><br />circle instanceof Circle // true<br />circle instanceof Ellipsis // true<br />circle instanceof Point // true<br />circle instanceof Object // true<br />circle instanceof Array // false, is not an Array<br /></code>


As properties are introduced when they are first assigned, properties delivered by the prototype chain are overloaded when newly assigned. The ''Object.hasOwnProperty'' method and ''in'' operator allow the place where a property is stored to be investigated.<br />
As properties are introduced when they are first assigned, properties delivered by the prototype chain are overloaded when newly assigned. The ''Object.hasOwnProperty'' method and ''in'' operator allow the place where a property is stored to be investigated.<br /><code><br />circle.hasOwnProperty(&quot;x&amp;quot;) // true, assigned by the Point constructor<br />circle.hasOwnProperty(&quot;area&amp;quot;) // false<br />&quot;area&amp;quot; in circle // true<br /></code>


As can be seen, the ''in'' operator resolves names using the prototype chain, while the ''Object.hasOwnProperty'' only looks into the current object.
As can be seen, the ''in'' operator resolves names using the prototype chain, while the ''Object.hasOwnProperty'' only looks into the current object.


In most JavaScript engines, the internal prototype reference is called ''__proto__'' and is accessible from outside. In our next example, we will use the ''__proto__'' reference to explore the prototype chain. Because this property is non-standard, you should avoid using it in all other context.<br /> First let us define a function to inspect an object by iterating its members:<br />
In most JavaScript engines, the internal prototype reference is called ''&amp;#95;&amp;#95;proto&amp;amp;#95;&amp;#95;'' and is accessible from outside. In our next example, we will use the ''&amp;#95;&amp;#95;proto&amp;amp;#95;&amp;#95;'' reference to explore the prototype chain. Because this property is non-standard, you should avoid using it in all other context.<br />First let us define a function to inspect an object by iterating its members:<br /><code><br />function inspect(o) { for (var n in o) if (o.hasOwnProperty(n)) print(n, &quot;=&quot;, o[n]); }<br /></code>


The ''inspect'' function prints all members stored in an object, so if we now apply this function to the ''circle'' object as well as to its prototypes, we obtain the following output:<br />
The ''inspect'' function prints all members stored in an object, so if we now apply this function to the ''circle'' object as well as to its prototypes, we obtain the following output:<br /><code><br />js&amp;gt; inspect(circle)<br />x = 1<br />y = 1<br />a = 1<br />b = 1<br />js&amp;gt; inspect(circle.''proto'')<br />x = undefined<br />y = undefined<br />a = undefined<br />b = undefined<br />js&amp;gt; inspect(circle.''proto''.''proto'')<br />x = undefined<br />y = undefined<br />area = function () { return Math.PI * this.a * this.b; }<br />js&amp;gt; inspect(circle.''proto''.''proto''.''proto'')<br />move = function (x, y) {<br /> this.x = x<br /> this.y = y;<br /> }<br />translate = function (dx, dy) {<br /> this.x ''= dx<br /> this.y''= dy;<br /> }<br />area = function () { return 0; }<br />js&amp;gt; inspect(circle.''proto''.''proto''.''proto''.''proto'')<br />js&amp;gt;<br /></code>


As you can see, the ''move'' method is actually stored in ''circle.__proto__.__proto__.__proto__''. You can also see a lot of redundant undefined members, but this shouldn’t cause you any concern as prototype objects are shared among instances.
As you can see, the ''move'' method is actually stored in ''circle.&amp;#95;&amp;#95;proto&amp;amp;#95;&amp;#95;.&amp;#95;&amp;#95;proto&amp;amp;#95;&amp;#95;.&amp;#95;&amp;#95;proto&amp;amp;#95;&amp;#95;''. You can also see a lot of redundant undefined members, but this shouldn't cause you any concern as prototype objects are shared among instances.


==Scopes, Closures and Encapsulation==
== Scopes, Closures and Encapsulation ==


In JavaScript, execution starts in the global scope. Predefined global functions like ''Math'' or ''String'' are properties of the global object. The global object serves as the root of the scope chain and is the first object created. The global object can be referenced from the global scope by explicitly using the ''this'' keyword. It means the following is the same:<br />
In JavaScript, execution starts in the global scope. Predefined global functions like ''Math'' or ''String'' are properties of the global object. The global object serves as the root of the scope chain and is the first object created. The global object can be referenced from the global scope by explicitly using the ''this'' keyword. It means the following is the same:<br /><code><br />this.Math === Math<br /></code>


Further scopes are created on-demand, whenever a function is called. Scopes are destroyed as any other object when they are no longer needed. When a function is defined, the enclosing scope is kept with the function definition and used as the parent scope for the function invocation scope. The new scope that is created upon function invocation is commonly referred to as the '''activation object'''. The scope in which functions are defined is commonly referred to as the '''lexical scope'''.
Further scopes are created on-demand, whenever a function is called. Scopes are destroyed as any other object when they are no longer needed. When a function is defined, the enclosing scope is kept with the function definition and used as the parent scope for the function invocation scope. The new scope that is created upon function invocation is commonly referred to as the '''activation object'''. The scope in which functions are defined is commonly referred to as the '''lexical scope'''.


The following example shows how to use lexical scopes to hide private members:<br />
The following example shows how to use lexical scopes to hide private members:<br /><code><br />function Point(x, y) {<br /> this.getX = function() { return x; }<br /> this.setX = function(x2) { x = x2; }<br /> this.getY = function() { return y; }<br /> this.setY = function(y2) { y = y2; }<br />}<br /></code>


When the ''Point'' constructor is invoked, it creates get and set methods. The newly generated scope for the invocation of the ''Point'' constructor carries the ''x'' and ''y'' members. The getters and setters reference this scope and therefore it will be retained for the lifetime of the newly created object. Interestingly there is no other way to access ''x'' and ''y'' other than via the set and get methods. This way JavaScript supports '''data encapsulation'''.
When the ''Point'' constructor is invoked, it creates get and set methods. The newly generated scope for the invocation of the ''Point'' constructor carries the ''x'' and ''y'' members. The getters and setters reference this scope and therefore it will be retained for the lifetime of the newly created object. Interestingly there is no other way to access ''x'' and ''y'' other than via the set and get methods. This way JavaScript supports '''data encapsulation'''.


The concept of a function referencing the enclosing scope and retaining it for the lifetime of the function is commonly called a '''closure'''. Low-level programming languages like “C” do not support closures because local scopes are created using stack frames and therefore need to be destroyed when the function returns.
The concept of a function referencing the enclosing scope and retaining it for the lifetime of the function is commonly called a '''closure'''. Low-level programming languages like &quot;C&amp;quot; do not support closures because local scopes are created using stack frames and therefore need to be destroyed when the function returns.


==Namespaces==
== Namespaces ==


Functions play a pivotal role in JavaScript. They serve as simple functions, methods, constructors and are used to encapsulate private properties. Additionally functions serve as anonymous namespaces:<br />
Functions play a pivotal role in JavaScript. They serve as simple functions, methods, constructors and are used to encapsulate private properties. Additionally functions serve as anonymous namespaces:<br /><code><br />(function() {<br /> // my code<br /> var smth = new Smth // safe<br /> other = [1,2,3] // bad, goes into global scope<br /> Array = function() {} // forbidden<br />}) ()<br />var smthElse = {} // bad, goes into global scope<br /></code>


An anonymous function is defined and executed on-the-fly. Global initialization code in particular is commonly wrapped in such a way to prevent polluting the global scope. As the global object can be modified as any other object in JavaScript, wrapping code in such a way reduces the risk of accidentally overwriting a global variable. To ensure that it actually works, all variables need to be duly introduced using the ''var'' statement.
An anonymous function is defined and executed on-the-fly. Global initialization code in particular is commonly wrapped in such a way to prevent polluting the global scope. As the global object can be modified as any other object in JavaScript, wrapping code in such a way reduces the risk of accidentally overwriting a global variable. To ensure that it actually works, all variables need to be duly introduced using the ''var'' statement.
Line 131: Line 138:
Named namespaces can also be created with functions. If for instance we wanted to write a utility library for painting applications, we could write:
Named namespaces can also be created with functions. If for instance we wanted to write a utility library for painting applications, we could write:


Once this little library module is executed, it will provide the single ''PaintUtil'' object which makes the utility functions accessible. A point can be instantiated using the constructor provided by ''PaintUtil'' as follows:<br />
<code><br />function PaintUtil() {<br /> PaintUtil.Point = function(x, y) {<br /> this.move = function(x2, y2) { x = x2; y = y2 }<br /> this.getX = function() { return x; }<br /> this.getY = function() { return y; }<br /> }<br /> // Ellipsis, Circle, other painting utility methods<br />}<br />PaintUtil()<br /></code>
 
Once this little library module is executed, it will provide the single ''PaintUtil'' object which makes the utility functions accessible. A point can be instantiated using the constructor provided by ''PaintUtil'' as follows:<br /><code><br />var p = new PaintUtil.Point(0.1, 0.2)<br /></code>


Reusable JavaScript modules should only introduce a single global object with a distinguishable name.
Reusable JavaScript modules should only introduce a single global object with a distinguishable name.


==Common Methods==
== Common Methods ==
 
JavaScript allows the default behavior of an object to be changed using the ''valueOf()'' and the ''toString()'' methods. ''valueOf()'' is expected to return a value of fundamental type. It is used to compare objects (when sorting them) and to evaluate expressions comprising of objects and fundamental types. ''toString()'' is invoked when an object is cast to a string.<br /> In JavaScript, objects are compared for equality differently than for being greater or lower. Comparison for equality always compares the object references. Comparison for being lower or greater, on the other hand, converts objects by first converting the objects to values of fundamental types. First ''valueOf()'' is invoked and, if it doesn’t return a fundamental type, it calls ''toString()'' instead.
 
For our ''Point'' class, we could define the methods as follows:<br />
 
==Exceptions==
 
JavaScript provides an exception handling mechanism like most other high-level languages. Exceptions are thrown using the ''throw'' statement. Any value can be used as an exception object:<br />


When an exception is thrown, JavaScript unwinds the current scope until it arrives at a try-catch scope:<br />
JavaScript allows the default behavior of an object to be changed using the ''valueOf()'' and the ''toString()'' methods. ''valueOf()'' is expected to return a value of fundamental type. It is used to compare objects (when sorting them) and to evaluate expressions comprising of objects and fundamental types. ''toString()'' is invoked when an object is cast to a string.<br />In JavaScript, objects are compared for equality differently than for being greater or lower. Comparison for equality always compares the object references. Comparison for being lower or greater, on the other hand, converts objects by first converting the objects to values of fundamental types. First ''valueOf()'' is invoked and, if it doesn't return a fundamental type, it calls ''toString()'' instead.


The name of the exception object is only locally defined inside the catch scope.<br /> Exceptions can be re-thrown.
For our ''Point'' class, we could define the methods as follows:<br /><code><br />Point.prototype.valueOf = function () {<br /> return Math.sqrt(this.getX() * this.getX() + this.getY() * this.getY());<br />}<br />Point.prototype.toString = function () {<br /> return this.getX().toString() + &quot;,&quot; + this.getY().toString();<br />}<br /></code>


==Resources==
== Exceptions ==


===Web Links===
JavaScript provides an exception handling mechanism like most other high-level languages. Exceptions are thrown using the ''throw'' statement. Any value can be used as an exception object:<br /><code><br />throw &amp;lt;expression&amp;amp;gt;<br /></code>


* [https://developer.mozilla.org/en/JavaScript/Reference The JavaScript Reference] ''[developer.mozilla.org]''
When an exception is thrown, JavaScript unwinds the current scope until it arrives at a try-catch scope:<br /><code><br />try {<br /> &lt;statement-list&amp;gt;<br />}<br />catch (&lt;name for exception object&amp;gt;) {<br /> // handle exception<br />}<br />finally {<br /> // always go through here<br />}<br /></code>
* [http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ JavaScript. The core. (Dmitry A. Soshnikov)] ''[dmitrysoshnikov.com]''
* [http://www.youtube.com/watch?v=Kq4FpMe6cRs Changes to JavaScript: EcmaScript 5 (Mark Miller)] ''[youtube.com]''
* [http://www.ecma-international.org/publications/standards/Ecma-262.htm Standard <span class="caps">ECMA</span>-262] ''[ecma-international.org]''


===Books===
The name of the exception object is only locally defined inside the catch scope.<br />Exceptions can be re-thrown.


* [http://oreilly.com/catalog/9780596517748 JavaScript: The Good Parts (Douglas Crockford)] ''[oreilly.com]''
== Resources ==
* [http://www.amazon.com/JavaScript-Definitive-Guide-David-Flanagan/dp/0596101996/ref=sr_1_1?ie=UTF8&s=books&qid=1304331183&sr=8-1 JavaScript: The Definitive Guide (David Flanagan)] ''[amazon.com]''


{| class="infotable line"
=== Web Links ===
| Footnotes
|
|-
| Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
|}


===Categories:===
* &quot;The JavaScript Reference&amp;quot;:https://developer.mozilla.org/en/JavaScript/Reference
* &quot;JavaScript. The core. &amp;#40;Dmitry A. Soshnikov&amp;amp;#41;&quot;:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
* &quot;Changes to JavaScript&amp;amp;#58; EcmaScript 5 &amp;#40;Mark Miller&amp;amp;#41;&quot;:http://www.youtube.com/watch?v=Kq4FpMe6cRs
* &quot;Standard ECMA-262&amp;quot;:http://www.ecma-international.org/publications/standards/Ecma-262.htm


* [[:Category:Developing with Qt|Developing_with_Qt]]
=== Books ===
** [[:Category:Developing with Qt::QtScript|QtScript]]
* [[:Category:Developing with Qt::QtWebKit|QtWebKit]]


* [[:Category:Developing with Qt::Qt Quick|Qt_Quick]]
* &quot;JavaScript&amp;amp;#58; The Good Parts &amp;#40;Douglas Crockford&amp;amp;#41;&quot;:http://oreilly.com/catalog/9780596517748
* &quot;JavaScript&amp;amp;#58; The Definitive Guide &amp;#40;David Flanagan&amp;amp;#41;&quot;:http://www.amazon.com/JavaScript-Definitive-Guide-David-Flanagan/dp/0596101996/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1304331183&amp;amp;sr=8-1


* [[:Category:Developing with Qt::Qt Quick::QML|QML]]
|Footnotes||<br />|Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.|

Revision as of 14:35, 23 February 2015

[toc align_right="yes&quot; depth="3&quot;]



JavaScript Language Overview

This article provides an overview of the JavaScript language. The idea is to provide a thorough overview of all of the language's features. You may want to read through this article from start to finish to learn about all the basic features of this language - especially when you are getting started with a JavaScript related technology.
Whenever possible, you should try out the examples in an interactive console. Most Linux distributions ship with the "SpiderMonkey&quot;:http://www.mozilla.org/js/spidermonkey/ console (smjs). If you prefer using a native Qt-based console, try "qtjs&quot;:https://github.com/unclefrank/qmlscriptconsole or "qmlscriptconsole&quot;:https://github.com/unclefrank/qmlscriptconsole. See the QML_Script_Console article if you're curious.

Introduction

JavaScript is a minimalistic dynamically typed scripting language. It is truly object-oriented, although it lacks support for classes. Frequently associated with client-side web development, JavaScript is a language of its own. Originally developed at Netscape and nowadays standardized as "ECMAScript-262 (3rd and 5th edition)":http://www.ecma-international.org/publications/standards/Ecma-262.htm , the language has found wide-spread use and circulates under various names. "JScript&quot; is Microsoft's derivative of the language. "JavaScript&quot; was the original name chosen by Netscape when the language was introduced with Netscape 2. Adobe's ActionScript was also based on ECMAScript-262 before version 3 was released.

Qt has been supporting a JavaScript engine compatible with ECMAScript-262 since Qt 4.3. This engine is called "QtScript&quot; and was originally an independent implementation. Since Qt 4.5, QtScript has been based on JavaScriptCore from WebKit. Qt's new markup language(QML) makes intense use of QtScript. Property values in QML are JavaScript expressions and are evaluated using QtScript.

The Type System

JavaScript supports the following fundamental types:
* boolean
* number
* string
* object
* function

New variables are introduced into the current scope using the var statement:

<br />var flag = false // a boolean<br />var x = 1., y = 2 // numbers can be integers and reals<br />var s1 = 'abc'; // a string<br />

To query the type of a variable, use the typeof keyword. typeof returns the name of the type as a string.

<br />var x = 0; typeof x // 'number'<br />typeof { x: 1 } // 'object'<br />typeof typeof { x : 1 } // 'string'<br />typeof JSON.parse('{&quot;a&amp;quot;: 7}') // 'object'<br />

Everything in JavaScript acts like an object.

<br />1.3333333.toFixed(2) // '1.33'<br />7..toString() // '7'<br />

Note that in JavaScript the expression '7.toString()' can't be interpreted correctly. '7.' is parsed into a number and thereafter results in a syntax error.

The primitive types boolean, number and string are implicitly converted into objects when needed. For this purpose, the global object provides special constructor functions which can also be invoked manually:

<br />typeof 1. // 'number'<br />typeof new Number(1.) // 'object'<br />typeof new String('Hi!') // 'object'<br />

Functions are special kinds of objects. They only differ from objects because they can be called and used as constructors. Properties can be added to functions dynamically:

<br />function f(x) { return f.A * x * x }<br />f.A = 2.7

function Buffer() {}<br />Buffer.MAX_LINE_LENGTH = 4096<br />

Usually those properties serve as global constants and therefore are written in uppercase.

Objects themselves can be expressed using an array or object literal. Arrays have no separate type, but are specialized objects which use array indexes as properties:

<br />var o = { name: 'Werner', age: 84 } // allocate simple object<br />print(o.name, o[age])<br /> // both notations are valid, but [] notation allows generated strings<br />var a = ['a', 'b', 7, 11.]<br /> // an array, equivalent to {'0': 'a', '1': 'b', '2': 7, '3': 11.}<br />typeof o, a // 'object', 'object'<br />

Expressions

The expression syntax follows mostly "C&quot; syntax (as in C++ or Java). As a major difference, there is no sharp distinction between statements and expressions. Basically everything evaluates to something. Function declarations and compounds can be included on-the-fly:

<br />function f() {} // evaluates 'undefined'<br />function f() {} + 1 // evaluates to 1, because 'undefined' is casted to 0<br />(function() {}) // evaluates to a function object<br />(function() { return 0; })() // evaluates to 0<br />{1;2;3} * 2 // evaluates to 6<br />

Expressions are separated by semicolons or line breaks.

Control Flow

Branching

Conditional branches follow "C&quot; syntax.

<br />if (&amp;lt;expression&amp;amp;gt;)<br /> &lt;statement1&amp;gt;<br />else // optional<br /> &lt;statement2&amp;gt; // optional<br />

The switch statement follows the same fall through semantics as in "C&quot;:

<br />switch(expression) {<br /> case &amp;lt;expression1&amp;amp;gt;:<br /> &lt;statement-list1&amp;gt;<br /> break;<br /> case &amp;lt;expression2&amp;amp;gt;:<br /> &lt;statement-list2&amp;gt;<br /> break;<br /> <br /> default:<br /> &lt;statement-listn&amp;gt;<br />}<br />

Repetitions and Iterators

Repeated actions can be expressed using do, while and for loops:

<br />do &lt;statement&amp;gt; while (expression)<br />while (expression) &lt;statement&amp;gt;<br />for (&lt;init-expression&amp;gt;;&lt;test-expression&amp;gt;;&lt;step-expression&amp;gt;) &lt;statement&amp;gt;<br />

For iterating objects JavaScript provides a special for-in statement:

<br />for (&amp;lt;expression&amp;amp;gt; in &amp;lt;object&amp;amp;gt;) &lt;statement&amp;gt;<br />

The given expression needs to be suitable for the left-hand side of an assignment. In the simplest case, it is just a variable declaration. Consider the following example:

<br />var a = [1,2,3,4]<br />for (var i in a)<br /> print(i, a[i]*a[i])<br />// '0', 1<br />// '1', 4<br />// '2', 9<br />// '3', 16<br />

Here the variable i is assigned to all keys of the array a consecutively. In the next example, the left-hand expression is dynamically generated:

<br />var o = {a0: 11, a1: 7, a2: 5}<br />var k = []<br />for(k[k.length] in o);<br />

The keys of o are copied to k. The loop statement itself is left empty. For each member in o, the name is assigned to another member of k.

Labeled Loops, Break and Continue

In JavaScript, loop statements can be given labels. The break and continue statements break or continue the current loop. It is possible to break an outer loop from the inner loop by using the label name as shown in the following example:

<br />label_x:<br />for (var x = 0; x &lt; 11; +''x) {<br /> for (var y = 0; y &lt; 11;y) {<br /> if ((x'' y) % 7 == 0) break label_x;<br /> }<br />}<br />

Objects and Functions

Objects are created using an object literal or the new operator.

In the following example, a point coordinate is expressed as object literal:

<br />var p = { x: 0.1, y: 0.2 }<br />

Objects are entirely dynamic sets of properties. New properties are introduced on first assignment. They can be deleted again by using the delete operator. To query if an object contains a certain property, use the in operator.

<br />'z' in p // false<br />p.z = 0.3 // introduce new property 'z'<br />'z' in p // true<br />delete p.z // remove 'z' from p<br />p.z // undefined<br />

Property values can be of any type - including the function type. Methods in JavaScript are just function properties. When a function is invoked in method notation, it gets passed a reference to the object as an implicit argument called this.

<br />p.move = function(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />p.move(1, 1) // invoke a method<br />

JavaScript allows any function to be called as a method of any object by using the call method, however, there are only a few cases in which you would want to use the call method.

<br />p2 = { x: 0, y: 0 }<br />p.move.call(p2, 1, 1)<br />

Prototype based Inheritance

The second way of creating objects is by using the new keyword together with a constructor function:

<br />var p = new Object<br />p.x = 0.1<br />p.y = 0.2<br />

The new operator allocates a new object and calls the given constructor to initialize the object. In this case, the constructor is called Object, but it could be any other function as well. The constructor function gets passed the newly created object as the implicit this argument. In JavaScript there are no classes, but hierarchies of constructor functions which operate like object factories. Common constructor functions are written with a starting capital letter to distinguish them from average functions. The following example shows how to create point coordinates using a constructor function:

<br />function Point(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />var p = new Point(1, 2)<br />

Each function in JavaScript can be used as a constructor in combination with the new operator. To support inheritance, each function has a default property named prototype. Objects created from a constructor inherit all properties from the constructor's prototype. Consider the following example:

<br />function Point(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />Point.prototype = new Object // can be omitted here<br />Point.prototype.translate = function(dx, dy) {<br /> this.x ''= dx<br /> this.y''= dy<br />}<br />

First we declared a new function called Point which is meant to initialize a point. Thereafter we create our own prototype object, which in this case is redundant. The prototype of a function already defaults to an empty object. Properties which should be shared among all points are assigned to the prototype. In this case, we define the translate function which moves a point by a certain distance.

We can now instantiate points using the Point constructor:

<br />var p0 = new Point(1, 1)<br />var p1 = new Point(0, 1)<br />p1.translate(1, 1)<br />p0 = p1 // false
p0.translate = p1.translate // true<br />

The p0 and p1 objects carry their own x and y properties, but they share the translate method. Whenever an object's property value is requested by name, the underlying JavaScript engine first looks into the object itself and, if it doesn't contain that name, it falls back to the object's prototype. Each object carries a copy of its constructor's prototype for this purpose.

If an object actually contains a certain property, or if it is inherited, it can be inquired using the Object.hasOwnProperty() method.

<br />p0.hasOwnProperty(&quot;x&amp;quot;) // true<br />p0.hasOwnProperty(&quot;translate&amp;quot;) // false<br />

So far, we have only defined a single constructor with no real object hierarchy. We will now introduce two additional constructors to show how to chain prototypes and thereby build up more complex relationships between objects:

<br />function Point(x, y) {<br /> this.x = x<br /> this.y = y<br />}<br />Point.prototype = {<br /> move: function(x, y) {<br /> this.x = x<br /> this.y = y<br /> },<br /> translate: function(dx, dy) {<br /> this.x ''= dx<br /> this.y''= dy<br /> },<br /> area: function() { return 0; }<br />}

function Ellipsis(x, y, a, b) {<br /> Point.call(this, x, y)<br /> this.a = a<br /> this.b = b<br />}<br />Ellipsis.prototype = new Point<br />Ellipsis.prototype.area = function() { return Math.PI * this.a * this.b; }

function Circle(x, y, r) {<br /> Ellipsis.call(this, x, y, r, r)<br />}<br />Circle.prototype = new Ellipsis<br />

Here we have three constructors which create points, ellipsis and circles. For each constructor, we have set up a prototype. When a new object is created using the new operator, the object is given an internal copy of the constructor's prototype. The internal reference to the prototype is used when resolving property names which are not directly stored in an object. Thereby properties of the prototypes are reused among the objects created from a certain constructor. For instance, let us create a circle and call its move method:

<br />var circle = new Circle(0, 0, 1)<br />circle.move(1, 1)<br />

The JavaScript engine first looks into the circle object to see if it has a move property. As it can't find one, it asks the prototype of circle. The circle object's internal prototype reference was set to Circle.prototype during construction. It was created using the Ellipsis constructor, but it doesn't contain a move property either. Therefore, the name resolution continues with the prototype's prototype, which is created with the Point constructor and contains the move property, whereby the name resolution succeeds. The internal prototype references are commonly referred to as the prototype chain of an object.

To query information about the prototype chain, JavaScript provides the instanceof operator.

<br />circle instanceof Circle // true<br />circle instanceof Ellipsis // true<br />circle instanceof Point // true<br />circle instanceof Object // true<br />circle instanceof Array // false, is not an Array<br />

As properties are introduced when they are first assigned, properties delivered by the prototype chain are overloaded when newly assigned. The Object.hasOwnProperty method and in operator allow the place where a property is stored to be investigated.

<br />circle.hasOwnProperty(&quot;x&amp;quot;) // true, assigned by the Point constructor<br />circle.hasOwnProperty(&quot;area&amp;quot;) // false<br />&quot;area&amp;quot; in circle // true<br />

As can be seen, the in operator resolves names using the prototype chain, while the Object.hasOwnProperty only looks into the current object.

In most JavaScript engines, the internal prototype reference is called &#95;&#95;proto&amp;#95;&#95; and is accessible from outside. In our next example, we will use the &#95;&#95;proto&amp;#95;&#95; reference to explore the prototype chain. Because this property is non-standard, you should avoid using it in all other context.
First let us define a function to inspect an object by iterating its members:

<br />function inspect(o) { for (var n in o) if (o.hasOwnProperty(n)) print(n, &quot;=&quot;, o[n]); }<br />

The inspect function prints all members stored in an object, so if we now apply this function to the circle object as well as to its prototypes, we obtain the following output:

<br />js&amp;gt; inspect(circle)<br />x = 1<br />y = 1<br />a = 1<br />b = 1<br />js&amp;gt; inspect(circle.''proto'')<br />x = undefined<br />y = undefined<br />a = undefined<br />b = undefined<br />js&amp;gt; inspect(circle.''proto''.''proto'')<br />x = undefined<br />y = undefined<br />area = function () { return Math.PI * this.a * this.b; }<br />js&amp;gt; inspect(circle.''proto''.''proto''.''proto'')<br />move = function (x, y) {<br /> this.x = x<br /> this.y = y;<br /> }<br />translate = function (dx, dy) {<br /> this.x ''= dx<br /> this.y''= dy;<br /> }<br />area = function () { return 0; }<br />js&amp;gt; inspect(circle.''proto''.''proto''.''proto''.''proto'')<br />js&amp;gt;<br />

As you can see, the move method is actually stored in circle.&#95;&#95;proto&amp;#95;&#95;.&#95;&#95;proto&amp;#95;&#95;.&#95;&#95;proto&amp;#95;&#95;. You can also see a lot of redundant undefined members, but this shouldn't cause you any concern as prototype objects are shared among instances.

Scopes, Closures and Encapsulation

In JavaScript, execution starts in the global scope. Predefined global functions like Math or String are properties of the global object. The global object serves as the root of the scope chain and is the first object created. The global object can be referenced from the global scope by explicitly using the this keyword. It means the following is the same:

<br />this.Math === Math<br />

Further scopes are created on-demand, whenever a function is called. Scopes are destroyed as any other object when they are no longer needed. When a function is defined, the enclosing scope is kept with the function definition and used as the parent scope for the function invocation scope. The new scope that is created upon function invocation is commonly referred to as the activation object. The scope in which functions are defined is commonly referred to as the lexical scope.

The following example shows how to use lexical scopes to hide private members:

<br />function Point(x, y) {<br /> this.getX = function() { return x; }<br /> this.setX = function(x2) { x = x2; }<br /> this.getY = function() { return y; }<br /> this.setY = function(y2) { y = y2; }<br />}<br />

When the Point constructor is invoked, it creates get and set methods. The newly generated scope for the invocation of the Point constructor carries the x and y members. The getters and setters reference this scope and therefore it will be retained for the lifetime of the newly created object. Interestingly there is no other way to access x and y other than via the set and get methods. This way JavaScript supports data encapsulation.

The concept of a function referencing the enclosing scope and retaining it for the lifetime of the function is commonly called a closure. Low-level programming languages like "C&quot; do not support closures because local scopes are created using stack frames and therefore need to be destroyed when the function returns.

Namespaces

Functions play a pivotal role in JavaScript. They serve as simple functions, methods, constructors and are used to encapsulate private properties. Additionally functions serve as anonymous namespaces:

<br />(function() {<br /> // my code<br /> var smth = new Smth // safe<br /> other = [1,2,3] // bad, goes into global scope<br /> Array = function() {} // forbidden<br />}) ()<br />var smthElse = {} // bad, goes into global scope<br />

An anonymous function is defined and executed on-the-fly. Global initialization code in particular is commonly wrapped in such a way to prevent polluting the global scope. As the global object can be modified as any other object in JavaScript, wrapping code in such a way reduces the risk of accidentally overwriting a global variable. To ensure that it actually works, all variables need to be duly introduced using the var statement.

Named namespaces can also be created with functions. If for instance we wanted to write a utility library for painting applications, we could write:

<br />function PaintUtil() {<br /> PaintUtil.Point = function(x, y) {<br /> this.move = function(x2, y2) { x = x2; y = y2 }<br /> this.getX = function() { return x; }<br /> this.getY = function() { return y; }<br /> }<br /> // Ellipsis, Circle, other painting utility methods<br />}<br />PaintUtil()<br />

Once this little library module is executed, it will provide the single PaintUtil object which makes the utility functions accessible. A point can be instantiated using the constructor provided by PaintUtil as follows:

<br />var p = new PaintUtil.Point(0.1, 0.2)<br />

Reusable JavaScript modules should only introduce a single global object with a distinguishable name.

Common Methods

JavaScript allows the default behavior of an object to be changed using the valueOf() and the toString() methods. valueOf() is expected to return a value of fundamental type. It is used to compare objects (when sorting them) and to evaluate expressions comprising of objects and fundamental types. toString() is invoked when an object is cast to a string.
In JavaScript, objects are compared for equality differently than for being greater or lower. Comparison for equality always compares the object references. Comparison for being lower or greater, on the other hand, converts objects by first converting the objects to values of fundamental types. First valueOf() is invoked and, if it doesn't return a fundamental type, it calls toString() instead.

For our Point class, we could define the methods as follows:

<br />Point.prototype.valueOf = function () {<br /> return Math.sqrt(this.getX() * this.getX() + this.getY() * this.getY());<br />}<br />Point.prototype.toString = function () {<br /> return this.getX().toString() + &quot;,&quot; + this.getY().toString();<br />}<br />

Exceptions

JavaScript provides an exception handling mechanism like most other high-level languages. Exceptions are thrown using the throw statement. Any value can be used as an exception object:

<br />throw &amp;lt;expression&amp;amp;gt;<br />

When an exception is thrown, JavaScript unwinds the current scope until it arrives at a try-catch scope:

<br />try {<br /> &lt;statement-list&amp;gt;<br />}<br />catch (&lt;name for exception object&amp;gt;) {<br /> // handle exception<br />}<br />finally {<br /> // always go through here<br />}<br />

The name of the exception object is only locally defined inside the catch scope.
Exceptions can be re-thrown.

Resources

Web Links

Books

|Footnotes||
|Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.|