Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
JavaScript is a scripting or programming language that allows you to implement complex features on web pages. It enriches both HTML and CSS languages by allowing complex operations of their entities, mostly HTML ones. JavaScript enables you to create dynamically updating content, control multimedia, animate images, react to events in the page and pretty much everything else. It is the third layer of the standard web technologies.
One of the great strength of the client-side JavaScript is the functionnality built on top of it. So-called API (standing for Application Programming Interfaces), they provide extra and important features, ready to use. They generally fall into two categories:
Brower APIs
Third Party APIs
Browser APIs are built into your web browser, and are able to do useful complex operations as well as using data from the computer environment. Examples are:
DOM (Document Object Model) API
XmlHttpRequest (XHR) API
Canvas et WebGL APIs
...
Third party APIs are APIs not built directly in the browser. Instead, you rely on other provider to give acces to the code somewhere on the web.
Twitter API
OpenStreetMap API
On an security note, each browser tab creates its own separate execution environment, generally preventing that a code can affect a code runing in another tab.
On a performance note, JavaScript is an interpreted non-typed language, which means it is not compilled into another form and that variable does not have a type. This has the main advantage of being easly readable and easily modifiable on the flight. However, this hinders somewhat its performance compared to other compiled language. Nevertheless, from a technical standpoint, most modern JavaScript interpreters actually use a technique called just-in-time compiling to improve performance; the JavaScript source code gets compiled into a faster, binary format while the script is being used.
JavaScript interprets a lot of things and allows some ambigus semantic, thus encouraging bad practices and habits, which can quickly transfer to other languages (e.g. anonymous function in C++? wtf). You must be careful when coding and well designing your code, otherwise this will quickly run into a coding hell!
For example, the variable hoisting concept:
Other example with arrays manipulation:
Oh, you also have an auto semi-colon adder, which means that var a = 7; is equal to var a = 7...
For fun, go check this and start the video at 1:22, or even this .
To insert some javascript to your page, there is only one way: by using the <script> element. Generally speaking, this element is placed in between the <head> element of your page. One script element is used for one javascript script, so if you have several of them, the same goes for the elements.
Note that even if you can put javascript code directly inside a <script> element, this is strongly discouraged. Instead, correctly organise your scripts.
There are a number of issues involved with getting scripts to load at the right time. A common problem is that all the HTML on a page is loaded in the order in which it appears in your code (thus, from top to bottom). If you are using JavaScript to manipulate elements on the page (or more accurately, the Document Object Model -- or DOM), your code won't work if the JavaScript is loaded and parsed before the HTML you are trying to do something to.
Generally speaking, this will generate errors when your JavaScript will be interpreted by the web browser. For example, associating an event lister to a specific HTML element which does not yet exist will return an error. Thankfuly, there is some strategies to circumvent this problem.
Here, we can see the loading strategies of the page: first load the html, then load all the other resources.
The old way consists to listen the main document of your page and catch the event related to the HTML body being completely loaded and parser. The event is DOMContentLoaded. Consequently, the content inside such an event listener will not run until after that event is fired (then catch): this prevent the error to happens. However, this is rather a disgracious method.
There are actually two modern features we can use to bypass the problem of the blocking script:
async
defer
Scripts loaded using the async attribute will download the script without blocking rendering the page and will execute it as soon as the script finishes downloading. You get no guarantee that scripts will run in any specific order, only that they will not stop the rest of the page from displaying. It is best to use async when the scripts in the page run independently from each other and depend on no other script on the page.
async should be used when you have a bunch of background scripts to load in, and you just want to get them in place as soon as possible.
Inversely, scripts loaded using the defer attribute will run in the order they appear in the page and execute them as soon as the script and content are downloaded.
Thus, if the script taskboard_pool.js relies on board_global_config.js (for example, the later creates useful data structures for the other type of boards), then you should use defer for the loading.
Nowaday, recent web browsers, especially Firefox and Chromium based web browser can be considered as small IDEs. They implement strong features, easy to use, such as:
An HTML inspector
A console
A debugger
A network observer
The debuggers are especially not to be underevaluated. They are really strong, and since JS is an interpreted language, they can modify the context of any bloc, variables and functions on the flight.
A profiler
undeclaredVar = 7; //unpreviously declated variable.
var underclaredVar; //ok.var arr = [];
arr.length → 0
arr[3] → "undefined" // No array bounds exception
arr[3] = "hi";
arr.length → 4 // Only one element has been added, but at the third index, misleading the length counter
arr["3"] → "hi" // Apparently "3" is coerced into a number
delete(arr[3]);
arr.length → 4 // 4??? There are no elements in the array!
arr[3] → "undefined" // 7 lines above, length was "0"...<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- STYLES -->
<link rel="stylesheet" href="../view/style/taskmenu.css" />
<!-- SCRIPTS -->
<script src="../model/board_global_config.js"></script>
<script src="../model/taskboard_pool.js"></script>
</head>
<body>
...document.addEventListener("DOMContentLoaded", function() {
...
});<script src="../model/board_global_config.js" defer></script>
<script src="../model/taskboard_pool.js" defer></script>Anything that is not a primitive type (undefined, null, number, string, boolean, bigInt, symbol) is an object (or an instance) in JavaScript. An object is used to store keyed collections of various data and more complex entities. Object instances can contain more instances which can be functions. These specific functions belongig to an object are called method. That also means functions are objects.
An object can be created with the object literal syntax {...}. The element stored inside an object are called property, and we will see how add and remove them from an object. An object can also be created by using the new operator.
We can create our object with predefined properties as key: value pairs:
Property values can be accessed using the dot notation:
Remember that variable does not have a type! Thus, we could have done quickdraw.weight="HEAVY!" with no error at all.
A property can also be accessed by using the square brackets notation []. It is more powerful that dot notation, but also more cumbersome to write. To access a property using square brackets notation:
Square bracket also permits to use variable as key value, which is very convenient.
A property can be added to an object "on the fly", after it has been created.
To delete a property, use the delete keyword.
Square bracket also permits to make computed property, using variable to create new property for an object. It can be done on the fly or while the creation of the object with the literal syntax {...}.
A const object's properties can still be changed! For example, suppose our const quickdraw={weight: 15} object. We can change its weight with no error. But we cannot change the value of the variable quickdraw itself (e.g. replacing it by another object).
JavaScript strength is its introspection almost limitless possibilities. Consequently, it is possible to access any property of an object, and plus, there will be no error if the property doesn’t exist. Indeed, a non existing property will just return an undefined value. There is also the in operator (much more elegant than the === operator) to test the existence of such properties.
Remember the for...in loop iterating over the properties of an object? No? Go review the .
Property can be more than just a primitive value. In fact, they can store other objects, or even functions.
In JavaScript, objects are stored and copied by reference, as opposite to primitive type. That means a variable storing an object always have its reference as value, and the object is stored somewhere in the memory. JavaScript performs auto-dereferencing of the address stored in the variable to get the actual object (and perform the desired action).
This is important because when an object variable is copied, it is not the object that is copied, but it is the reference! The object is not duplicated.
These two variables references the same object. Making a property modification of one of the variable will instantetly reflect on the other as well! Below an exemple to help you grasp the concept.
This mean that it is not trivial to entierely copy an object which is independent of the first. This is called cloning. In fact, JavaScript does not has built-in function for that, and you will see that it is rarely needed.
But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them.
This copy only the primitive level of the object. If you have another level in your object (e.g. another object), and you want to deep copy them, you will need to go this level. There is already some function here and there to do that, you could check the for example.
As we have seen, {...} operator allows us to create one new object. However, when several similar objects are required, this method is not practicable (e.g tiles of mahjong). Constructor functions and new operator are what we need to do that.
Constructor function are regular functions, with no difference to a simple function. However, they should respect these two conventions (they are not implemented in a language-level):
The function should start with a capital letter
The function should only be called using the new operator
The syntax is as follow
When a function is executed with the new operator, it does the following steps:
A new empty object is created and assigned to this.
The function body executes. Usually it modifies this, adds new properties to it.
The value of this is returned.
There much more to learn on constructor function and new. But we want to emphasize on OOP, thus we will lean toward a more appropriate syntax
With a little imagination and knowledge about the language, it is totally possible to force function's visibility for function constructor. Use the .
The return statement of the Quickdraw contains our public functions. The private functions are just those that are not returned. Not returning functions makes them inaccessible outside of the Quickdraw namespace. But our public functions can access our private functions thanks to closure.
A convention is to use the _ (underscore) symbol as a prefix for protected method, and returning an anonymous object containing the public functions.
In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). (Wikipedia)
A class is the fondamental element of the object-oriented programming paradigm, and we want that to be convenient to use and powerful. While constructor function and new operator help us to create many similar objects, a class construct give us much more features.
The syntax of a class is:
So if you retake our quickdraw example, to define a class and instantiate an object of this class
Even if alert(typeof Quickdraw) says that a class is a function, it is not just a syntactic sugar. One of the important thing is that in the prototype of the object, the enumerable flag is set to false for all methods of the class. That means iterations instructions, like for...in, will only iterate over the properties of the object, not its methods.
Classes always use strict mode, even if you are in sloppy mode (the default)! All code inside the class construct is automatically in strict mode. This mean that the behavior of somes JavaScript feature can change! Be aware of that, such as this value and the execution scope. More information .
Class fields are defined for each instance of the class, not the class itself. For example Quickdraw.prototype.weight is undefined, whereas myQckd.weight is set.
JavaScript introduced getters and setters concept both for literal function and class. Easily enough, the syntax is:
Getters and setters are specific functions. When declaring a get/set over a property of your object, JavaScript actually replace this property with a specific function. That is why you need to change the name of the property and -- by convention -- we used the _ to do that. Otherwise, you will have an infinite recursive loop. Thus, when we do myQckd.weight = 15, it is actually the setter that is called, not a value affection for the property! More information about getters and setters .
Your class can represents objects aiming to be interact with in the view of your application. Consequently, maybe some of its methods need to be called when specific events are dispatched. The inconvenient with JavaScript is that this is dynamic. Therefore, we cannot "simply" give a method as a callback to a function.
This is called "losing this". There is several approach for fixing this issue, but an elegant solution is relying on class fields, since they are object based, and not prototype based. Thus the method myClick will be created on a per-object basis, with this always referencing the object.
This is a recent implementation and could not work with all the browsers.
It is possible to associate a method to a class itself, not to its prototype with the keyword static. Usually, static methods are used to implement functions that belong to the class itself, but not to any particular instance (object) of it. Simply prefix the method of the keyword to obtain such a behavior.
This goes the same for static property.
Again, mind this! It refers to the class itself, not a particular instance. Therefore, if we had a static method in our Quickdraw class, and inside the method, alert(this === Quickdraw)//true.
OOP imply visibility for fields class. In JavaScript, because it is a prototype based language, all the fields are public by default. That means all properties and functions of an object are visible and modifiable anywhere if there is a reference to this object.
Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated. In our Quickdraw example, weight and brand, as well as method1 are public.
The convention (since it is not implemented on the language level) is to prefix the protected element with an _ (underscore). So, if our protected should be protected, they will become _weight and _brand.
Do not be fooled! They are still publicly accessible. But since you will be probably looking for weight instead of _weight, you will not find them. You will also avoid all properties starting with _ in iterations instruction like for...in.
The same goes for methods. Prefix the class methods with _ to indicate they are protected. However, tend to favor get and set when possible!
In the recent additions of the language, a private symbol as been introduced at the language-level. Any element prefixed by # is meant to be private, and therefore is only accessible from inside the class whether it is a method or a property.
Relying on # while defining a class element also has an impact on its syntactic declaration: two elements (e.g. properties) can share a same name if one is either public or protected, and the other private. You can also combine this with getter and setter to have a powerful encapsulation.
The instanceof operator allows to check whether an object belongs to a certain class. It also takes into account. In case of polymorphic objects, for example, this operator is handful. It is applicable to class, but works also with constructor functions.
The syntax is simple.
It returns true if myObj belongs to the class ClassName or a class inheriting from it.
Another way to bing method of an object with any event is by relying on async and Promise. async can be added in front of class/object methods to make them return promises, and await promises inside them.
This is a brief introduction to meta-programming via Proxy and Reflect new features introduced in JavaScript by ES6. Meta programming is about code that have a direct effect on the code we use to write the application (or core).
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object (cf. ). In other word, it allows us to create some kind of a layer between an object and its consuming entities. We can then control the behavior of the object, like deciding what should be done when accessing a property in a object or the set is used.
The syntax is:
Where the target is the object for which you want to create the proxy, and the handler is the object defining the custom behavior. The handler traps some predefined functions, such as:
apply()
construct()
get()
has()
With the above example, we saw that each time we access an object property, we call the get handler and perform the instruction within, instead of directly accessing target attributes.
This example is somewhat identical to the use of get from a class as we saw before.
Reflect is a built-in object that provides static functions for interceptable JavaScript operations. Some of these functions are the same as corresponding method on object (yet can apply). Put in other words, it simplifies creation of Proxy since it is a minimal wrapper around the interal methods trappable.
Some examples
set()
HTML has never be user friendly regarding its reusable aspect. In complex page structures, where lot of UI custom are placed, the document can quickly become a mess (mostly due to a lot of copy paste, modifying few ids and classes). However, as developpers, we know that reusable and small code is a good idea, if not only for code maintenance.
Web components is a suite of technologies that has been created to address this problem of reusability in web page. The idea behind web components is to break a web page into small and reusable blocks, with their own custom logic and states, where they can communicate between each other, mostly via events and recativity (i.e. when an object's attribute change). This allows a better encapsulation and help the developpers to seperate the view from the application logic (the model).
If we take a look at a web page, we can see that some elements are redudant and can be derivated into web components (and maybe it is already the case here!).
In a web component approach, such a page could be transcripted into the following HTML code:
To achieve this building philosophy, web components rely on shadow dom, preventing them to leak outside their respective DOM. Thanks to dedicated JavaScript framework, Shadow DOM manipulation is often transparent to the programmer.
Vue.js components are written as a combination of JavaScript objects that manage the app's data and an HTML-based template syntax that maps to the underlying DOM structure.
As we have seen above, a web component is an encapsulation of one or several specific HTML elements (native and/or custom component) supposed to work together in a specific way in order to make an action or an application logic easily reusable. A web component is a custom HTLM element, generally "reactive", which is usable as any other HTML element in your document. But two instances of a same web component can have a different state.
This last fact implies that a web component definition introduces some variabilities in its HTML code. Such an adaptive code is called a template. It describes how it should be rendered (from an HTML point of view) by identifying which part of the HTML is static, and the other part is dynamic. This allows the web component to update itsefl depending on the current state of its data, consequently reflecting the change to the user accordingly.
An example of a template, in my-logInfo-component.vue:
Here, we specify a component designed to display user's information, and if connected, a button to disconnect it, mostly by using HTML code plus some specific attributes (we will see them later). Let's say we have two user now, we could have two instances (or more!) of this web component in our page:
This is just an illustrative example. The syntax in Vue.js will be a little different.
As you can see, we somewhat "paste" the content of the web component's template -- instanciated -- inside the custom HTML. Thus, during the rendering, the HTML is adapted to the state of the component (like PHP in some way, except this is dynamic).
Registering attributes is the concept of passing existing data to a web component, and storing the passed data into the component (to use it). In the example above, we bind the object user1 and user2 to respectively the first and the second <my-logInfo-component> components. Registering data to components is useful to instanciate them correctly. Like that, you can pass a data from a parent to a child component, again to a child component that needs specifically this data to correctly instatiate.
Moreover, registering data allows a powerful mechanism to take place: reactivity (even accross components). The reactivity consists of two things. Firstly, it kept the registered data synchronized. Secondly, and this is powerful, it listens to any change made in the parent data, and re-render the components which depends on it. This makes the page dynamic and keeps all the element synchronized.
There is also the two-ways binding/registering, which simply consists of listen to any modification for the parent data, or the child data. Thus, once the data change, from either component level, the modification is taken into account, and the component re-rendered. Thanks to that, it is also possible to share data accross component not only in depth, but also in wide.
Check the illustration below. We have a main page where three components, where two are different instances of the same component, are attached to the main page. On the first blue component, we also attach a third component. Big arrows represent registering, thin arrows represents cross registering.
Vue.js adopts a much more simple approach than some heavy framework like Angular: everything a component needs is write into a single file. Let's see the structure of a Vue.js component.
Has you can see, there is three parts in a Vue.js component. The <template> section, that we discuss about, the <script> section handling you component logic, as well as all data reactivity and some specifics mecanisms and the <style> section, used to design your component.
let quickdraw = {}; // "empty" object ; literal syntax
let quickdraw = new Object();let quickdraw = {
weight: 15, // key= weight, value=15 ; notice the comma here
brand: "ClimbingGoat", // key= brand, value = "ClimbingGoat"
};console.log(quickdraw.weight); // cli: 15
quickdraw.weight = 20; // setting a new value to the property weight of the object quickdrawalert(quickdraw["weight"]);
quickdraw["brand"] = "Awesome Brand";var key = prompt("What info about the quickdraw?", "weight", "brand");
alert( quickdraw[key] ); // alert either the content of the key, or undefined if the key does not match a propertyquickdraw.hasGate = true;
//or
quickdraw[hasGate] = true;delete quickdraw.hasGate;
alert(quickdraw.hasGate); // underfined.var myProp = "color";
quickdraw[myProp] = "Rainbow";
const qckDraw2 = {
[myProp + "hey, why not" + foo(10)]: "Double Rainbow", //complex instruction in [] are possible as well
weight: 100,
brand: "OMG It's a!",
}let wgt = "weight";
alert( "weight" in quickdraw ) // TRUE
alert( wgt in quickdraw ) // TRUE, still checking for the property weight
alert( "rope" in quickdraw ) // FALSElet quickdraw = {
weight: 15, // key= weight, value=15 ; notice the comma here
brand: "ClimbingGoat", // key= brand, value = "ClimbingGoat"
printMe(){
console.log(this.brand + " has a weight of" +this.weight); // this refer the object here, not the global
},
};
quickdraw.open = function(){ //add another property
console.log("Hey, I'm the open anonymous function! but could be named too!")
}
let gate = {type:fill}; //new object gate
quickdraw.gate = gate; //the new gate object is placed inside a new gate propertylet quickdraw = {weight : 15};
qckd2 = quickdraw;let clone = {}; // **new** empty object
// let's copy all quickdraw properties into a clone
for (let key in quickdraw) {
clone[key] = user[key];
}function Quickdraw(param1, param2){
this.weight = param1;
this.brand = param2;
}
var myQckd = new Quickdraw(50, "Ultra poney"); // create new object Quickdraw
alert(myQckd.weight) // access , add, remove, as usualvar Quickdraw = (function() {
function privateMethod() {
// do something
}
function publicGetterMethod()
{
// do smth
}
return {
publicGetterMethod: publicGetterMethod,
publicMethod: function() {
// can call privateMethod();
},
};
})();
Quickdraw.publicMethod(); // works
Quickdraw.publicGetterMethod(); // works
Quickdraw.privateMethod(); // Uncaught ReferenceError: privateMethod is not definedclass MyClass {
prop1;// properties are optional but its good to indicate them anyway
prop2 = 0; //IDEM, with default value
constructor(){...}//several constructor can be defined, with various param.
method1(){...}
method2(){...}
//and so on, like Java, C++ objects
}class Quickdraw{
// Class fields
weight;
brand;
constructor(weight, brand){
this.weight = weight;
this.brand = brand;
}
printMe(){
console.log("hey! it's me, "+this.brand+"!");
}
}
// And use it
let myQckd = new Quickdraw(15, "Mario");
myQckd.printMe(); // cli : Hey! it's me, Marioclass Quickdraw{
// Class fields
weight;
constructor(weight){
this.weight = weight; // auto calling of the setter
}
get weight(){
return this._weight; //note the _
}
set weight(w){
if(w > 1000)
{
alert("error, qckd to heavy");
return;
}
this._weight = w; //note the _
}
}class Quickdraw{
constructor(w){ this.weight = w }
myClick(){alert(this.weight);}
}
let qck = new Quickdraw(150);
setTimeout(qck.myClick, 1000); // undefined ! Oops!class Quickdraw{
constructor(w){ this.weight = w }
myClick = () => {alert(this.weight);} // this is now a class field (i.e. attribute)!
}
let qck = new Quickdraw(150);
setTimeout(qck.myClick, 1000); // 150class Quickdraw{
weight;
brand;
method1(){};
}class Quickdraw{
#weight; //private class field
set weight(value){ // setter, defined on weight
if(value > 0)
this.#weight = value; //ok to access private elmt from inside
else
throw new Error("Check Manage error section ;)");
}
}
let qck = new Quickdraw();
qck.weight = 150; // OK! Call the setter, and set the value of the private weightmyObj instanceof ClassNameclass Quickdraw{
async makeAwait() {
return await (new Promise( (resolve, reject) => setTimeout(() => resolve("Hi! I'm resolved"),3000)));
}
};
let qck = new Quickdraw();
qck.makeAwait().then(console.log); //cli : Hi! I'm resolved ; after 3 sec.
console.log("Don't forget!"); // <-- This code prints before the above log!var p = new Proxy(target, handler);const target = {
notProxied: "original value",
proxied: "original value"
};
const handler = { //defining a handler for get
get: function(target, prop, receiver) {
if (prop === "proxied") {
return "replaced value";
}
return Reflect.get(...arguments);
}
};
const proxy = new Proxy(target, handler); //creating the proxy
console.log(proxy.notProxied); // cli : original value
console.log(proxy.proxied); // cli : replaced value.const dog = {
race: "tamaskan",
color: "grey",
bark: function(){console.log("woof");},
}
Reflect.ownKeys(dog); // list all the properties ["race", "color", "bark"]
Reflect.set(dog, "color", "purple"); // set the dog's color to purple
Reflect.has(dog, "corol"); // false<div id="app">
<app-nav></app-nav> <!--Login,search etc component: include a search component, a login component-->
<app-view>
<app-overviewbar></app-overviewbar>
<app-content></app-content> <!--Contain a lot of <app-story> components-->
</app-view>
</div><my-logInfo-component><!--no need to introduce body or html!-->
<p>
You are logged as : <span>{{ user.name }}</span>
</p>
<div v-if="connected">
<input name="Disconnect"/>
</div>
</my-logInfo-component><html>
<body>
<my-logInfo-component user="user1"></my-logInfo-component> <!--Just displaying You are logged as : Alexis Lebis -->
<my-logInfo-component user="user2" connected="true"></my-logInfo-component> <!--Display : You are logged as : Luc Fabresse **AND** the Disconnect button-->
</body>
</html><template>
<h1>My Vue App</h1>
{{ msg }}
</template>
<script>
export default {
name: 'MyComponent',
props: {
msg: String
}
}
</script>
<style>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

In this section, we will learn the concept of Single Page Application (SPA), how to make a SPA and how to dedicated client side framework.
A SPA is a web application accessed with a unique web page instead of loading entire new pages. It interacts with the user by dynamically rewritting some parts of the current web page by retrieving data from the server. All necessary HTML, CSS and JavaScript are retrieved with a single page load (or dynamically loaded and added to the pages thereafter). There should not be a reload of the page at any point of the use of the SPA, nor delegation of control process to another page.
SPA rely on dynamic communication with the server, either by using AJAX/Fetch API or websocket to modify elements on the page. Below a comparative illustration.
SPA tends to favorise a better maintenance, and a better referencement. They also emphasize a stronger organisation of your application and offer increased performances, mostly when the server's tasks are heavy since a lot of logic is client sided.
One major drawback of SPA is they reliance to JavaScript. If your user has deactivated (or cannot correctly interpret) JavaScript on its browser, your site is unusable (or worst, can have some security flows). Keep that in mind, especially when you strongly couple SPA with web components, since the web components standard is not well implemented in all the browsers.
An important point is that SPA tends to rely heavily on the notion of web components (cf. dedicated ). Briefly, they are custom and reusable HTML elements embeding their own logic.
In this course, we will use Vue.js as our JavaScript framework for building SPA. There is a lot of other JavaScript frameworks out there, such as:
Vue.js is a modern JavaScript framework that provides useful facilities for progressive enhancement and strong reactivity. It is one of the most easy to use framework and lightweight. It also adopts a "middle ground" approach, instead of more important framework like Angular, where e.g. route and state management are delegated to other (already) existing libraries doing the work quite well. And unlike many other frameworks, you can use Vue.js to enhance existing HTML.
Usually, a JavaScript framework allows you to handle the DOM of your page more easily by giving you new ways to manage it, create reactivity (i.e. using a built-in observator pattern for your object's properties) between various HTMLxJavaScript elements and providing you with usefull new API.
The installation procedure of Vue.js is explained in the . Here, we are interested in the CLI installation (there is a more detailed explanation in the section.), which gives us a way to quicly create a new projet and scaffold important project.
Using the important method is good for small project and tests. But it will quickly become not practicable! Use the CLI!
Instead of rewritting the procedure, it's demo time for creating a new project!
🕑Time passes🕑
Your src/ folder contains all the Vue app and components you create. src/App.vue is your main vue (top-level) component, which globally load the framework. The folder src/components/ should contains all your web components. src/assets/ is used to store static assets like CSS and images. src/routers contains your route configuration for a SPA, and src/views/ contains all the vue (the "pages" or sections) of your SPA.
.
Install the plugin Vetur for VS Code for code highlights!
Currated list of various components and stuff for Vue.js:
Made of several pages
Only one page
Web browsers generally just display pages and gives to the server the users' input
Web browsers fully exploited and dynamically retrieve content from the server
All the logic of the App is served-sided
Either the logic is client sided (beurk!) or separate as much as possible to not compromise security
Server reacts to user interaction and serves new page
The server is responsible to expose and make accessible app's resources (e.g. REST API)
This is just an overview of event handling in Vue.js. For more information, check the event documentation and the custom event documentation.
Vue.js change the event listener (handler) paradigm, and how and where they should be introduced in the code. The frameworks encourages listener to be DOM-free manipulation and focus only on logic. To achieves this, the listener are now attached directly to HTML document using the v-on directive. An advantage is it's easier to locate handler function by skimming your HTML template instead of the JS code, another is that Vue.js handle all the creation and desctruction of the listeners.
Easily enough, an event is handle using the v-on directive, followed by :eventName the name of the event to listen to. This is directly followed by ="method" the handler to call for the specified event.
However, the method needs to be defined in the component using the methods attribute:
We can even use event modifiers to change the default behaviour of an event, e.g. event.preventDefault() for a form. Vue.js introduces a list of keywords related to the event modifier, and to use them, suffix your directive by the keyword, like v-on:submit.prevent="onSubmit".
You can fired custom event using Vue.js. To do so, you can use the this.$emit("myEvent") function call. This will fire the event "myEvent", which can be handle with the v-on handler.
Despite it is the case for almost everything in Vue.js, the name of an event is not transformed automatically into kebab-case name (my-event) in the template. You must refert it by its actual name. Consequently, it is recommended to always use kebab-case for events.
Two-way binding, if badly executed, can cause undesired behaviors, time consuming debuging session and even disastrous performance. Use it carefully!
To reduce the impact of the mentioned issues, Vue.js strongly recommend the use of events to update a parent data. For example:
A good practice is to prefix your update event with update:. Like that, you will know that this kind of event is only used as for the double way binding mecanism.
It's used as follow:
For convenience, Vue.js introduced the .sync keyword which do exatcly the same thing, but is a shorthand for above (supposing that your event is called update:theNameOfTheData).
https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
<template>
<div id="example-1">
<button v-on:click="incrementCounter">Add 1</button> <!--incrementCounter is a method of the component-->
<p>Button click {{ counter }} times.</p>
</div>
</template>export default {
name: 'HelloWorld',
data: {
counter: Number,
}
methods: {
incrementCounter: function(event){
alert("Hey! I'm the incrementor, the one we call to increment you");
this.counter++;
if(event)
alert(event.target.tagName)
}
}<my-component v-on:myEvent="doSmth"></my-component>this.$emit('update:pseudo', newPseudo)<text-document
v-bind:pseudo="user.pseudo"
v-on:update:pseudo="user.pseudo = $event" # JS interpretation here: we store the value of the $event received into the pseudo.
></text-document><text-document
v-bind:pseudo.sync="user.pseudo"
></text-document>

There is two specific keywords used to control how the iteration goes:
break
continue
The break statement is used to terminate a loop, switch, or in conjunction with a labeled statement (more info ). When you use break without a label -- the most probable way of using it -- it terminates the innermost enclosing while, do-while, for, or switch immediately. The important thing to remember is that it transfers control to the following statement.
This statement is quite interesting because it prevents unnecessary iteration over the entities being iterated, in addition to being clear.
The continue statement can be used to restart a while, do-while, for, or label statement. When you use continue without a label, it terminates the current iteration of the innermost enclosing while, do-while, or for statement and continues execution of the loop with the next iteration. In contrast to the break statement, continue does not terminate the execution of the loop entirely. In a while loop, it jumps back to the condition. In a for loop, it jumps to the increment-expression.
In addition to these three loops, there also exists three more loops mostly used to iterate over element of a collection:
forEach
for... in
for... of
forEach is not quite a special control structure but more a prototype method attached to the Array object (more information about prototype in the ). It executes a provided function once for each array element. Be careful however, since this method does not copy the array: it directly uses the collection and if it cause some desynchronisation or unexpected behavior, mostly if you remove/add new element in the collection.
The => element indicates an arrow function. We will talk about that below, and in the part.
The for...in statement iterates a specified variable over all the enumerable properties of an object. For each distinct property, JavaScript executes the specified statements. A for...in statement looks as follows:
Use the for...in statement wisely! For example, it is not advise to use it for Arrays instead of for. The principal reason is that it will iterate also on the user-specified variable, not only on the numerical index.
The for...of statement creates a loop iterating over iterable objects (including Array, Map, arguments object and so on), invoking a custom iteration hook with statements to be executed for the value of each distinct property. A for...of statement looks as follows:
A for...in loop would have displayed 0,1,2,"someText" instead of the value of the array.
The notion of iterator comes from the fact that processing each item of a collection is a very common operation in computing. The important notions behind an iterator are that at a specific moment it points toward a specific item of the collection and that there is a well defined sequence in the collection (implied by the specific moment). Thus, an iterator must answer the following questions:
In JavaScript an iterator is an object which defines a sequence and potentially a return value upon its termination (simply stated, this is the iteration protocols):
Is there any element left in the collection ?
What is this very element if it exists ?
In fact, you already have used an iterator by using loop such as for...of without knowing it.
Technically speaking, any object is qualifiable as an iterator if it has a next() method and it returns an object with the two following properties:
done: a boolean value indicating whether or not there are any more items that could be iterated upon. If true, there is no more item.
value: the current element
If you have a custom type and want to make it iterable so that you can use the for...of loop construct, you need to implement the iteration protocols. The following code creates a Sequence object that returns a list of numbers in the range of (start, end) with an interval between subsequent numbers.
To use the built-in iterator of Sequence, there is mainly two ways:
One issue with custome iterators is that their creation requires careful programming since their internal state has to be explicitly maintained. To circumvent this issue, generator functions allow the definition of a single function whose execution is not continuous.
When called, generator functions do not initially execute their code. Instead, they return a special type of iterator, called a Generator. When a value is consumed by calling the generator's next method, the Generator function executes until it encounters the yield keyword. In other hand, the execution is suspended once a yield is encountered, and resumed after it at the next call.
The function can be called as many times as desired, and returns a new Generator each time.
Generator functions are written using the function* syntax, as follow (taking the Sequence example above, droping the class aspect):
Generators compute their yielded values on demand, which allows them to efficiently represent sequences that are expensive to compute (or even infinite sequences, as demonstrated above). An advanced generator could be, for the fibonacci sequence:
To conclude, an object is directly iterable if it has an iteration behavior by implementing the @@iterator method. This simply means that the object needs to have a property [Symbol.iterator].
To make your own iterables:
In the difference of generators where their iterator can be iterated only once, an iterable can be used several times.
There is a difference between a function delcaration and a function expression. A function The later can have its name omitted, defining an anonymous function. The main difference between a function expression and a function declaration is the function name, which can be omitted in function expressions to create anonymous functions.
An anonymous function will do nothing on its own (except enclosed in a grouping operator -- see beelow). It need to be "manually" invoked.
These kind of functions are commonly used along event handler or callback function.
However, anonymous functions are not condamned to be used only once. In fact, a function expression can be assign to a variable, making it invokable wherever needed.
A function expression can be used as an IIFE (Immediately Invoked Function Expression) which runs as soon as it is defined. In addition of being directly interpreted, an IIFE has its lexical scope enclosed within the Grouping Operator (). This prevents accessing variables within the IIFE idiom as well as polluting the global scope.
An IIFE cannot be stored in a variable. Assigning it to a variable stores its return value instead of its definition. An IIFE statement looks as foolow:
An arrow function expression is a compact alternative to a traditional function expression, but is limited and cannot be used in all situations. One of the major reason arrow functions were introduced was to alleviate scope and context complexities ( this ) thus making functions execution much more intuitive. There is several way of declaring an arrow function. The two most commons are:
Check for more in depth information about arrow functions.
Arrow function are best suited for non-method functions, mostly due by the scope (non-)modification implied. By using it as an object method, since an object does not create a new scope the this context does not change, and the arrow-function does not have its own this. It can be a good candidate for promises.
In JavaScript, there is two type of scopes:
Local: Variables declared inside a function is in the local scope of this very function. Therefore, each function creates a new scope when defined.
Global: Variables declared outisde of a function is in the global scope. Variables inside the Global scope can be accessed and altered in any other scope.
Conditionnal statements (e.g. if, switch) and loops, unlike functions, don't create a new scope. Variables defined inside of them remains in the scope they were already in while declared.
HOWEVER! let and const statement for variable declaration support the declaration of local scope in conditionnal and loop statements. This means that at the end of the statement, all the variables declared with either let or const is destroyed.
Global scope lives as long as your application lives. Local Scope lives as long as your functions are called and executed.
Context refers to the value of this (the introspection operator) in some particular part of the scope of your code. In the global scope context is always the Window object (this === Window).
Programer tend to often confuse scope for context, and vice et versa. But they are not the same concept! Scope refers to the visibility of variables in a specific code location ; context, their values in a specific scope.
When declaring a new object -- or using the new operator, the context changed.
Which mean that normal function and arrow function does not share the same behaviour.
Lexical Scope means that in a nested group of functions, the inner functions have access to the variables and other resources of their parent scope. This means that the child functions are lexically bound to the execution context of their parents. Lexical scope is sometimes also referred to as Static Scope.
However, the lexical scope only works forward. That means that a parent scope can not have access to a children's scope.
Closure is an advanced technic of scopes managment and variables lifetime. A closure can not only access the variables defined in its outer function but also the arguments of the scope chain of its outer function (i.e. the variables outside of the immediate lexical scope). Closures contain their own scope chain, the scope chain of their parents and the global scope.
To create a closure, the idea is to return a function from a function. By doing so, variables from the lexical scopre are not deallocated (check execution context for more information), and remain accessible from this function.
This is an interesting behaviour. More examples .
Variable hoisting is a mecanism in JavaScript implied by how the code is processed before its interpretation. This has for effect to allow post-variable declaration in the code, even if the variable is used beforehand.
There is no function hoisting! Function must be declared before they can be used.
Be careful however, since hoisting can lead to leaking variable. For example

JavaScript is a weakly typed language, mostly used to manipulate the DOM of a web page.
Additionally, JavaScript is an object-oriented language (but it allows imperatif and also lambda calculus). However, its main difference with language like Java or C++ is that it is a prototype based language and not a class based one. We will saw the implication of such a statement in the Object-oriented programming section. Briefly said, anything but primitive types is an object in JavaScript.
This section serves as a quick reminder, mostly regarding the syntax, for several important notions.
JavaScript has three different conditionals, well known in other languages as well.
The if...else conditional.
The ternary statement.
The switch statement.
JavaScript has three different ways to perform an egality check, either with their own specificity.
The first one is the simple equality made by the == operator. It does make a data type converstion before the comparison of the objects. You can have important side effects if not used correctly.
The second equality operator is the strict operator === (3 =). The most notable difference between this operator and the simple equality operator is that if the operands are of different types, it will not attempt to convert them to the same type before comparing.
The last equality operator is Object.is() operator. It determines whether two values are the same value. It is widely different to == since it does not perform coerce checks, and differ from === in regard that it treats the number values -0 and +0 as equal and treats Number.NaN as not equal to NaN.
In JavaScript, the 3 classic loop structures are available:
for
while
do...while
The for loop repeats until a specified condition evaluates to false. A for statement looks as follow:
The do...while statement repeats until a specified condition evaluates to false. It looks as follows (do not forget the semi colon at the end of the while instruction):
A while statement executes its statements as long as a specified condition evaluates to true. It looks as follows:
JavaScript is weakly typed, meaning that the variables do not have a specific on their declaration. Instead, we use a generic keyword declaration to declare a new variable.
There is only three declaration keywords in JS. They are:
let: allows the declaration of a block scope local variable (it is destroyed while outside the block) ; it can optionally be initialized to a value ;
var: declares a variable, optionally initializing it to a value ;
const: declares a read-only named constant.
Basically, a function is defined by its name, and its parameters. It does not have a return type: therefore you must be carreful about how the code is documented. A function declaration looks as follow:
To invoke a function:
for (let i = 0; i < a.length; i++) {
if (a[i] === theValue) {
break;
}
}let i = 0;
let n = 0;
while (i < 5) {
i++;
if (i === 3) {
continue;
}
n += i;
console.log(n);
}
//cli: 1,3,7,12const array1 = ['a', 'b', 'c'];
list.forEach((item, index) => {
console.log(item) //value
console.log(index) //index
})
//index is option: list.forEach(item => console.log(item))let player = { name:"Clive", pv: 25, job: "Warrior" };
for (let item in player) {
console.log(student[item])
}
// résultats : Clive \n 25 \n Warriorconst myarray = [2, 4, 8];
myarray.foo = 'someText';
for (const i of myarray) {
console.log(i); // logs 2, 4, 8
}class Sequence {
constructor(start = 0, end = Infinity, interval = 1 ) {
this.start = start;
this.end = end;
this.interval = interval;
}
[Symbol.iterator]() {
let counter = 0;
let nextIndex = this.start;
return {
next: () => {
if ( nextIndex <= this.end ) {
let result = { value: nextIndex, done: false } // done is important!
nextIndex += this.interval;
counter++;
return result;
}
return { value: counter, done: true }; // IDEM, done is important
}
}
}
};let nbPair = new Sequence(2, 10, 2);
for (const num of nbPair) {
console.log(num);
} //cli: 2 4 6 8 10
// OU
let iterator = nbPair[Symbol.iterator]();//Retrieving the iterator through the well-known symbol
let result = iterator.next();
while( !result.done ) // while there is still something
{
console.log(result.value);
result = iterator.next();
}function* Sequence(start = 0, end = Infinity, step = 1) {
let iterationCount = 0;
for (let i = start; i < end; i += step) {
iterationCount++;
yield i;
}
return iterationCount;
}
const s = Sequence(1, 10, 2);
for(let x in s)
{
console.log(x); //CLI: 1 3 5 7 9
}function* fibonacci() {
let current = 0;
let next = 1;
while (true) {
let reset = yield current;
[current, next] = [next, next + current];
if (reset) {
current = 0;
next = 1;
}
}
}
const sequence = fibonacci();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5, etcconst myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
}function* makeIterator() {
yield 1;
yield 2;
}
let it = makeIterator();
for (const itItem of it) { // CLI: 1 2
console.log(itItem);
}
for (const itItem of it) { //this loop is not exectued, it.next() has done:true
console.log(itItem);
}
console.log(it[Symbol.iterator]() === it) // true;
it[Symbol.iterator] = function* () {
yield 2;
yield 1;
};
for (const itItem of it) { // CLI: 2 1
console.log(itItem);
}
for (const itItem of it) { //this loop is executed again, CLI : 2 1
console.log(itItem);
}
console.log(it[Symbol.iterator]() === it) // false;function()
{
console.log("Hi! I'm anon");
}document.addEventListener("DOMContentLoaded", function() {
console.log("Hi! I'm anon once the DOM is loaded");
});var maVar = function()
{
console.log("Hi! I'm anon");
}
// then invoke it
maVar();// Do stuff on scroll
var onScrollHandler = function (event) {
// Do something on scroll...
};
// Listen for scroll events
window.addEventListener('scroll', onScrollHandler, false);(function(){console.log("IIFE1")})();
var result =( function ()
{
var name = "IIFE2";
return name;
}
)();
result; // Contains "IIFE2"
console.log(name); // throws "Uncaught ReferenceError: name is not defined"var maVar = 10;
() => 5 * maVar; //no parameter, return is implicit, one line
(a,x) => { // multi line, multi param, return mandatory
a += 5;
return a * x;
}var name = 'Kazuma';
console.log(name); // CLI: 'Kazuma'
function logName() {
// Local Scope # 1
console.log(name); // 'name' is accessible here and everywhere else
function someOtherFunction() {
// Local Scope #2
console.log(name); // name still accessible
}
var name2 = "Majima";
}
// 'name2' inacessible here: destroyed at the end of logName()
function foo(){
// Local Scope #3
}
logName(); // CLI: 'Kazuma'console.log(this); // cli: Window{...}
function logFunction() {
console.log(this);
}
logFunction(); // cli: Window{...} -> because logFunction() is not a property of an object
class Tile {
logValue()
{
console.log(this)
}
}
(new Tile).logValue(); // cli: Tile{...}window.age = 10; // <-- notice me?
function Person() {
this.age = 42; // <-- notice me?
setTimeout(function () { // <-- Traditional function is executing on the window scope
console.log("this.age", this.age); // yields "10" because the function executes on the window scope, not in p
}, 100);
}
Person(); // cli: "this.age" 42
var p = new Person(); // cli "this.age" 10window.age = 10; // <-- notice me?
function Person() {
this.age = 42; // <-- notice me?
setTimeout(() => { // <-- Arrow function executing in the "p" (an instance of Person) scope
console.log("this.age", this.age); // yields "42" because the function executes on the Person scope
}, 100);
}
var p = new Person();function foo() {
var name = 'Levant';
// status is not accessible here
function bar() {
// name is accessible here
// status is not accessible here
function 2000() {
// Innermost level of the scope chain
// name is also accessible here
var status = 'Great';
}
}
}function speak() {
name = 'Zagreus';
return function () {
console.log('Hello ' + name);
}
}
speak(); // nothing happens, no errors
var speakVar = speak(); // the returned function from speak() gets saved in greetLetter
// calling speakVar calls the returned function from the speak() function
speakVar(); // logs 'Hello Zagreus'. See how the anon. function accesses the name variable from speakundeclaredVar = 7; //unpreviously declated variable. Totally fine and usable
var underclaredVar; //ok.var x = 0;
function f() {
var x = y = 1; // Declares x locally; declares y globally.
}
f();
console.log(x, y); // 0 1
// In non-strict mode:
// x is the global one as expected;
// y is leaked outside of the function, though!if(condition)
{
//code
}
else if(cond2)//optionnel
{
//code
}
else
{
//code
}(condition) ? instruction;if;true; : instruction;if;false;switch (expression) // NOT a condition
{
case 1:
code;
break;
case 2:
code:
break;
default:// Don't forget me
code; //no break needed, we are at the end
}console.log('1' == 1);// CLI: trueconsole.log('1' === 1);// CLI: falsevar foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // CLI: true
Object.is(foo, bar); // CLI: falsefor(let i = 0; i < selectObject.options.length; i++)
{
//instructions goes here
}let i = 0;
do {
i += 1;
console.log(i);
} while (i < 5);let i = 2;
while (i < 65536) {
n*=n;
}var myVar = 7;function foo(param1, param2)
{
//instruction
return result; //optional
}foo(7777, "hello");JavaScript has been made to handle client side application, and therefore has been designed with this objective in mind. One of the principal particularity of client side is the presence of a user, needing a highly interactive interface for browsing. Consequently, JavaScript event managment has quickly become one of its strength.
An event can be seen as a signal that something has happened. All nodes from the DOM generate such signals. Below are some useful DOM events:
Mouse events
click – when the mouse clicks on an element (touchscreen devices generate it on a tap).
contextmenu – when the mouse right-clicks on an element.
mouseover / mouseout – when the mouse cursor comes over / leaves an element.
Form element events
submit – when the visitor submits a <form>.
focus – when the visitor focuses on an element in the form, e.g. on an <input>.
Document events
DOMContentLoaded – when the HTML is loaded and processed, DOM is fully built.
CSS events
transitionend - when a CSS-animation finishes.
When such actions are performed (e.g. a button is clicked), we say that the click event is fired (or dispatched).
To react on events (i.e. catch a dispatched event) we can assign a handler – a function that runs in case of an event.
There is several ways to assign handlers to HTML elements. We will only see the more flexible and less error prone here: addEventListener (doc. ). As an example, lets say we have an HTML input button
To handle the click event, we first need to retrieve our HTML element (here the input) in our JavaScript code, then attach to it our handler.
When an event is dispatched, it is often in a specific context which is important to us in order to understand what was going on. For example, in the case of a mouse click, where was the coordinate of the mouse?
Usually, when an event happens, the browser create what it is called an event object. This object contains the details of the event and is passed as an argument to the handler.
It is also possible to attach to a handler not a function but an object! The only prerequisite is that the object implements a handleEvent() method. The method also receives the event object.
We can also use a class to better organize our code, especially if we want to delegate the events. In the following example we listen the up and down of the mouse with a single object, and the event is then dispatched.
JavaScript allows you to create and manually manage your own events, which prevent you to fully reimplement an event handler. They are called synthetic events, as opposed to the events fired by the browser itself.
These events are DOM events: they rely on the DOM API of your browser, and are considered as event targets (cf. ). They are not supposed to be events produced by your objects.
To create a new event, the Event constructor can be call
Then, this new type of event can be attached to any DOM elements, and listened to.
And to fire the event
You can also add custom data to the event by using the CustomEvent constructor
However, you will mostly rely on already existing events, such as 'click', 'drag', etc. The full list is accessible .
The principle of bubbling events is the following:
When, lets say, a click is made on <p>, the onclick event is run firstly on <p>, then <div>, then <form>. The process is called “bubbling”, because events “bubble” from the inner element up through parents like literally an air bubble in the water.
An interesting point is that an event handler on a parent element can always get the details about where the event actually happened.
The event.target property stores the most deeply nested element that cause the event, while event.currentTarget stores the element where the handler is (this, in the example below the form).
event.target – the deepest element that originated the event.
event.currentTarget (=this) – the current element that handles the event (the one that has the handler on it)
event.eventPhase – the current phase (capturing=1, target=2, bubbling=3).
All these previous notion, and mostly bubbling, allow us to implement powerful event handling patterns.
The idea behind the event delegation pattern, is that, when several elements on an HTML page are supposed to be handled in a similar fashion, we define a single handler on their common ancestor in charge of all these elements.
This is made possible because we have the event object with the target property, alowing us to see where the event actually took place in the page.
For example, imagine that we have a table, with various element inside each cell. The objective is to overlay the clicked cell.
Delegation pattern can also be used for other uses. For example, to match action in a menu. The trivial solution is to assign for each entry of the menu an handler on the click. But there is a more elegant solution to that using delegation.
For that, we will use HTML data attribute, attach the handler directly to the menu and rely on a menu object. All the logical operation will be performed directly in the object, which is a good way to structure your code.
HTML:
JS
Please note that this.onClick is bound to this in (1). That’s important, because otherwise this inside onClick would reference the DOM element (elem), not the Menu object, and this[action] would not be what we need (cf. ).
The behavior pattern rely both the delegation pattern and the data attribute of HTML. The idea behind this pattern is to assigne specific action to specific data-attribute, by using a top level delegation. In other words, we attach to the document itself a handler and verify the very existence of the attribute. It has thus two parts:
We add a custom attribute to an element that describes its behavior.
A document-wide handler tracks events, and if an event happens on an attributed element – performs the action.
Example of counter associate with data-counter:
Though you can use camelCase naming convention in the declaration of your component, or even the component's variables, you need to reference to them using a kebab-case (hyphenation) convention in the template of your component!
We will see how we declare a component, how the data flow is configurated, as well as how events are handled.
Registration is making your component known by your application so that it can be used during rendering. We will not see global registration here. Check for more information.
Instead, local registration, in addition of providing some advantage about the weight of your app, allows a better organisation and uses the pre-defined model given by the CLI scafolder you used to create your Vue.js project. Lets review the step needed for registration.
As you can see, your Home.vue component has the following code in <script>
In the main.js of your file, you should have something like (if you used the configuration with router)
Stop! What is happening here? Well, in this specifc case, we register our HelloWorld component into our Home component: it is then available to use. The new Vue here create our Vue application. The specificity here is that we specify the router component (automaticaly created with the CLI with routing configuration), which in turn register (well, in a specific way for routing purpose) Home.
So, every of the components you plan to use in a component must be declared in the components object of the host component.
We can use a component only if it has been exported. To do so, you need to use the export keyword in the file where the component is described.
Exported modules are in strict mode whether you declare them as such or not. The export statement cannot be used in embedded scripts.
And to add a component to the array of components, this component needs to be imported! When you use the import Obj from 'my/path/to/Obj.vue, you create an instance of this object.
In a real application, you will often have components which will depend on specific data -- data most of the time provided by their parent. For example, lets imagine that your main App has a user object. We want to pass this object to the userSetting component, in charge of displaying its avatar, and all its information. Passing off the data could be as follow:
The parent gives the object userObj to its child. To receive such a variable, the child component must define its interface (called props in Vue.js), namely all the receivable variables and their alias. In the above example, the alias for the attribute is user. Defining the interface of your child component is by filling up its props array:
Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child component will affect the parent state! Be mindful of your mutation (that is why you should heavily rely on getter and setter -- check )
You can perform prop validation by specifying type requirement in the props attribute of the component, as we perform above:
means that user is an object, and should not be otherwise. You have different keywords available, such as String, Boolean, etc...
Tend to prefer this notation for the props! It is always a good idea to introduce some verifications in your code!
At least, if you want two ways data binding, you can use the v-model directive. Check and here for an . However, it is recommended to use .sync instead alonside event. Check the for more information.
One thing to be noted though: your props are not registered into the reactivity system of the framework. Here is apparently some rules (from ):
If you face issue with reactivity with your propos, check the following list, maybe you fall into one of these case:
primitive props (String, Number, … ) can be reactive in a component only if made dynamic via v-bind:
they are reactive if used in computed properties or in methods
Lecture about Client/Front Side, mostly:
As you have noticed from now, JavaScript is a very flexible language, allowing you to perform things that is usually not possible in more conventional language like Java or C (e.g. non-typed variable and polymorphism). However, the drawback of this flexibility lays often in code instability and weird behaviors (this has an important part to do here).
Exploiting the non-typed approach of JavaScript, a way to allievate weird behaviors is to heavily rely on return; to stop the execution of a function that either does nothing to do, or has face a faillure/unauthorised case. To foster maintenable code, and well documented, the checkings is often made at the begin of the function -- regrouping all the verification in a single place which can be easily documented.

they are not reactive if used in data as initial value - unless being referenced by a watch function. Also note that when used as non-reactive initial data the assigned value will be the props value at the moment of component creation*.
Object (or Array) props can be reactive whether or not passed via v-bind if the object itself is being passed and stored in data - and not just primitive values of the object.
If the Object reference is stored in data any use of this data will be reactive towards the props value
If the Object is cloned or only primitives are stored in data the same rules apply as for primitive props above
However, no matter how hard you try, your code will fail one time or another (because of you, the user, the hardware, etc.). Despite return is a good approach in several cases, sometimes you need more powerful error managment. Indeed, when your script fails, it usually "dies" -- stops immediatly. However, maybe you want to recover from this error and do some specific actions instead of stopping your script (e.g. reinitializing your interface).
My advice is to break hard and break soon! Even if your code growth in size and take you more time by doing so, this is always a good practice, and it will help you when your code will become important.
JavaScript, as several other language, introduced the try...catch syntax:
When JavaScript arrives on a try...catch statement, first the code in try is executed. If no error are thrown inside this block, then the catch block is ignored. Otherwise, the rest of the try block is ignored once an error is thrown. The error is then handled by the catch block and stored in a variable (here error). Consequently, an error does not stop your script of running if it happens in a try block.
The catched error by catch is also an object. The built-in erros has the following useful properties:
name
message
stack
Variable inside try...catch are local! You cannot declare a new variable inside a try block and use it elsewhere. This gives some confusion at the beginning, since it may change how your code is structured, especially with nested try...catch.
There is an additionnal clause to the try...catch which is finally. If attached to a try or a try...catch statement, the content of the finally block is always executed. This is usefull to end/finalise something that has been started. For example, closing a communication socket. The syntax:
You can produce your own error during the execution of your code. For example, parsing a JSON string and noticing that there is no information about an expected state of a game (i.e. gameState is set to undefined). To do so, we simply use the throw keyword:
Error is the super type of all the errors in JavaScript. But there is more specific built-in errors, like SyntaxError, that can be used as Error depending on the situation.
When you throw an error, you create an exit point in code: all the instructions below are no longer executed (like a return).
In a complete example:
You can rethrow a handled error in a catch. Rethrowing is used when the error received cannot be correctly handled where it happens and needs to go back up the execution stack.
You can define your own errors by extending the built-in errors in the language, like any class. And then use it as any other errors:
Since MyError is a class, you can inherit from it too!
An important things to note is that try...catch works synchronously. In other words, if an error happens in a "scheduled" code, like in a event callback or in TimeOut, try...catch will not catch it. That is because the function is executed later in the code, when the engine has alread left the statement.
Thus, to catch an error in an asynchronous, the try...catch need to be in this very function!
In addition, in the case of a async/await situation, it is possible for a promise rejects an error, just as if there were a throw statement at the line of the .reject(new Error).
However, in real situation, the promise will take some times before it rejects. In that case, we can use try...catch to catch the error throw by awaiting.
Use your browser to debug your code!! A good tutorial from the Chrome DevTools.
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue' //Import of another component, declared similarly to this one
export default { //we "export" this object, making it available to import elsewhere
name: 'Home', //the name of our component used in the template <home></home>
components: { // we register here the components used in this Home component
HelloWorld
}
}import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')components: { // we register here the components used in this Home component
HelloWorld,
Comp2,
Comp3,
}
}export default { //we "export" this object, making it available to import elsewhere
name: 'Home',...<user-setting user="userObj"></user-setting> <!--the name of the attribute can be different of the variable!-->export default {
name: 'HelloWorld',
props: {
user: Object,
//can be other prop here!
},
...user: Object,function foo(var1, var2, callback){
if(!callback) //if callback is null or undefined, we stop here
return; //return undefined
if(var1 < 0)
return;
if(var2 > var1*this._someGlobalVar)
return;
if(!this.registerCallback(callback))//callback already exists for example
return;
// Now we can run the function's code
}try {
// code...
}
catch (error)
{
// error handling
}let json = "{ bad json }";
try {
let user = JSON.parse(json); // <-- when an error occurs...
alert( user.name ); // doesn't executed
} catch (e) {
// ...the execution jumps here
alert( "The JSON seems to be corrupted." );
alert( e.name );
alert( e.message );
alert("We will try to retrieve it again soon");
}try {
// try to perfoms the code
} catch(e) {
// lands here if an error happens
} finally {
// always executed!
}throw new Error(message);let json = '{ "nbPlayer": 4 }'; // incomplete data
try {
let game = JSON.parse(json);
if (!game.state) {
throw new SyntaxError("Incomplete data: no game state send by the server!"); // <- We leave the try block here and be catched by the catch below
}
alert( game.state );//never executed!
} catch(e) {// It catches both the JSON.parse error and OUR OWN ERROR!!
alert( "JSON Error: " + e.message ); // JSON Error: Incomplete data: no game state send by the server!
}catch(e) {
if (e instanceof SyntaxError) {
alert( "JSON Error: " + e.message );
} else { //if it is not a syntaxerror, we do not handle it here, we throw above
throw e; // rethrowing
}
}class MyError extends Error {
constructor(message) {
super(message);
this.name = "MyError";
}
}
try{
try{
throw new MyError("hey, i'm the message");
}
catch(e){
if(e instanceof MyError)
throw e; //rethrowing
else
console.log("Error but not ours")
}
catch(e){
console.log("This is a MyError error!!");
}try {
setTimeout(function() {
noSuchVariable; // script will die here
}, 1000);
} catch (e) {
alert( "not catched!" );
}setTimeout(function() {
try {
noSuchVariable; // try..catch handles the error!
} catch {
alert( "error is caught here!" );
}
}, 1000);async function f() { //note the async and await
await Promise.reject(new Error("Error here!")); // equivalent to throw new Error("msg");
}async function f() {
try {
let response = await fetch('/bad-url-lol');
let user = await response.json();
} catch(err) {
// catches errors both in fetch and response.json
alert(err);
}
}
f();In JavaScript, there always exists a special property for each object called [[Prototype]], that is either null or a reference to another object, called a prototype. Prototypes are used to perform prototypal inheritance, which means than the prototype of an object extends this very object. In other, this allows an object to directly reuse properties and methods from its prototype automatically: this is transparent for the developper!
This property [[Prototype]] is internal and hidden: you will not iterate over it with for...in loop for example -- instead you will iterate overs the properties/methods of the prototype. Their is several ways to access the prototype, such as the historical __proto__, but we will not use it anymore. Instead, we will use the class oriented methods, more clean: Object.getPrototypeOf() and Object.setPrototypeOf().
Let's illustrate prototype setting and automatic access of the prototypal chain:
Visually, this give something like:
As you can see, there is one additional prototype, which is the Object.prototype. Indeed, when you create an object, JavaScript automatically attach to this object the Object.prototype in the exemple: this gives us access to a lot of useful function defined for all the object, such as toString().
thisSince this is dynamic in JavaScript, an iterrogation may arise: what is the value of this once in the prototype chain?
The answer is always the initial object calling the property/methods, not the objects from the prototype chain: this is not affected by the prototype chain at all.
Use the following rule to help you find the value of this: no matter where the method is found, this is always the object before the . (dot)!
What happens here is that the variable versus has been attached to the calling object kendo, despite the fact the function that creates it is in its prototype (martialArt). martialArt does not have a versus variable after that.
There is no hoisting (cf. ) concept involved here!
The prorotype is only used for reading properties and methods, not for writting them. Write operation (as for delete though) works directly with the object itself. Thus, you can rewritte an actual function existing in the prototype by the object's own definition of the method.
By now, it should be clear how prototype can be used for object inheritance. As stated above, this is called prototypal inheritance. Here we will see how we can extend an object using constructor function and new operator by using a property named prototype.
Here we speak of a special property called prototype, not the [[Prototype]] seen above. It is only used once: while construction an object via a function thanks to new.
This property prototype of a constructor function (cf. ) means the following: "When a new object is created (by using the new operator), assigns its [[Prototype]] to the given object". By this mean, all the objects from a constructor function created with new will all have the object as prototype.
Class inheritance is a basic feature in OOP allowing to extends the functionalities of a class with ones from another class. In JavaScript, it is basically a syntactic sugar for prototype manipulation.
This is how graphically the above example can be represented:
Now, if we want to create a new class, lets say Planet, that is based on Satelite (i.e. that share similar concepts), we can use the extends keyword to indicate so. The global syntax is class Child extends Parents. In our example, this will result in:
Internally, extends keyword works using prototype mechanism. It sets Planet.prototype.[[Prototype]] to Satelite.prototype. So, if a method is not found in Planet.prototype, JavaScript takes it from Satelite.prototype, as we have seen before.
As said previously, when JavaScript is told to execute a specific method from an object, it firts checks if this object has a property of that name. If not, it goes back up the object prototype and checks in it, and repeats the operation while the property has not beend found or there is no more prototype to explore. That means if we define a new explode method in Planet, all planet object will have a function property named explode: JavaScript will not bother to go back up the prototype chain. This is called overriding a method.
However, when overriding a method from the parent class, we often want to build on top of it, not entierely replace it. In other want, we want to call the parent method before (or after), then perform the class's specific operations. To do so, we use the super keyword (e.g. super.explode()).
super can also be used to override constructor. Currently, Planet does not have is own constructor, it relies entierely on the Satelite constructor. But if your class needs to have a specific construction, you can't rely entierely on the parent class (which is probable more generic). Calling a constructor parent with super(...) can only be done in a constructor.
A child constructor MUST always have a call to its parent constructor (super(...))! In addition, this call MUST be made before any property affection (e.g. this.x = smth). This is logical, because you build your child on top of your parent!
Protected fields are not supported to the language-level. As so, the convention is to used the _ to prefix them (cf. ). A direct consequence of this is that protected fields are directly accessible from a child to its parents -- since they are just properties obfuscated.
Private fields in the other hand are not inherited. There is no direct access to a private methods/attributes from a child to its parent. Consequently, you will need to rely on both getter and setter to retrieve the information, otherwise JavaScript will throw an error.
Static methods and static properties are also inherited!
As we have seen, there is only one [[Prototype]] for an object at a time. This implies that multi-inheritance is not possible using extends. Despite this prevents complex and dangerous inheritances (like diamond ones), this can feel a little limitating. To alleviate this, JavaScript implements mixin.
A way to implement a mixin in JavaScript is to define an object continue the desired useful methods, and then merge them to the desired objects, by using the Object.assign(source, mixin) function.
From :
A mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes.
Sometimes, you will just want to use a specific method from another class, and inheriting from it could be misconceptual (i.e. inheriting a Planet while the child is Pencil). It is possible to borrow methods from an object, by using the bind, apply and call keywords.
Just a word on bind thought. This very useful keyword allows us to set the value of this to the provided value.
Example (from ):
Hook example :
Dynamic routing is the heart of any SPA application. Instead of changing and loading a new web page when the website URL changed, the idea is to update the page by adding and removing new component on the page. To do so, The HTTP request is caught by a dedicated router component, and if the desired URL match the routing rules of the router, then components are invoked and destroyed in order to update the page.
If you have created your Vue.js application using the CLI as writen , then you should have a router component called index.js in the folder @/src/router/ (@ is the root of your Vue.js project). Let's have a look
In order:
Import and global configuration for your router component. You need vue-router to be able to route HTTP request. Don't fort Vue.use to say Vue to use the router!
Define some routes. Each route should map to a component. So a route has a path where it trigger (e.g. when writting server/url/about) and the component to call.
Create the router instance and pass the
The important thing to note here is the path property. This property indicates which queries has to be caught -- any uncaught path generate a new server call. The / indicated the root of your website. Therefore, when accessing the index of your website, you will instead load/render the Home component ; when accessing the /about URL, it will be the About imported component.
In addition, when an URL maps a route definition, the component(s) specified in the components property will somewhat "replace" the <router-view/> component. Think of it as an anchor.
That's it! Do you see the advantage of web components now? Each page relies on either one or several components!
## Dynamic routing Most of the time, your website will access very similar resources, discriminated only by a specific information. For example, you can access your users Sol and Ky with the /user URL suffixed with their pseudi, like in /user/sol and /user/ky.
In a web component approach though, this will be the same component that will handle this data processing and rendering (and request). So we need a way to map several routes to a same component: this is dynamic routing. To do so, we can use dynamic segment in the path expression:
You can have multiple dynamic segments in your url. Say that we want to retrieve a specific game information (the 315th) of the user Baiken, the dynamic path could be:
The content of the $route.params here will be {username: "Baiken", id_game: 315}.
As we have seen, we can use $route both in the template of your component, and also in the JavaScript of your component. However, this may create intricate coupling between your route and your component, and this is not very good for maintenance and scaling. A good way to do so is to pass the $route.params as props for your component.
Here is how you can do that:
Thus, your componant can now be used everywhere in your app: its interface is clearly specified -- it waits an id. The true boolean in the route declaration is used to transform your params into props. You need to set it to true to use this feature.
You can even set a function which returns props. Check !
In complex application, the page is often composed of several components nested at various levels. For example, we could imagine that accessing the games information for a specific user is still made in the user component, as well as accessing its profile.
The routing logic here should not be entierely made at the top level, but instead to the component-level. The top-level application should indeed redirect to the User component, but any further route mapping should be handled by this component, such as accessing the profile of the user.
Thus we could used the <router-view></router-view> component to host the nested component and react according to the end of the URL.
To indicate that a component is supposed to be nested according to a specific route, you need to used the children property of a route. Moreover, if you want to keep access to the parent page (here: /user/Sol), you will need to specify an empty subroute.
Maybe you will also have complex view in your application, and consequently several <router-view> in one same component. You can name them and specify which view has to be updated when a path is matched. More information in
In this section, we will see how you can conjuge an OOP approach with Vue.js
The first thing you need to do is to export your class declaration. If you have a one class per file project organisation, a Weapon.js class could look as
Once your class is exported, you can still use it within other classes (or even inherit from them). For example, a NPC.js class using a weapon:
In this section, we will see the principal Web API client-side which are built-in the browsers. As a reminder, API (Application Programming Interfaces) are a way to simplify the construction of complex functionnalities by using abstract, high-level, functionnalities. The principal API we will use are the DOM API, used to manipulate the DOM for your page.
For your project, you will probably need the four following API:
DOM API
Fetching API
What is the big deal with events? It is that they illustrate how your code can run asynchronously! And this is a very important aspect for a client side application. Indeed, without this asynchronous aspect, waiting a button to be clicked will block the entire page, thus making it unbrowsable. More generally, code runs straight along, making instruction after instruction ; however, if your instruction is quite important and cpu-intensive and take some time to finish, the whole experience will appear to be frozen for the user, unresponding even to its clicks.
This behavior is called blocking : an intensive chunk of code runs without returning control to the browser, and therefore the browser appears to be frozen. The reason is that JavaScript is single threaded.
Asynchronicity allows us to initiate actions at a specific time, and finish them later without worrying to call them again.
<input id="elem" type="button" value="Click me">var elem = document.getElementById("elem");
elem.addEventListener('click', (e) => alert(e), false);elem.addEventListener('click', function(e){
alert(event.type + " at " + event.currentTarget); // shows event type, element
alert("Coord: " + event.clientX + ":" + event.clientY); // shows coord
}) let obj = {
handleEvent(event) {
alert(event.type + " at " + event.currentTarget);
}
};
elem.addEventListener('click', obj);class Menu {
handleEvent(event) {
let method = 'on' + event.type[0].toUpperCase() + event.type.slice(1); //we retrieve the name of the event, the we split to conserve the name for the function
this[method](event); //look here: calling the appropriate function according to event
}
onMousedown() {
elem.innerHTML = "Mouse button pressed";
}
onMouseup() {
elem.innerHTML += "...and released.";
}
}
let menu = new Menu();
elem.addEventListener('mousedown', menu);
elem.addEventListener('mouseup', menu);var myEvent = new Event("nameEvent");domElem.addEventListener('nameEvent', function(e){/*...*/}, false);domElem.dispatchEvent('nameEvent');var myCEvent = new CustomeEvent("custom", {detail : aVar.value, name : elem.name})
// access the data as usual in the handling function
function evtHandler(e)
{
console.log("Details are" + e.detail);
}<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>form.onclick = function(event) {
alert("target = " + event.target.tagName + ", this=" + this.tagName);
}table.addEventListener('click',function(event) {
let td = event.target.closest('td'); // returns the nearest ancestor that matches the selector.
if (!td) return; // if the user did not click on a td, nothing to do
if (!table.contains(td)) return; // if there is nested table, the td could not be the td of the table we are interested in, so return
highlight(td); // highlight the cell, for example with selectedTd.classList.add('highlight');
});<div id="menu">
<button data-action="save">Save</button>
<button data-action="load">Load</button>
<button data-action="search">Search</button>
</div> class Menu {
constructor(elem) {
this._elem = elem;
elem.addEventListener('click', this.onClick.bind(this)); // (1)
}
save() {
alert('saving');
}
load() {
alert('loading');
}
search() {
alert('searching');
}
onClick(event) {
let action = event.target.dataset.action;
if (action) {
this[action]();
}
};
}
let menu = document.getElementById("menu");
new Menu(menu);Counter: <input type="button" value="1" data-counter>
One more counter: <input type="button" value="2" data-counter>
<script>
document.addEventListener('click', function(event) {
if (event.target.dataset.counter != undefined) { // if the attribute exists...
event.target.value++;
}
});
</script>With all that, you have what you need to adopt an OOP approach in your Front End app! Have fun!
export default class Weapon{
constructor(val, type)
{
this.val = val;
this.family = type;
}
}import Weapon from "./my/path/Weapon.js"; //Weapon variable is available, we can construct new weapon is `new`
export default class NPC{ //don't forget to export this class too!
constructor()
{
this.weapons = [];
this.weapons[0] = new Weapon(5,"bamboo"); //new instance of weapon!
}
pickWeapon(wpn)
{
this.weapons.push(weapons);
}
throwWeapon()
{
this.weapons.pop();
}
}</script><template>
<div class="hello">
<h1>{{ msg }}</h1>
<p v-if="hand">
yo!
{{ npc.weapons.length }}<br/> <!--displaying size of the weapons array of the npc-->
</p>
</div>
</template>
<script>import Weapon from '../model/Weapon.js' //don't forget to import them
import NPC from '../model/NPC.js'
export default {
name: 'myComponents',
props: {
msg: String
},
data(){ //remember, in a component, data must be a function!
return{
npc: null, //our npc object
}
},
mounted(){ //hook on mounted, we init the object. It could have been done before.
this.npc = new NPC();
this.npc.pickWeapon(new Weapon(7, "chakram"));
console.log("New weapon acquired! GG");
setTimeout(() => { //update of the weapons, we will throw a weapon in 2 sec, for testing reactivity since we print the array length!
this.npc.throwWeapon();
console.log("Weapon throws");
this.npc.weapons[0].family = "reactivIsIt?"; //re-render once modified!
}, 2000);
}
}routesExport the router (it is used in Vue.js, go check there!)
Drawing API
Audio API
Generally speaking, an API uses JavaScript object to handle the data from the API. This means that you can manipulate these objects in your code and access API's data easily by they properties and their methods. For example, retrieving a document on the page Object.getElementById(id) or playing a sound SoundObject.play().
When manipulating an API, you should identify where its entry point(s) is(are). An entry point is generally an object representing the API's data, where most of the functionnalities of the API are available and where you can begin to work with.
Obviously, the entry point for the DOM API is the Document document, or an instance of an HTML element that you want to affect in some way. For the 2D API Canvas, its the <canvas> element and then calling CanvasElement.getContext().
As you already know, the content you see in your browser is a set of HTML, CSS and JS. HTML is the content of your web page, and has a tree structure in order to be easier to be manipulate. This tree structure is called DOM.
In the above tree example, we can highlight important concepts:
Element node: It is an element as it exists in an HTML file (e.g. <p>)
Root node: The top node in the tree, which is always HTML for HTML file
Child node: The direct node of a chosed node
Descendant node: A node contained inside a chosed node, independantly of its depths
Parent node: The node of a descendant node
Sibling nodes: Nodes that are in the same level in the DOM tree
Text node: A node containing a text string
JavaScript has been made principally to manipulate the DOM of a page.
DOM elements retrieval is more than a common operation: it allows you to get the element to listen to, the element you want to update and so on. There is a lot of way for selecting DOM elements in JS. We will see the more common and convenient here.
Old selector functions are getElementByClass and getElementById. They select specific elements in the DOM according, respectively, to their class or their id. They are used with a direct reference with the document.
In more recent JavaScript version, querySelector has been introduced. It is more powerfull and versatile than the getElementByXXX since it combines all these functions in one. Concretly, querySelector relies on CSS selector to perform the search in the DOM tree, somewhat unifying the selecting keywords in JS and CSS.
The above example can be written as follow using querySelector
Consequently, since you can use CSS selector in querySelector, you can now make complex query (taken from MDN)
You can manually add (therefore creating) new elements to the DOM using JavaScript. To create programmatically a new HTML element, the keyword is createElement(ANY_HTML_ELMT), and it is used like that:
Now, we just need to attach this new paragraph to our document. Let's say that we want to attach it to the main div of our page, then we first need to select these div, and attach its the new paragraph.
HTML element can have attributes (e.g. an id, a src). Since getting DOM elements returns us objects, we can directly access these attributes in their properties!
Sometimes, though, the attributes attached to an HTML element can be non-standard (i.e. either not expected for the element, or does not exist in the standard). For non-standard attributes, their corresponding properties are not created in the object!
However, you can access/modify/remove such non-standard attributes by using the following methods:
.hasAttribute(name)
.getAttribute(name)
.setAttribute(name, value)
.removeAttribute(name)
When a standard attribute changes, the change also reflects in the corresponding property. The other way is also true. So when you perform a elm.setAttribute("attr", value), the changed is reported back to the HTML element's attribute.
However, their is (ofc...) exceptions to this. For example, the input.value synchronises itself only in the attribute -> propertye way, not the other. That means that you cannot perform a .setAttribute("value", "someVal") on an input element.
Non-standard properties are usefull to pass some specific data to your HTML elements. However, since the HTML evolves continiously, it may happen that your non standard property becomes a standard property, possibly making huge mess in your code.
That is why to avoid conflict dataset has been introduced for the data-* attributes. All HTML object has a dataset property listing all the data attributes an HTML element has.
For example, if your element has an data attribute named data-family, you can access it:
Multiword attributes like data-my-family become camel-cased: dataset.orderMyFamily.
In addition, data attribute can even be used to store other object (use it with parsimony). Since they are HTML attributes however, we can't store an object reference directly, we have to transform it in a compatible string. That is good because an object can be encoded as a JSON object, so with can do the following:
In a web component paradigm (we will see that with Vue.js), an important aspect is the encapsulation of markup structure, styles and behaviors: they should nenot be leaking between components. However, due to how the DOM and the DOM API are made, this is not possible by simply using the standard DOM specification.
That is why the concept of Shadow DOM has been introduced. Shadow DOMs are hidden DOMs, not parsed by the DOM API, and only sensible to what happen inside them. We will cover this aspect in more detail in the Single Page Application section.
More information about shadow dom here.
Form and control elements are one of the principal source of interaction between your user and the server. That is why they have special properties and events attached to make their use more convenient in JavaScript.
Despite forms can be retrieved as any HTML elements using selector (e.g. querySelector), they are also member of a special named (and ordered) property collection of the document, called forms. And, each form of this document.forms collection has a named (and ordered) collection elements, listing all the elements contained in the form. Therefore, you can then easily access any form and form's elements in a page simply by name.
If you organise your form with <fieldset> element, you gain even more control on how your form is structured. Each fieldset element also has an elements property listing all its child form elements. And since a fieldset is a form element, it is also retrievable by its name.
Form control is related to accessing, setting and checking form's elements value. To access their value, we can use the value property. Note that its content depends obviously of the type of input checked.
You can also set the element value.
Generally speaking, the information of interest in an element form is stored in the value property, not in the innerHTML.
So far, we have seen how to access forms' elements. However, this is not really useful if we did not know when to check for their value! Luckily, JavaScript trigger a lot of events when elements are used.
Every time an element's value is modified by the user, this event is triggered.
The input event does not only trigger with keyboard events, but also with other device, such as mouse (e.g. pasting a text from the clipboard) or with text recognition device. However, non altering action, such as pressing ^ alone (or directional arrow) does not trigger this event.
This event is good if you need a fine management on the element.
However, we often don't need such a fine management over an element. We prefer to check the element once it has lost focused. The event is change and can be used as follow.
The submit event triggers when a form is submitted. This means that either an input of type="submit" as been clicked or enter has been pressed in a field. This is usually used to validate the form before sending it to the server or to abort the submission and process it in JavaScript.
Never ever trust the user side of your application. It is possible to get rid of your data control. User side verification should be design with reducing the server side load in mind, not replacing it!
However, the submit event is not attached to the submit input, but to the form!
The method submit() of a form allows to initiate form sending, from a JavaScript standpoint. This is useful to manually send our own forms to our server.
The need of dynamically refreshing some part of a web page, and not the whole page, is an important feature in the web now. Indeed, from a server standpoint, sending just some chunck of data is often a more lightweight operation, and from a UX design point of view, the flow stay consistent: only the elements that are supposed to change are actually updated on the page, creating dynamic web page.
In a conventional web application, for retrieving specific elements, a new whole HTML page has to be received. This is not the case whith an asynchrone communication. The most known approach is AJAX. It works as follow
However, this is somewhat similar to all the asynchrone approaches: the DOM is updated asynchronously. In any case, the server should obviously be designed to handle such asynchrone requests.
Asyncrhonous JavaScript And XML (AJAX) is a programming practice designed to build dynamic web pages relying on asynchronous communication. It uses the xmlHttpRequest to communicate with the server.
However, we will not study this technology, since the fetch API has been recently introduced and is planned to replace it. Nonetheless, almost all the current web site use AJAX for now, so it is important to understand what it is and how to use it.
The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set. (source: MDN)
Put in other terms, the Fetch API is a wrapper, a generic definition on how systems request resources and how they respond, and therefore can be extended to much more than network communication.
The basic syntax for fetching resources from a server is simply:
Note that fetch returns a promise, and without option, your perform a GET request, downloading the content from the url. Getting a response is a two stages process :
The promise of fetch resolves with a Response object as soon as the server responds with headers.
The response as to be parsed to gets its content/body.
In the first stage, we usually check the status code (a property) of the headers received in the response. The shortcut response.ok is useful to check if the status code is between 200-299. If not, you know that there was an error during the fetch.
Abnormal error (e.g. 300-499) do not cause an error! Therefore the following code is not equivalent:
Because bad HTTP code will not be caught.
The seconde stage is to get the response body. In the above example, we saw that we do a response.json() to get that body. This is possible because Reponse give provides multiple promise-based methods to access the body. Some other examples:
response.text(): read the response and return a string,
response.blob(): return the response as a blob object,
response.arrayBuffer(): return the response as an array buffer.
A body can only be consumed once! You cannot call consecutively response.json() then response.text().
You can also make asynchrone POST with fetch. To do so, you will need to specify the method, the header and the content (body) of your request. The body can only be one of the following type:
a string (e.g. JSON-encoded),
FormData object, to submit the data as form/multipart,
Blob/BufferSource to send binary data,
URLSearchParams, to submit the data in x-www-form-urlencoded encoding, rarely used.
(The JSON format is used most of the time)
Like that, you can for example send an image once uploaded in a form without reloading the entire page.
Working with an asyncrhonous requires to change the way of how your think about your code and how it is supposed to run. Otherwise, catastrophes are on the way. Thus you need to be fully aware of the code execution order. The example below will console the first and the last log ; the second being block until someone click on a button:
A callback function is a function (generally anonymous) passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. This is extremelly usefull to make versatile function by attaching it a specific behavior when it has finished to run.
We have already seen callbacks a lot in the Events section!
Callback are not always associated with events though. They can also be used with simple function (native or custom). For example with Timeout
Or custom functions
It is also possible to use callback functions inside other callback functions and make a whole chain of actions triggering automaticaly (e.g. on click of the button, perform an action then draw).
Be carefull of the nesting of callbacks, since it can quickly become out of control if the depth is too important. A way to alievate this problem is to create small standalone function and do not rely on anonymous function.
Promises have some similarities with callbacks. They are essentially a returned object to which you attach callback functions, rather than having to pass callbacks into a function. However, promises are specifically made for handling async operations, and have many advantages over old-style callbacks:
Chainning multiple async operations together is simple and easier to read (including the passing of the result to the following promise)
They assure consistency in the event queue
Error handling is better
They avoid inversion control
Concretely, the constructor syntax for a promise looks like:
A promise involve always two "entities" in your code, and bind them together. The concept is the following, there is the concept of
An executor, that does/returns something and generally take time. For instance, retrieving data over the network according to your REST API.
A consuming code, that wants the result of the executor once it’s ready (not before! Because it is useless).
The executor's arguments resolve and reject are callbacks automatically provided by JavaScript itself (no need to create them). They should always be present in the definition of the executor of your promise. When the executor obtains the result, be it soon or late, doesn’t matter, it should call one of these callbacks:
resolve(value): if the job finished successfully, with result value.
reject(error): if an error occurred, error is the error object.
(Please mind the three differents states of a promise, as well as the value of the result property) Now, let's illustrate how this works with a simple executor code using setTimeout.
After one second of “processing” the executor calls resolve("done") to produce the result. This changes the state of the promise object from pending to fulfilled.
This goes the same for the executor rejecting the promise with an error:
There can be only a single result or an error. The executor should call only one resolve or one reject. Subsequent call to resolve or reject are simply ignored : any state change is final. HOWEVER, instructions after the call to resolve or reject are still performed.
resolve/reject expect only one argument (or none) and will ignore additional arguments.
As stated before, a promise bind an executor with a "consumer" which will receive the result or the error from the executor. A "consumer" is represented by consuming functions that are subscribed to the promise using one the three following methods/handlers:
.then
.catch
.finally
The .then handler is the fundamental one for promises. It dispatches the executor's result variable to the appropriate consuming function according to the executor's state. The syntax is:
The first argument of .then is the function to run when the promise is resolved, and takes the result. The second argument is the function to run when the promise is rejected, and receives the error from the executor. It can be used as follow:
The .catch handler is designed to simplify the retrieve of the error if you are only interested by it. Instead of using .then with a null value for the resolve like .then(null, errorHandlingFunction), we can use .catch(errorHandlingFunction) which does exactly the same.
The call to .finally will always run the consuming function associated with when the promise is settled (i.e. has been resolved or rejected). It is a good handler for performing cleanup (e.g. stopping our loading animations, etc.).
.finally has no arguments: we do not know whether the promise is successful or not. This should not bother you because the kind of operations here are supposed to be "global", like stoping loading animation, etc.
Promises offer a really convenient way to deal with a sequence of asynchronous tasks to be performed one after another, which is call chaining. The idea beyond chaining is that the result is passed through the chain of .then handlers.
The chaining process is possible because a call to promise.then returns a thenable object (quite equivalent to a promise). Therefore, we can also call the next .then on it.
The triggering of the chaining is asynchrone, but even if the two last executors looks like they run in a synchronous way, they don't. They indeed wait the previous executor to finish, but if you are writing code below a .then handler the code will run probably before the handler.
You can also reintroduce asynchronicity in the chaining by creating and returning a new promise.
Let's see another, more concrete, example with the fetch method (more powerfull and flexible than XMLHttpRequest). We will retrieve my GitHub avatar, by finding my name in the commit history of the CDAW project on github, then display it for 3sec before removing it.
Remember, anyway, that : Promise handling is always asynchronous! Even if a .then wait the previous .then to finish, all the rest of your code is still running!
The async keyword, put in front of a function declaration, turn the function into an async function. An async function is a function that knows how to expect the possibility of the await keyword being used to invoke asynchronous code. An async function in fact returns -- automatically or not -- a promise.
Is equivalent to
So, async ensures that the function always returns a promise, wrapping anything non-promises in a promise.
The await keyword works only inside async functions. It makes JavaScript actually wait that the promise's state settles and return its result.
The syntax looks like:
The important thing to note is that the execution is "paused" until the promise is settled. That means that the code below the await instruction will not be executed until the promise is finished.
Roughly speaking, it can be seen as a more elegant way to deal with .then handlers.
To conclude, to call an async function from an non-async, do not forget that you receive a promise!
Handling error for async/await function is relying on try...catch syntax, instead of the .catch handler.
In a complex web app, where interactions between users exist, you will probably need to synchronize several users together. This occurs mostly when a user performed an action, which change the state of the app, and this change needs to be refleted on other users. In a standard web architecture, the sever cannot take any kind of initiative per se, it waits for client to request information. Therefore, the synchronization of users must be thought of in the client side.
On a client-server architecture, the server is the final authority regarding logic and decisions.
Accordingly, you will need three steps to achieve such a synchronization, relying on asynchronous communication:
Send a POST request to the server, indicating that the state of the app (e.g. the game) has changed
Update, in the server, the state of the app with the newly received state from the client (remember to perform security tests!)
All clients should ask regularly the server if there is any change in the app's state. If so, retrieve the change and reflect it accordingly
setTimeOut is very usefull to achieve this behavior. However, keep in mind that setTimeOut, as well as all time related function, are not reliable. Even if you set a specific amount of time t, the wait will be t+Δt. Thus, you will potentially face desynchronization issues with such a method. This kind of problem has been talked a lot on the internet. Here is an interesting post and reflexion about this topic in JavaScript, wrote by Gary Weiss.
There is three things to figure out for rendering a component :
Where this component will be placed on the page and its objectif
What are the DOM command that can be used within the template
How to setup the reactivity of your component, so that it becomes dynamic
// ----- 1 ------
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
// ----- 2 ------
const routes = [
{
path: '/',
name: 'Home',
component: Home //this method of referencing component is better for now!
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
// ----- 3 ------
const router = new VueRouter({
routes
})
// ----- 4 ------
export default routerconst User = {
template: '<div>User name: {{ $route.params.id }}</div>' //when a route is matched, a $route object is create and usable as in here
}
const router = new VueRouter({ // or simply router if you import it!
routes: [
// dynamic segments start with a colon
{ path: '/user/:id', component: User }
]
}){ path: '/user/:username/game/:id_game', component: Game }const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({// or simply router if you import it!
routes: [
{ path: '/user/:id', component: User, props: true },
]
})const User = {
template: '
<div class="user">'+
'<h2>User {{ $route.params.id }}</h2>'+
'<router-view></router-view>'+ //router-view will be replaced with the specified child component.
'</div>'
}const router = new VueRouter({//router-view will be replaced with the specified child component.
routes: [
{ path: '/user/:id', component: User,
children: [
{ path: '', component: UserHome }, // empty subroute, redirecting to the homepage for /user/Sol
{
// UserProfile will be rendered inside User's <router-view>
// when /user/:id/profile is matched
path: 'profile',
component: UserProfile
},
{
// UserPosts will be rendered inside User's <router-view>
// when /user/:id/games is matched
path: 'games',
component: UserGames
}
]
}
]
})let circularForm = document.forms.myForm.radio.form; // get the myForm form!fetch(url)
.then(response=>response.json())
.then(json=>alert)
.catch(err=>alert)let myIdElm = document.getElementById("idOfMyHTML"); //returns only the html object maching, or undefined
let myClassElems = document.getElementByClass("myclassHTML"); //return an array-like object of all the elements found with myclassHTMLlet myIdElm = document.querySelector("#idOfMyHTML");
let myClassElems = document.querySelectorAll(".myclassHTML"); //Note we use querySelectorAll here, returning an array-like let myElm = document.querySelector("div.user-panel.main input[name='login']")let newElm = document.createElement("p"); // create a new <div> element
newElm.textContent = "Let's make some content here";let divToAttach = document.querySelector("div#main");
divToAttach.appendChild(newElm); // p is attached (to the end) of the div now !let elm = document.querySelector("#superId");
alert(elm.id); // superId from the object elm<div id="standard" plop="non-standard"></div>
let elm = document.querySelector("#standard");
alert(elm.plop); //undefined!let elm = document.querySelector("#idTest");
alert(elm.dataset.family) // bamboo
elm.dataset.family = "circle"; //setting non standard elmlet myObj = {
name: "MyName",
tileVal: "2",
}
let elm = document.querySelector("#idTest");
myObj.json().then(data => elm.dataset.tile = data);<form id="myId" name="myForm">
<input type="radio" name="one" value="radioInput">
<input type="password" name="two" value="mypwd">
<input type="text" name="two" value="name">
</form>let form = document.forms.myForm; //get the above form object!
let radio = form.elements.radio; //get the radio input object
let collec = form.elements.two; //get a collection containing the password input object and the text input objectlet myFS = form.elements.myFieldsetName; //retrieving the myFieldsetName FS
let anElm = myFS.elements.name; // retrieving the input element name from the FSlet rdio = document.forms.myForm.radio.value; // the content of the radio value
let pwd = document.forms.myForm.two[0].value; // the pwdlet radio = document.forms.myForm.myRadio;
radio.addEventListener("input", function(data){
alert("onInput!");
})let radio = document.forms.myForm.myRadio;
radio.addEventListener("change", function(data){
alert("onChange!");
})let form = document.forms.myForm;
form.addEventListener("submit", function(data){
alert("youhou! Soshin!");
// perform form verif here !
})let form = document.createElement('form');
form.action = 'https://google.com/search';
form.method = 'GET';
form.innerHTML = '<input name="form" value="test">';
// the form must be in the document to submit it
document.body.append(form);
form.submit();let promise = fetch(url, [options]);let response = await fetch(url);
if (response.ok) { // if HTTP-status is 200-299
// get the response body
let json = await response.json();
} else {
alert("HTTP in header: " + response.status);
}let response = await fetch('/my/url/to/space/observatory/planet', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(venus); //we send our old venus object over POST
}); //creating the content and sending the request
let result = await response.json(); //we want to know how our request has been handled by the serverconst fileInput = document.querySelector('#your-file-input') ;
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const options = {
method: 'POST',
body: formData,
headers: {'Content-Type': 'multipart/form-data',}
};
fetch('your-upload-url', options);console.log("registering click handler");
button.addEventListener('click', () => {
console.log("get click");
});
console.log("all done"); setTimeout(function(){ alert("I'm callback!"); }, 3000);function calculate(num1, num2, callbackFunction) { //take a callback function
return callbackFunction(num1, num2);
}
function calcProduct(num1, num2) { // a callback
return num1 * num2;
}
function calcSum(num1, num2) { // another callback
return num1 + num2;
}
console.log(calculate(4, 25, calcProduct)); // cli: 100
console.log(calculate(4, 25, calcSum)); // cli : 29let promise = new Promise(function(resolve, reject) { /*the EXECUTOR code here*/});let promise = new Promise(function(resolve, reject) { // reminds that the executor is automatically executed when the promise is constructed
setTimeout(() => resolve("done"), 1000); // after 1 second, we consider the operation successful and we return the result "done"
});let promise = new Promise(function(resolve, reject) { // reminds that the executor is automatically executed when the promise is constructed
setTimeout(() => reject(new Error("Whoops!")), 1000); // after 1 second, we consider the operation failed and we return an error object
});promise.then(
function(result) { /* handle a successful result */ },
function(error) { /* handle an error */ }
);let promise = new Promise(function(resolve, reject) { //don't forget ! the code runs automatically, but we wait 1 sec
setTimeout(() => resolve("done!"), 1000);
});
promise.then(
result => alert(result), // shows "done!" after 1 second since we always resolve
error => alert(error) // doesn't run
);let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Whoops!")), 1000);
});
// .catch(f) is the same as promise.then(null, f)
promise.catch(alert); // shows "Error: Whoops!" after 1 secondnew Promise((resolve, reject) => {
setTimeout(() => resolve("result"), 2000)
})
.finally(() => alert("Promise ready. Do global task"))
.then(result => alert(result)); // .then still handles the result. IDEM for rejectnew Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // asyncrhonous
}).then(function(result) { // when the above executor finishes, execute this one
alert(result); // 1
return result * 2;
}).then(function(result) { // handle the return value of the previous executor (result * 2)
alert(result); // 2
return result * 3;
}).then(function(result) { // handle the return value of the previous executor (result * 3)
alert(result); // 4
return result * 4;
});new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) { // triggered after 1sec
alert(result); // 1
return new Promise((resolve, reject) => { // returning a new promise. REMEMBER! a new promise constructor automatically run the executor!
setTimeout(() => resolve(result * 2), 5000);
});
}).then(function(result) { // triggered after 5 sec (so ~6sec in total since the begigning)
alert(result); // 2
return new Promise((resolve, reject) => { //Idem
setTimeout(() => reject(result * 3), 2000); //this time we trigger an error for the sake of example
});
}).then(null, function(error) { // or (error) => alert(error)
alert(error); // 6, in the error state
});fetch('https://api.github.com/repos/ceri-num/uv-cdaw/commits')
.then(response => response.json())
.then(commits => fetch("https://api.github.com/users/"+commits[10].author.login))
.then(response => response.json())
.then(githubUser => {
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => img.remove(), 3000); // async callback, removing the img
});async function f() {
return 7;
}
f().then(console.log); // cli : 7function f(){
return new Promise((resolve, reject) => resolve(7));
}let value = await promise; // works only inside async functionsasync function f() {
let promise = new Promise((resolve, reject) => { // our previous example with the executor waiting 1 sec
setTimeout(() => resolve("done!"), 1000)
});
// here the clock is already running
let result = await promise; // BLOCK! Wait until the promise resolves. Result store the result of the promise, here "done"
alert(result); // trigger an alert after waiting the promise to end, ~1 sec. after
}
f();async function myGitHubAvatar(){
let response = await fetch('https://api.github.com/repos/ceri-num/uv-cdaw/commits');
let commits = await response.json();
let user = await fetch("https://api.github.com/users/"+commits[10].author.login);
let githubUser = await user.json();
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
await new Promise((resolve, reject) => setTimeout(resolve, 3000)); // async callback, removing the img
img.remove();
return githubUser
}
myGitHubAvatar();async function waitingF() {
await new Promise(resolve => setTimeout(resolve, 1000)); //wait 1 sec
return 7;
}
function f() { //non async function, we can't use await here!
waitingF().then(result => alert(result)); //simply use .then
}
f();let martialArt = {
grade: "3rd Dan",
fight(){
console.log("Tōōōō~~~");
},
}
let kendo = {
armor: true,
}
let kendoTournament = {
participant: 105,
}
Object.setPrototypeOf(kendo, martialArt); // we set the prototype of kendo with martialArt obecjt
Object.setPrototypeOf(kendoTournament, kendo); // IDEM kT with kendo, which has its prototype filed with martialArt!
alert(kendo.armor); //true
alert(kendo.grade); //"3rd Dan"
alert(kendo.participant); // Error // We can't go "down" the prototype chain
alert(kendoTournament.armor); //true
alert(kendoTournament.grade); // "3rd Dan", we go up again in the prototype and get martialArt property!
alert(kendoTournament.fight()); // "Tōōōō~~~"let martialArt = {
grade: "3rd Dan",
fight(){
if(this.versus)
console.log("HAJIME!");
},
makeVersus()
{
this.versus= true;
}
}
let kendo = {
armor: true,
}
Object.setPrototypeOf(kendo, martialArt);
kendo.makeVersus();
alert(kendo.fight); // cli: HAJIME!
alert(martialArt); // Undefined variable this.versus in the prototypelet martialArt = {
grade: "3rd Dan",
fight(){
console.log("Tōōōō~~~"); // this method will not longer be used by kendo
},
}
let kendo = {
armor: true,
}
Object.setPrototypeOf(kendo, martialArt);
kendo.fight = function(){
console.log("Geikō time! BANZAI!");
}
alert(kendo.fight); // Geikō time! BANZAI!let martialArt = {
grade: "3rd Dan",
fight(){
console.log("Tōōōō~~~");
},
}
function Kendoka(armor){
this.armor = armor;
}
Kendoka.prototype = martialArt; // all the instance of Kendoka will have martialArt object in their direct prototype chain
let kendo = new Kendoka(true);
alert(kendo.grade) // 3rd Danclass Satelite{
constructor(name, velocity=-1)
{
this.name = name; this.velocity = velocity;
}
beAttracted(velocity){
this.velocity += (velocity * 9.8);
console.log("I'm attracted... by u!");
}
explode()
{
this.velocity = 0;
console.log("K... B O O M");
}
}
let sat = new Satelite("Hinode", 500);class Planet extends Satelite{
rotate(degree){
this.rotation += degree;
console.log("I'm rotating! Youhou!");
}
}
let venus = new Planet("Venus"); // <- Observe that we used the Planet constructor calling the Satelite constructor!
venus.rotate(20); // I'm rotating! Youhou!
venus.beAttracted(300); // I'm attracted... by u!class Planet extends Satelite{
rotate(degree){...}
explode(){
this.rotate(15000); // Lets spins a little the ball of death before exploding!
super.explode();
}
}
let venus = new Planet("Venus");
venus.explode(); // I'm rotating! Youhou! ; "K... B O O M"class Planet extends Satelite{
constructor(name, rotate){
super(name, 0); // calling the constructor of Parent (and creating the first "part" for planet)
this.rotate = rotate;
}
} constructor(...args) {
super(...args);
}class Satelite{
static place = "Universe";
constructor(name, velocity){...}
beAttracted(){...}
explode(){...}
static compareSatVelocity(sateliteA, sateliteB)
{
return sateliteA.velocity - satelireB.velocity;
}
}
class Planet extends Satelite{
rotate(){...}
}
let planets = [
new Planet("Venus", 120),
new Planet("Mars", 80),
]
planets.sort(Planet.compare); //call the sort method of Arrays, using the static method from satelite to compare
console.log(planets[0].name); // cli: Mars
console.log(planets[0].place); // cli: Universelet myMixin = {
usefulFunc(){
console.log("Hello, I'm a useful func");
},
sayHW()
{
alert("Hello World");
}
}
class A{
constructor(name)
{ this.name = name; }
}
Object.assign(A.prototype, myMixin);
new A("testMixin").usefulFunc();const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42var hooks = {};
function add_to_function(name, func) {
if(!hooks[name]) hooks[name] = [];
hooks[name].push(func);
}
function call_my_function(name, ...params){
if(hooks[name])
hooks[name].forEach(func => func(...params));
}In this section we do not focus on binding data yet. Check the property section for this kind of information.
Binding consists of linking data in the <script> section of your component with the <template> section of the same component. In Vue.js the simpliest way to bind data is to use the {{ Mustache }} tag (two {, your data, then two }). While the component is rendered, the tag will be replaced with the content of the data used within the mustache.
Mustache can handle complex JavaScript operation too
Everything in the mustache tag will be interpreted! You cannot put html elements in there.
Nonetheless, mustache tag has some limitation, especially within the HTML attributes since they cannot be used. For example, you can't write <div id="{{myDynamicId}}">: this will throw an error. To circumvent this issue, Vue.js introduces directives which are special-interpreted HTML attributes.
The most important one is the v-bind directive. This directive allows to bind a standard HTML attribute element to a custom data. For example, you can bind your data with the id of an element using the v-binddirective.
There also exists dynamic binding, which allows you to use varibale to determine which HTML property you want to bind your data with. Check the documentation if your are interested.
Two way data binding allows a child component to update its direct parent. It is mostly used for forms. Check here for more information.
We will see in this section some handful syntaxex to define how your component should render according to its state (its data).
In your component template, you will often face the necessity to check if a variable exists in order to display specific information. For instance, you want to display user's information only if he/she is logged in your application, otherwise you don't have access to this information.
To do that, Vue.js introduce the v-if directive. It is used to conditionally render a block: the block will be rendered only if the expression value is computed to true. You also have the v-else-if and v-else directive, obviously.
A directive has to be attached to only one element. If you want to toggle more than one HTML element with you directive, you must use it on a <template> element, which serves as an invisible wrapper.
Another common needs is to dynamicaly render list of elements in a page. Vue.js introduces the v-for directive for addressing this need. It uses a special syntax item in items (if items is the array, item is an alias for the array element: it can be anything else). You can also retrieve the key/index of the element iterated with the special syntax (item, index) in items.
You can use v-for to render a list based on an array.
Here, a first <li> element will be rendered with the Foo message, and the second with the Bar message.
It is also possible to iterate over an object's properties with the same directive.
Here, the first <li> will display Name is: Soen, and so on.
Another important things for the v-for directive is about maintaining the state of your list up to date. Whenever possible, it is higly recommended by Vue.js assign a unique key to the alias element created (here item and prop) when possible (the value must be numeric or string). To do so:
When a Vue.js instance is created, it adds all the properties found in its data object to the reactivity system of the framework. When values of those properties change, the view will automatically “react”, updating itself to match the new values. This is a powerful feature that you should intensively use (it is somewhat a reimplementation of the observer pattern).
Each component has a data object. For every component but the main component Vue.vue, data must be a function, otherwise, the data will be shared accross the difference instances of the same component.
In the <script> element of your component, you should have:
Then, during using app, if you change the value of name, this change will reflect on the template of the component.
Lifecycle hooks are special functions which allow user to perform specifics operations at certain moment of the creation and the rendering of a component. For example, just before your component goes mounted to the page, you can modify the component's data.
Below a diagram of the lifecycle of a component and the associated hooks.

<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template><template>
{{ user.name }} <!--will print the attribute of the variable user -->
</template><template>
{{ user.getLevel() + user.increaseXP()) }}
</template><template>
<div v-bind:id="myDynamicId"></div>
<a v-bind:href="myDynaLink">linkmesenpai</a><!--or any other html attribute!-->
</template><template>
<p v-if="user">Hello {{ user.name }}</p> <!--if the user exists, then we have its name-->
<p v-else> Hey! You! Log you, Yeah! You!</p>
</template><ul>
<li v-for="myItem in items"> <!-- items: [{ message: Foo}, {message: Bar}]-->
{{ myItem.message }}
</li>
</ul><ul id="v-for-object">
<li v-for="(prop, key) in myobject"> <!-- myObject { name: "Soen", level: "3Dan", xp: 150,}-->
{{key}} is: {{ prop }}
</li>
</ul><li v-for="item in items" v-bind:key="item.id"> <!--we know that .id is unique across all the element of your array, we can use it as a key -->data(){ // the data, declared as function
return{ // we return all the properties that should be react on.
name: "Yo!",
value: 15,
}
},data(){
return{
value : -1;
}
}
mounted: function(){
console.log("Component mounted!");
value = DEFAULT_MOUNT_VALUE;
}

