Quick refresher on JavaScript’s objects, prototypes and inheritance


Here is how we commonly code JavaScript’s objects, prototypes and inheritance.  You can copy the JavaScript code below and quickly run it on any online JavaScript compiler/runner app on the Internet.  I use JS Bin.

// If we don't need to create/instantiate objects, then an object literal will do
console.log("*****Object Literal*****");
var EmployeeMe = {
  FullName: "Rodan Sotto",
  HireDate: "12/1/2015",
  Save: function(){
    console.log("Employee saved: " + this.FullName + ", " + this.HireDate.toString());
  }
}

EmployeeMe.Save(); // displays "Employee saved: Rodan Sotto, 12/1/2015"

console.log(EmployeeMe); // displays the object literal itself
console.log(Object.getPrototypeOf(EmployeeMe)); // displays the object literal's prototype which is Object


// Otherwise, we would use a constructor function to define the properties of the class
console.log("*****Constructor Function*****");
var Employee = function(fullName, hireDate){
  this.FullName = fullName;
  this.HireDate = hireDate;
}

// ... and on the constructor's prototype property to define the methods of the class
// We actually can define the methods inside the constructor but it's common practice
//  to define them on the prototype to get the maximum benefit of the prototypal inheritance
Employee.prototype.Save = function(){
    console.log("Employee saved: " + this.FullName + ", " + this.HireDate.toString());  
}

var e = new Employee("Rodan Sotto", "12/1/2015");
e.Save(); // displays "Employee saved: Rodan Sotto, 12/1/2015"

console.log(Employee); // displays the Employee constructor
console.log(Employee.prototype); // displays an object containing the Save() method
console.log(Employee.prototype.constructor); // displays the original constructor (e.g. the Employee constructor)
console.log(Object.getPrototypeOf(e)); // displays the Employee prototype
console.log(Object.getPrototypeOf(Object.getPrototypeOf(e))); // displays Object


// To inherit from Employee, the following is the common pattern used
// Notice the call to Employee.call(), this calls the Employee constructor but runs it in the context of the Manager by passing "this"
console.log("*****Inheritance*****");
var Manager = function(fullName, hireDate, companyShares){
  Employee.call(this, fullName, hireDate);
  this.CompanyShares = companyShares;
}

// The next statement is needed to allow Manager to inherit properties and methods defined on the Employee constructor's prototype
Manager.prototype = Object.create(Employee.prototype);

// Because of the previous statement, the Manager constructor's prototype's constructor is set to the Employee constructor
//  and we do not want that, so we need to fix this to point to the Manager constructor
Manager.prototype.constructor = Manager;

var m = new Manager("John Smith", "1/1/2000", 1000);
m.Save();
console.log(Manager); // displays the Manager constructor
console.log(Manager.prototype); // displays an object containing the constructor property and the inherited Save() method
console.log(Manager.prototype.constructor); // displays the Manager constructor
console.log(Object.getPrototypeOf(m)); // displays the Manager prototype
console.log(Object.getPrototypeOf(Object.getPrototypeOf(m))); // displays Employee prototype
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(m)))); // displays Object

// As we can see in the last three statements how Manager inherits Employee
//  and the Employee inherits from Object by traversing the prototype chain

Advertisements

TypeScript Notes: Part 2


Part 2 is all about classes, interfaces, abstract classes, and inheritance in TypeScript.  It’s similar to OOP in C#.  So easy to grasp and use that one might totally forget how OOP in JavaScript works.  Same as in TypeScript Notes: Part 1, I will present the TypeScript code and the generated JavaScript code.  The generated JavaScript code might be overwhelming to understand at first but as long as your knowledge with JavaScript objects is still intact, you should be able to figure it out.  For a refresher, read MDN’s Introducing JavaScript objects.

// TypeScript Notes: Part 2


// Classes, access modifiers, properties, constructor
class Employee {
    FullName: string;
    public HireDate: Date; // this is a Javascript Date object
    private Salary: number;
    protected HomeAddress: string;

    // properties / accessors
    private _position: string;
    get Position(): string {
        return this._position;
    }
    set Position(position: string) {
        this._position = position;
    }

    // constructor
    constructor() {
        console.log("Employee object created");
    }

    Save(): void {
        console.log("Employee saved: " + this.FullName + ", " + this.HireDate.toLocaleDateString());
    }
}

let e: Employee = new Employee(); // displays "Employee object created"
e.FullName = "Rodan Sotto";
e.HireDate = new Date("12/1/2015");
e.Save(); // displays "Employee saved: Rodan Sotto, 12/1/2015"

e.Salary = 0; // compile-time error because e.Salary is declared private; default access modifier is public
console.log("Salary set to " + e.Salary);

e.HomeAddress = "Mississauga, ON"; // compile-time error because e.HomeAddress is protected
console.log("Home address set to " + e.HomeAddress);

e.Position = "Senior Software Developer";
console.log("Position set to " + e.Position); // displays "Position set to Senior Software Developer"
// Note: To support properties / accessors, at minimum, ES5 is required


// Using shorthand properties to initialize properties at construction
class Employer {
    // specifying access modifier before constructor parameter makes it a property
    // in the example below, Name and Address are properties while misc is not
    constructor(public Name: string, public Address: string, misc: string) {
    }
}



let er: Employer = new Employer("Acme Company", "Ontario, Canada", "xyz");
console.log("Employer: " + er.Name + ", " + er.Address); // displays "Employer: Acme Company, Ontario, Canada"


// Inheritance, protected variables in derived classes
class Manager extends Employee {
    constructor(public CompanyShares: number, address: string) {
        super(); // required call for derived classes
        this.HomeAddress = address; // protected variable is accessible to derived classes
    }

    // method to return the protected variable HomeAddress
    GetHomeAddress(): string {
        return this.HomeAddress;
    }
}






let m: Manager = new Manager(1000, "Toronto, ON"); // displays "Employee object created"
m.FullName = "John Smith";
m.HireDate = new Date("1/1/2000");
m.Position = "Development Manager";
m.Save(); // displays "Employee saved: John Smith, 1/1/2000"
console.log("Company shares set to " + m.CompanyShares); // displays "Company shares set to 1000"
console.log("Home address set to " + m.GetHomeAddress()); // displays "Home address set to Toronto, ON"


// Template strings
// To use, enclose your template string with the tick symbol (`)
//  and enclose the variables in ${} notation
console.log(`Manager ${m.FullName} is hired ${m.HireDate.toLocaleDateString()} as a ${m.Position} and he lives in ${m.GetHomeAddress()}`);
// displays "Manager John Smith is hired ?1?/?1?/?2000 as a Development Manager and he lives in Toronto, ON"


// Interfaces
interface ICanSing {
    Sing(): void;
}

interface ICanDance {
    Dance(): void;
}

class Person implements ICanSing, ICanDance {
    constructor(public Name: string) {
    }

    Sing(): void {
        console.log(`${this.Name} can sing!`);
    }

    Dance(): void {
        console.log(`${this.Name} can dance!`);
    }
}




let j: Person = new Person("Jane");
j.Sing(); // displays "Jane can sing!"
j.Dance(); // displays "Jane can dance!"


// Abstract classes
// In an abstract class you can have partial implementation while in an interface you cannot
// Plus you cannot extend more than one abstract class while you can implement more than one interface
abstract class AbstractPerson {
    ShowAbilities(): void {
        if (this.CanSing) this.Sing();
        if (this.CanDance) this.Dance();
    }

    CanSing: boolean;
    CanDance: boolean;
    abstract Sing(): void;
    abstract Dance(): void;
}



class AnotherPerson extends AbstractPerson {
    constructor(public Name: string) {
        super();
    }

    Sing(): void {
        console.log(`${this.Name} can sing!`);
    }

    Dance(): void {
        console.log(`${this.Name} can dance!`);
    }
}







let k = new AnotherPerson("Kane");
k.CanSing = true;
k.CanDance = false;
k.ShowAbilities();

// Generated JavaScript Code From TypeScript Notes: Part 2


// Classes, access modifiers, properties, constructor
var Employee = /** @class */ (function () {
    // constructor
    function Employee() {
        console.log("Employee object created");
    }
    
	Object.defineProperty(Employee.prototype, "Position", {
        get: function () {
            return this._position;
        },
        set: function (position) {
            this._position = position;
        },
        enumerable: true,
        configurable: true
    });
    
	Employee.prototype.Save = function () {
        console.log("Employee saved: " + this.FullName + ", " + this.HireDate.toLocaleDateString());
    };
    
	return Employee;
}());


var e = new Employee(); // displays "Employee object created"
e.FullName = "Rodan Sotto";
e.HireDate = new Date("12/1/2015");
e.Save(); // displays "Employee saved: Rodan Sotto, 12/1/2015"

e.Salary = 0;
console.log("Salary set to " + e.Salary);

e.HomeAddress = "Mississauga, ON";
console.log("Home address set to " + e.HomeAddress);

e.Position = "Senior Software Developer";
console.log("Position set to " + e.Position); // displays "Position set to Senior Software Developer"



// Using shorthand properties to initialize properties at construction
var Employer = /** @class */ (function () {
    function Employer(Name, Address, misc) {
        this.Name = Name;
        this.Address = Address;
    }
    
	return Employer;
}());

var er = new Employer("Acme Company", "Ontario, Canada", "xyz");
console.log("Employer: " + er.Name + ", " + er.Address); // displays "Employer: Acme Company, Ontario, Canada"


// Inheritance, protected variables in derived classes
var Manager = /** @class */ (function (_super) {
    __extends(Manager, _super);
    
	function Manager(CompanyShares, address) {
        var _this = _super.call(this) || this;
        _this.CompanyShares = CompanyShares;
        _this.HomeAddress = address;
        return _this;
    }
    
    Manager.prototype.GetHomeAddress = function () {
        return this.HomeAddress;
    };
    
	return Manager;
}(Employee));

var m = new Manager(1000, "Toronto, ON"); // displays "Employee object created"
m.FullName = "John Smith";
m.HireDate = new Date("1/1/2000");
m.Position = "Development Manager";
m.Save(); // displays "Employee saved: John Smith, 1/1/2000"
console.log("Company shares set to " + m.CompanyShares); // displays "Company shares set to 1000"
console.log("Home address set to " + m.GetHomeAddress()); // displays "Home address set to Toronto, ON"


// Template strings


console.log("Manager " + m.FullName + " is hired " + m.HireDate.toLocaleDateString() + " as a " + m.Position + " and he lives in " + m.GetHomeAddress());



// Interfaces








var Person = /** @class */ (function () {
    function Person(Name) {
        this.Name = Name;
    }
    
	Person.prototype.Sing = function () {
        console.log(this.Name + " can sing!");
    };
    
	Person.prototype.Dance = function () {
        console.log(this.Name + " can dance!");
    };
    
	return Person;
}());

var j = new Person("Jane");
j.Sing(); // displays "Jane can sing!"
j.Dance(); // displays "Jane can dance!"


// Abstract classes


var AbstractPerson = /** @class */ (function () {
    function AbstractPerson() {
    }

    AbstractPerson.prototype.ShowAbilities = function () {
        if (this.CanSing)
            this.Sing();
        if (this.CanDance)
            this.Dance();
    };

    return AbstractPerson;
}());

var AnotherPerson = /** @class */ (function (_super) {
    __extends(AnotherPerson, _super);
    
	function AnotherPerson(Name) {
        var _this = _super.call(this) || this;
        _this.Name = Name;
        return _this;
    }
    
	AnotherPerson.prototype.Sing = function () {
        console.log(this.Name + " can sing!");
    };
    
	AnotherPerson.prototype.Dance = function () {
        console.log(this.Name + " can dance!");
    };
    
	return AnotherPerson;
}(AbstractPerson));

var k = new AnotherPerson("Kane");
k.CanSing = true;
k.CanDance = false;
k.ShowAbilities();


// This is the __extends code used to implement classes extending another class or abstract class in Typescript
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    
	return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();

TypeScript Notes: Part 1


I decided to post a series of notes on TypeScript and this is Part 1.  I think understanding what TypeScript does makes you a better JavaScript programmer as you will come to know the issues inherent in JavaScript.  The format I will be using is to present the TypeScript code and explain it along the way in the comments itself and then present the generated JavaScript code.  You can play with the code by copying it and pasting it on any online TypeScript compiler/runner app.  I recommend Playground TypeScript.  So let’s get to it and no more dilly dally.

// TypeScript Notes: Part 1

// Using var
// Works almost the same way as using var in Javascript
var myDeclaredVar = "Rodan Sotto";
console.log(myDeclaredVar); // displays "Rodan Sotto"
//console.log(myUndeclaredVar); // compile-time error; in JavaScript it's a runtime error
console.log(myHoistedVar); // displays "undefined"; no error because all JavaScript var declarations anywhere in the code are moved up and made available from line 1 (concept called hoisting)
var myHoistedVar = 5;

var myNoBlockLevelScopingVar = 5;
if (myNoBlockLevelScopingVar > 2) {
    var myNoBlockLevelScopingVar = 6;
    console.log(myNoBlockLevelScopingVar); // displays 6 as expected
}
console.log(myNoBlockLevelScopingVar); // displays 6 as well because JavaScript var declarations don't have block level scoping


// Using let
// This solves issues with variable hoisting and no block level scoping
let myLetVar = "Rodan Sotto";
console.log(myLetVar);
console.log(myNotHoistedLetVar); // compile-time error because let does not allow hoisting variables
let myNotHoistedLetVar;

let myBlockLevelScopingLetVar = 5;
if (myBlockLevelScopingLetVar > 2) {
    let myBlockLevelScopingLetVar = 6;
    console.log(myBlockLevelScopingLetVar); // displays 6 as expected
}
console.log(myBlockLevelScopingLetVar) // displays 5 because let allows block level scoping (check the generated JavaScript code how it does this)


// Using const
const myConst = 5;
myConst = 6; // compile-time error because const does not allow changing the values of constant or read-only variables


// Data types: number, string, and boolean
let n: number = 123;
let s: string = "ABC";
let b: boolean = true;
n = "DEF"; // compile-time error because TypeScript is type safe
s = 456; // compile-time error
b = "GHI"; // compile-time error

let myTypeInferedVar = 1;
myTypeInferedVar = "A"; // compile-time error because TypeScript has type inference that decides the type of datatype-less variables based on first assignment

let myNotTypeInferedVar; // notice that there is no initialization here
myNotTypeInferedVar = 1;
console.log(myNotTypeInferedVar); // displays 1
myNotTypeInferedVar = "A";
console.log(myNotTypeInferedVar); // displays "A"; no compile-time error because varialbles with no data type specified is by default has an implicit datatype of any

// Data type any
// This is default datatype for datatype-less variables
// Use it when it is a must because it is not a best practice always.
let myAnyTypeVar: any;
myAnyTypeVar = 1;
console.log(myAnyTypeVar); // displays 1
myAnyTypeVar = "A";
console.log(myAnyTypeVar); // displays "A"


// Generic arrays
// Just like the C# generic collection
let myNumberArray: Array<number> = new Array<number>();
myNumberArray.push(1);
myNumberArray.push(2);
myNumberArray.push("C"); // compile-time error


// Functions in TypeScript ...
// ... forces you to return
function myNumberFunction(): number {
    return 1; // without this return statement will produce compile-time error
}

// but following function declarations will not force you to return
function myVoidFunction(): void { } // you cannot have return statement here
// or
function myAnyFunction(): any { } // you can have return statement here
// or
function myFunction() { } // by default the return type is any

// ... has parameter checking
function myFunctionWithParams(x: number, y: number): void {
    console.log(x + y);
}
myFunctionWithParams(1, 2);
myFunctionWithParams(1, 2, 3); // compile-time error

// ... does not allow duplicate function names regardless if parameters are different
function myDuplicateFunction(x: number, y: number): void { }
function myDuplicateFunction(x: number, s: string, b: boolean): void { } // compile-time error

// ... has optional parameters
function myFunctionWithOptionalParams(x: number, y?: number): void {
    console.log(x);
    console.log(y);
}
myFunctionWithOptionalParams(1, 2); // displays 1 and 2
myFunctionWithOptionalParams(1); // displays 1 and "undefined"

// ... hs rest parameter which allows defining function with array as parameters
function myFunctionWithRestParam(...x: Array<number>): void {
    for (let e of x) {
        console.log(e);
    }
}





myFunctionWithRestParam(1, 2); // displays 1 and 2
myFunctionWithRestParam(3, 4, 5); // displays 3, 4, and 5
myFunctionWithRestParam(6, 7, 8, 9, 0); // displays 6, 7, 8, 9, and 0

// Generated JavaScript Code From TypeScript Notes: Part 1



var myDeclaredVar = "Rodan Sotto";
console.log(myDeclaredVar); // displays "Rodan Sotto"
//console.log(myUndeclaredVar); // runtime error
console.log(myHoistedVar); // displays "undefined"
var myHoistedVar = 5;

var myNoBlockLevelScopingVar = 5;
if (myNoBlockLevelScopingVar > 2) {
    var myNoBlockLevelScopingVar = 6;
    console.log(myNoBlockLevelScopingVar); // displays 6 as expected
}
console.log(myNoBlockLevelScopingVar); // displays 6 as well




var myLetVar = "Rodan Sotto";
console.log(myLetVar);
console.log(myNotHoistedLetVar);
var myNotHoistedLetVar;

var myBlockLevelScopingLetVar = 5;
if (myBlockLevelScopingLetVar > 2) {
    var myBlockLevelScopingLetVar_1 = 6;
    console.log(myBlockLevelScopingLetVar_1); // displays 6 as expected
}
console.log(myBlockLevelScopingLetVar); // displays 5



var myConst = 5;
myConst = 6;


// Data types: number, string, and boolean
var n = 123;
var s = "ABC";
var b = true;
n = "DEF";
s = 456;
b = "GHI";

var myTypeInferedVar = 1;
myTypeInferedVar = "A";

var myNotTypeInferedVar;
myNotTypeInferedVar = 1;
console.log(myNotTypeInferedVar); // displays 1
myNotTypeInferedVar = "A";
console.log(myNotTypeInferedVar); // displays "A"




var myAnyTypeVar;
myAnyTypeVar = 1;
console.log(myAnyTypeVar); // displays 1
myAnyTypeVar = "A";
console.log(myAnyTypeVar); // displays "A"




var myNumberArray = new Array();
myNumberArray.push(1);
myNumberArray.push(2);
myNumberArray.push("C");




function myNumberFunction() {
    return 1;
}


function myVoidFunction() { }

function myAnyFunction() { }

function myFunction() { }


function myFunctionWithParams(x, y) {
    console.log(x + y);
}
myFunctionWithParams(1, 2);
myFunctionWithParams(1, 2, 3);


function myDuplicateFunction(x, y) { }
function myDuplicateFunction(x, s, b) { }


function myFunctionWithOptionalParams(x, y) {
    console.log(x);
    console.log(y);
}
myFunctionWithOptionalParams(1, 2); // displays 1 and 2
myFunctionWithOptionalParams(1); // displays 1 and "undefined"


function myFunctionWithRestParam() {
    var x = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        x[_i - 0] = arguments[_i];
    }
    for (var _a = 0, x_1 = x; _a < x_1.length; _a++) {
        var e = x_1[_a];
        console.log(e);
    }
}
myFunctionWithRestParam(1, 2); // displays 1 and 2
myFunctionWithRestParam(3, 4, 5); // displays 3, 4, and 5
myFunctionWithRestParam(6, 7, 8, 9, 0); // displays 6, 7, 8, 9, and 0

JavaScript: You think you know it well?

Just because you are a C# or Java developer that you think you know JavaScript well.  Well I don’t.  But no worries, below are some quick pointers to remember:

  • null and undefined are types, just like Numbers, Strings, Booleans, and Objects.  null indicates a deliberate non-value while undefined indicates an uninitialized value.
  • Primitive/literal values (null, undefined, “string”, 10, true, false) are converted to objects (wrapper objects) when properties are accessed.
  • Functions and Arrays are special types of objects.
  • Built in Error types are there as well.
  • Object(), Array(), String(), Number(), Boolean(), Function(), Date(), RegExp(), and Error() are native constructor functions.
  • parseInt() and parseFloat() parse the number in string until it reaches an invalid character.
  • Unary + operator converts values to numbers (+ “42” = 42 ) and returns NaN (Not a Number) if non-numeric.
  • isNaN() tests for NaN.
  • isFinite() tests for Infinity (1/0), -Infinity (-1/0), and NaN.
  • false, 0, empty string (“” ), NaN, null, and undefined convert to false, and all others convert to true.
  • Blocks do not have scope, only functions have scope.
  • “3” + 4 + 5 = 345, while 3 + 4 + “5” = 75.
  • Triple-equals operator avoids type coercion.  1 === true is false, but true === true is true.
  • JavaScript objects are simple collections of name-value pairs where the name is a JavaScript string and the value is any JavaScript value.
  • array.length isn’t necessarily the number of items in the array.  It is one more than the highest index.
  • No return statement or empty return with no value in a function returns undefined.
  • arguments variable contains all the values passed to the function.
  • IIFEs (Immediately Invoked Function Expressions) is basically what it says.  It’s a function in an expression and invoked immediately ( (function () { … })();  )
  • To call functions recursively, you can use a named IIFE ( (function myFunc() { myFunc(); })();  ).  The name is only available to the function’s own scope.
  • this inside a function refers to the current object if the function is called against an object or using dot notation or bracket notation; otherwise it will refer to the global object.
  • Global object or the head object in JavaScript in a web browser environment is the window object.  Variables you declare globally in your JavaScript code will become properties of the window object.
  • JavaScript does not have classes; it only has object prototypes. It uses functions as classes.  You declare the properties inside the function and declare the methods by assigning them to the function object’s prototype.
  • prototype is an object shared by all instances of the object.  It forms part of a lookup chain, which has a special name called prototype chain.  Anything assigned to the object’s prototype becomes available to all instances of the object.
  • Inner or nested functions can access variables in their parent function’s scope.
  • Closure happens when an outer function returns the inner function and the inner function needs access to the outer function’s local variables.  The outer function’s scope object is actually retained even after the outer function has returned.  Only when there are no more references to the inner function will the outer function’s scope object be garbage collected.
  • Scope objects form a chain called the scope chain.  Scope object is created every time the function starts executing.

JavaScript: Attaching/Detaching Event, OnLoad vs. DOMContentLoaded, Manipulating DOM and CSS

Event Handling, Attaching and Detaching Events

3 phases of event dispatch:

  • Capturing – going down the DOM tree until it reaches the target element
  • Target
  • Bubbling – going back up the DOM tree from the target element

 

// standard way of accessing the Event object
var eventHandlerDOM = function(evt) {
alert(evt.type); //displays click
}

// starting IE 9 you can use the standard way
var eventHandlerIE8Older = function() {
var evt = window.event;
alert(evt.type);
}

// cross-browser way
var eventHandlerCB = function(evt) {
if (!evt) evt = window.event;
alert(evt.type);
}

window.onload = function() {
var btn = document.getElementById("btn");

// 2 ways of attaching an event
btn.onclick = eventHandlerCB;
// or ...
if (btn.addEventListener) {
btn.addEventListener("click", eventHandlerCB, false);
}
else {
// starting IE 9, you can use the standard way using
// addEventListener
btn.attachEvent("onclick", eventHandlerCB);
}

alert("events attached");
alert("now detaching events...");
detachEvents();
alert("events detached");
}

// detaching events
var detachEvents = function() {
if (btn.removeEventListener) {
btn.removeEventListener("click", eventHandlerCB, false);
}
else {
// starting IE 9, you can use the standard way using
// removeEventListener
btn.detachEvent("onclick", eventHandlerCB);
}
}

 

window.onload Event vs. document.DOMContentLoaded event

The problem with running script on window.onload event is that if you have a rather large image to download, your script will run only after the image is downloaded.  window.onload event is triggered after everything, including external stylesheets, javascript files and images, has been downloaded.  An alternative, and usually a best practice, is to run your script on document.DOMContentLoaded event.

var readyFunc = function() {
var stat = document.getElementById("statDOMReady");
stat.innerHTML = "DOM is ready!!!";
}

document.addEventListener("DOMContentLoaded", readyFunc, false);

 

Note that document.DOMContentLoaded event is an HTML5 specification.  Also if your script needs to work with CSS, you need to put all your external stylesheets in the header and all your external scripts in the footer so all the styles will be loaded before your scripts are run.

 

Manipulating DOM

A sample of what you can do for manipulating DOM:

  • document.createElement() – create an Element node
  • document.createTextNode() –  create a Text node
  • element.cloneNode() – create a copy of a node and its attributes with option to include the descendants as well
  • element.appendChild() – add a new child node as the last child node
  • element.insertBefore() – insert a new child node before a specified child node
  • element.removeChild() – remove a child node
  • element.replaceChild() – replace a child node
  • document.createDocumentFragment() – create an imaginary Node object; useful for adding content to your document, or extracting parts of your document and modifying it and inserting it back

 

Manipulating CSS

2 ways to import external stylesheets:

<!-- using <style> tag and @import -->
<style type="text/css">
@import "myStylesheet.css";
</style>

<!-- using <link> tag and rel="stylesheet" -->
<link type="text/css" href="myStylesheet.css" rel="stylesheet" />


 

Persistent, preferred, and alternate stylesheets:

<!-- persistent stylesheet -->
<link type="text/css" href="main.css" rel="stylesheet" />

<!-- preferred stylesheet -->
<link type="text/css" href="dflt.css" rel="stylesheet" title="Default" />

<!-- alternate stylesheet -->
<link type="text/css" href="alt1.css" rel="alternate stylesheet"
title="Alternate 1" />

 

element.style, window.getComputedSyle(), element.currentStyle, elements positioning properties:

var p1 = document.getElementById("p1");
p1.style.fontSize = "20px";

// standard way of getting the computed style
var computedStyle = window.getComputedStyle(p1, null);
alert(computedStyle.fontSize); // displays 20px

// IE way of getting the computed syle
// starting from IE9, you can use the standard way
var computedStyle2 = p1.currentStyle;
alert(computedStyle2.fontSize); // displays 20px

// cross-browser code for getting the computed style
if ( !("getComputedStyle" in window) ) {
alert("getComputedStyle does not exist")
window.getComputedStyle = function(element) {
return element.currentStyle;
}
}

// positioning properties of an element you can use
alert(p1.offsetTop); // displays 130
alert(p1.offsetLeft); // displays 8
alert(p1.offsetHeight); // displays 23
alert(p1.offsetWidth); // displays 911
// below will display 0, because it's parent is the body tag
alert(p1.offsetParent.offsetTop);
var body = document.getElementsByTagName("body")[0];
alert(body.offsetTop); // displays 0