Javascript
- The language of the web, for HTML, for servers, PCs, laptops, tablets, cell phones, and more.
- Very widely used, and growing, very common to use JavaScript to manipulate the HTML DOM.
- Developed by Brendan Eich at Netscape in 10 days as a scripting language for Netscape Navigator 2 (more on that later..)
- Related to Java in name only
- JS Style guide by AirBNB- https://github.com/airbnb/javascript
Primitive Datatypes
-
Number
- 64-bit floating point, similar to Java double and Double
- No integer type
- Special values NaN (not a number) and Infinity
-
String
- Sequence of zero or more Unicode characters
- No separate character type (just strings of length 1)
- Literal strings using ' or " characters (must match)
-
Special values
- null and undefined
- typeof(null) = object; typeof(undefined)=undefined
- Boolean
- Two values: true and false
-
Empty strings, undefined, null and 0 are all treated as false
Variables
- No type specified, can be changed dynamically
- Variables with no value have undefined value
- Always use var, otherwise the variable is defined on the global scope
- It's a good practice to define variables at the beginning of a function
var pi = 3.14; // pi is a Number
var person = "John Doe"; // person is a string
var answer = 'Yes I am!'; // Different quotes, answer is a
//string as well
console.log(typeof answer); // string
answer = 10; // answer is now a number
console.log(typeof answer); // number
var a; // a is undefined
globalVariable = 'i am a global variable';
// one statement, many variables
var lastname = "Doe", age = 30, job = "carpenter";
var lastname; console.log(lastname); // still contains "Doe"
Flow control
- If... else
if (time < 10) {
x = "Good morning";
}
else if (time < 20) {
x = "Good day";
}
else {
x = "Good evening";
}
- Switch
var day = new Date().getDay();
switch (day) {
case 6:
x = "Today is Saturday";
break;
case 0:
x = "Today is Sunday";
break;
default:
x = "Looking forward to the Weekend";
}
If What?
- var a = ...;
- if (a) - ?
if (a) - will evaluate to true if (a) isn't undefined, null, or NOT false.
- Check if a is actually false:
- WHAT?! === and !== ?
- One liner check and assignment:
a = a || 'hello'; // leave a as is, or set it to 'hello' if it // evaluates to false
if (a === false)
(a === b) - makes sure that a and b are of the same type. Will return false immediately if a and b aren't of the same type. Have better performance then ==.
Loops
- for
var numbers = [1, 2, 3], sum = 0;
for (var i = 0; i < numbers.length; i++) { sum += numbers[i]; } console.log(sum); // 6
-
for.. in (iterate through object keys)
var txt = "";
var person = { fname: "John", lname: "Doe", age: 25 };
for (var x in person) {
txt = txt + person[x];
}
console.log(txt); // JohnDoe25
- While
var i = 0, x = 0;
while (i < 5) { x = x + i; i++; }
Loops- break / continue
for (var i = 0; i <= 5; i++) { if (i == 3) continue; console.log(i); // 0, 2, 2, 4, 5 }
for (var i = 0; i <= 5; i++) { if (i == 3) break; console.log(i); // 0, 1, 2 }
Loops - JavaScript style
- forEach:
var numbers = [1, 2, 3], sum = 0;
numbers.forEach(function(item) {
sum += item;
});
console.log(sum); // 6
- forEach:
var numbers = [1, 2, 3], sum = 0;
numbers.forEach(function(item) {
sum += item;
}); console.log(sum); // 6
Exceptions
- Errors will happen
- When the JavaScript engine is executing JavaScript code, different errors can occur:
- It can be syntax errors, typically coding errors or typos made by the programmer.
-
It can be misspelled or missing features in the language (maybe due to browser differences).
-
It can be errors due to wrong input, from a user, or from an Internet server.
- And, of course, it can be many other unforeseeable things.
Try.. Catch.. Throw
- Can throw any object as an error
function div(x, y) {
try {
if (!x && !y) throw 'please provide x and y';
if (y === 0) throw 'can not divide by 0';
console.log(x/y);
}
catch(err) {
console.log('error:', err);
}
}
div(10, 2); // 5
div(); // error: please provide x and y
div(10, 0); // error: can not divide by 0
Object == DICTIONARY
- Every object in JS is basically a dictionary
- Entries can be of any of the main types (object, array, function) or any of the basic types (String, Number, Date, RegExp)
-
Keys are strings (or numbers)
-
Entries can be added (or removed) dynamically at any time
Defining an object
- Everything non primitive is an object- array , function, ...
-
Properties are values associated with objects
-
Methods are actions that objects can perform
-
objects are data (variables), with properties and methods
- Objects can be modified with new properties any time
var person = new Object(); // can also be: var person= {}; person.firstname = "Ami"; person.lastname = "Turgman"; person.age = 37; person.eyescolor = 'brown';
var anotherPerson = { firstname: 'John', lastname: 'Doe' }; anotherPerson.age = 50; // dot notation anotherPerson['eyescolor'] = 'blue'; // key notation
console.log(person, anotherPerson);
delete person.age;
console.log(person.age); // will print 'undefined'
A function member
var anotherPerson = {
firstname: 'John', lastname: 'Doe', getFullName: function () { return this.firstname + ' ' + this.lastname; } }; console.log(anotherPerson.getFullName()); // John Doe
-
this represents the current object the method is running on.
- In most cases, this points to the object which has the function as a property.
-
this is resolved dynamically when the method is executed
- this can be changed explicitely using the call/apply object functions
console.log(anotherPerson.getFullName.call(person));
- The object person does not have the getFullName method
- We can invoke any function on any object
Array == List
- Arrays are just dynamic lists. They serve as a powerful container. Basic functionality of list, queue and stack.
- Prefer using the [ ] notation to the new Array() directive.
var a = [], b = new Array(); // both equivalent
a[0] = 0, a[1] = 1, a[3] = 3; console.log(a.join(',')); // 0,1,,3 b.push(1, 'a', null, undefined, true); console.log(b); // [1, "a", null, undefined, true]
- Array API: push, pop, shift, unshift, splice and slice
Functions
- Always returns a value
- undefined is used if returned value was not provided
-
Basic types passed by value, objects by reference
- Can have any number of parameters
- Caller can call the function with any number of arguments
- Missing arguments will have the value undefined
- Extra arguments will be ignored
function myFunc(a, b) {
console.log(a, b);
}
var result = myFunc(1, 2); // 1 2
console.log(result); // undefined
myFunc('a'); // b undefined
- myFunc is a named function and can be invoked by calling it
Functions returning function
- Functions can be returned from other functions and be stored in variables
function getAdder(sum) {
sum = sum || 0;
return function (num) {
sum += num;
return sum;
}
}
var adderFunc = getAdder(100);
console.log(adderFunc(1)); // 101
console.log(adderFunc(2)); // 103
console.log(adderFunc(3)); // 106
- The internal adder function is an anonymous function
- anonymous functions are usually used as callbacks
setTimeout(function(){ console.log('time expired'); }, 100);
- Even though the adder function is being called from outside of the getAdder() function, it still has access to the sum variable.
- this is called closure
Closures
- Inner functions have access to variables in the outer function.
- Accessing variables outside of your immediate lexical scope creates a closure.
- A closure is the local variables for a function- kept alive after the function has returned, or a closure is a stack-frame which is not deallocated when the function returns
function sayHello(name) {
var text = 'hello ' + name; return function () { console.log(text); } } var sayHelloFunc = sayHello('ami'); sayHelloFunc(); // hello ami
function say100() {
// Local variable that ends up within closure
var num = 100;
var logNum = function() { console.log(num); }
num++;
return logNum;
}
var logNumFunc = say100();
logNumFunc(); // 101
Closures- cont
- Be careful when passing references to objects
- You might get unexpected behavior when the objects values are changed
function foo(x) {
var tmp = 2; return function (y) { console.log(x.val + y + tmp); } } var obj = { val: 10 }; var bar = foo(obj); // bar is now a closure referencing obj. bar(3); // 15 obj.val = 20; bar(3); // 25
Self invoking functions
-
A function can be declared and execute itself
- (function(params) { function body } )(variables);
var u = { a: 1, b: 2 };
var v = { a: 3, b: 4 }; console.log(u, v); // {a: 1, b: 2} {a: 3, b: 4} (function (x, y) { var tempA = x.a, tempB = x.b; //local variables x.a = y.a; x.b = y.b; y.a = tempA; y.b = tempB; })(u, v); console.log(u, v); // {a: 3, b: 4} {a: 1, b: 2}
// This works because objects are passed by reference
Scope
- The environment where variable are contained
- Scope chain - the current scope plus all parent scopes
- A variable that was set in a function without defining it previously will be defined in the global scope
- Outside of a function body the scope is the global scope, in the browser this usually means 'window'
var externalVar = 'external';
function myFunc() { var myFuncVar = 'myFunc'; function internalFunction() { var internalVar = 'internal'; console.log(externalVar, myFuncVar, internalVar, globalVar); } globalVar = 'global'; internalFunction(); // external myFunc internal global } myFunc(); console.log(globalVar); // global console.log(myFuncVar); // myFuncVar is not defined console.log(internalVar); // internalVar is not defined
The arguments argument
- Each function is passed an arguments object
- The arguments object is an array-like object containing all the parameters that were passed to the function
- Used usually when there is a variable number of parameters that can be passed to a function
function sumAll() {
var total = 0; for (var i = 0; i < arguments.length; i++) total += sumAll.arguments[i]; return total; } console.log(sumAll(1, 2, 3, 4, 5)); // 15
The this arugment
- Each function is passed a reference to this.
- It will contain a reference to the object that is holding the function.
- In case function isn't called "on" an object - behavior might be weird, better use the "this insanceof ..." pardigm. (more on that later)
function getName() {
return this.name;
}
var o = {name : 'Nadav'};
o.getName = getName;
o.getName(); // returns Nadav;
getName(); // hmmm? - this == global
- Each function is passed a reference to this.
- It will contain a reference to the object that is holding the function.
- In case function isn't called "on" an object - behavior might be weird, better use the "this insanceof ..." pardigm. (more on that later)
function getName() {
return this.name;
} var o = {name : 'Nadav'};
o.getName = getName;
o.getName(); // returns Nadav;
getName(); // hmmm? - this == global
Varialbe number of params
- It is a common design to send a single object with the parameters value
- Can be changed dynamically without changing the API
function doWebRequest(options) {
var scheme = options.scheme || 'http'; var port = options.port || 80; var url = scheme + '://' + options.host + ':' + port + options.path; console.log('calling', url); } doWebRequest({ host: 'microsoft.com', path: '/js' }); doWebRequest({ scheme: 'https', port: 441, host: 'microsoft.com', path: '/js' });
// calling http://microsoft.com:80/js // calling https://microsoft.com:441/js
Function as a class - prototypes
- Using the new keyword to create an instance of a class
- The convention is to Capitalize constructor names
- This is called a "prototype"
function Person(name, age) {
this.name = name;
this.age = age;
this.getDetails = function () { return this.name
+ ', ' + this.age;
};
}
var p1 = new Person('nadav', 29);
var p2 = new Person('guy', 28);
console.log(p1.getDetails()); // nadav, 37
console.log(p2.getDetails()); // guy, 28
- Using the new keyword to create an instance of a class
- The convention is to Capitalize constructor names
- This is called a "prototype"
function Person(name, age) {
this.name = name; this.age = age; this.getDetails = function () { return this.name + ', ' + this.age; }; } var p1 = new Person('nadav', 29); var p2 = new Person('guy', 28); console.log(p1.getDetails()); // nadav, 37 console.log(p2.getDetails()); // guy, 28
Function as a class - contid.
- You can still call the function without the new keyword - but the reference to *this* won't be set.
- Best practice is to have it behave as if it was called with the new keyword
function Person(name, age) {
if (!(this instanceof Person)) {
return new Person(name,age);
}
//...
}
var p1 = Person('nadav', 29); // equivalent to new Person
- You can still call the function without the new keyword - but the reference to *this* won't be set.
- Best practice is to have it behave as if it was called with the new keyword
function Person(name, age) {
if (!(this instanceof Person)) {
return new Person(name,age);
}
//...
}
var p1 = Person('nadav', 29); // equivalent to new Person
Prototypes - contid.
- After being invoked with the new keyword, an object will have the "Person" prototype.
- You can set the object methods to be part of the prototype instead of each Object separately.
- You can add properties to an existing prototype using the constructors' "prototype" property.
function Person(name, age) {
//...
}
// function will be "shared" among instances
Person.prototype.getDetails = function {
return this.name + ',' + this.age;
}
- After being invoked with the new keyword, an object will have the "Person" prototype.
- You can set the object methods to be part of the prototype instead of each Object separately.
- You can add properties to an existing prototype using the constructors' "prototype" property.
function Person(name, age) {
//...
}
// function will be "shared" among instances
Person.prototype.getDetails = function {
return this.name + ',' + this.age;
}
Inheritance
- Instead of inheritance - there are "prototype chains"
- Alternative: Runtime Inheritance - Clone objects and add extra properties
- Some libraries (for example, node.js) provide all kind of 'inheritance-like' functionality
Prototypes Chain
- Give your prototype a prototype.
function Person(name, age, profession) {
//...
}
Person.prototype.getDetails = function() {...};
function Developer(name, age, lang) {
Person.call(this, name, age, 'developer');
this.lang = lang;
}
Developer.prototype = new Person();
var d = new Developer('Nadav', 29, 'JavaScript');
apply, call and bind
- You can invoke a function with the 'apply' method and specify the "this" reference as the first argument (followed by the other arguments as an array)
- you can also use 'call' but specify the arguments instead of using an array
function func(b) = { return this.a + b;}
var o = {a : 1}
func.apply(o, [3]); // will return 4
func.call(o, [3]); // will also return 4
bind
- calling 'bind' on a function will return a new function with fixed this/ parameters.
- Accepts this, and an array of arguments.
- Very useful when iterating over loops, or when using async programming.
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var getX = module.getX;
getX(); // 9, because in this case, "this" refers to the global object
// Create a new function with 'this' bound to module
var boundGetX = getX.bind(module);
boundGetX(); // 81
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var getX = module.getX;
getX(); // 9, because in this case, "this" refers to the global object
// Create a new function with 'this' bound to module
var boundGetX = getX.bind(module);
boundGetX(); // 81
Object "utility" methods
- The Object type has some very useful methods:
- Object.create(obj) - Will create a new object, setting obj as it's prototype.
- Object.getPrototypeOf
- Object.getOwnPropertyNames
- Object.keys
- Object.preventExtensions
- Object.defineProperty
- The Object type has some very useful methods:
- Object.create(obj) - Will create a new object, setting obj as it's prototype.
- Object.getPrototypeOf
- Object.getOwnPropertyNames
- Object.keys
- Object.preventExtensions
- Object.defineProperty
Object.defineProperty
- Defines a property of an object, but can define "special attributes" for that property.
- Can be used to define read-only, hidden or non-deletable properties.
- Can be used to define getter and setter function for the property.
var o = {}; // Creates a new object
// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, 'a', {
value: 37,
writable: true,
enumerable: true,
configurable: true
});
- writable, enumarable and configurable will be set to false if not explicitly specified!!!
Object.defineProperty
- Can be used to define getter and setter function for the property.
// Example of an object property added with defineProperty with an
// accessor property descriptor
var o = {};
var bValue = 38;
Object.defineProperty(o, 'b', {
get: function() { return bValue; },
set: function(newValue) { bValue = newValue; },
enumerable: true,
configurable: true
});
o.b; // 38
- You cannot specify getters /setters and also specify a value
- Can be used to define getter and setter function for the property.
// Example of an object property added with defineProperty with an
// accessor property descriptor
var o = {}; var bValue = 38; Object.defineProperty(o, 'b', { get: function() { return bValue; }, set: function(newValue) { bValue = newValue; }, enumerable: true, configurable: true }); o.b; // 38
- You cannot specify getters /setters and also specify a value
Async Functions
- Calling an async function with a callback function that will be invoked once it has completed its work
function doWorkAndCallMeWhenDone(callback) {
console.log('starting work');
setTimeout(function () {
console.log('work completed, calling callback');
callback();
}, 1000);
}
var onCompleteHandler = function () {
console.log('work is completed, now i can proceed with
my next task');
};
doWorkAndCallMeWhenDone(onCompleteHandler);
Async error handling
- A common design is that a callback function will have an error object as its first parameter and then the returned values
- If there was an error during the async function work, it will invoke the callback with the error as its first value
- First thing the callback will do is to check if there was an error
function doWorkAndCallMeWhenDone(callback) {
console.log('starting work'); setTimeout(function () { console.log('work completed with error, notifying caller'); callback('some error occurred'); }, 1000); } doWorkAndCallMeWhenDone(function (err, result) { if (err) return console.error('error doing work:', err); console.log('work is completed, now i can proceed with next task'); });
Async function
- checking for errors and getting the result from the async call
function doWorkAndCallMeWhenDone(callback) {
console.log('starting work'); setTimeout(function () { console.log('work completed successfully, notifying caller'); callback(null, 'some result object'); }, 1000); } doWorkAndCallMeWhenDone(function (err, result) { if (err) return console.error('error doing work:', err); console.log('work is completed with result:', result); });
Christmas tree problem
- Look for the tree...
function async(x, cb) { cb(null, x + 1); } function executeAsyncSequence(cb) { async(0, function (err, res) { async(res, function (err, res) { async(res, function (err, res) { cb(null, res); }); }); }); } executeAsyncSequence(function (err, res) { console.log('result:', res); });
- There are libraries that makes this look sequentially
Checking parameters
- Sometimes you allow you async function to be called without providing parameters or a callback
- This is a common design
function asyncFun(param, cb) {
if (typeof param == 'function') cb = param;
cb = cb || function () {console.log('completed work');};
// do some async work
cb();
}
asyncFun('some value', function () {console.log('here!');});
asyncFun(function () { console.log('here!'); });
asyncFun();
Copy of Javascript
By Nadav Bar
Copy of Javascript
- 1,148