Basic JavaScript
by John Vincent
Posted on February 23, 2017
This stuff ends up sprayed everywhere, so let's create a reference document.
Polymorphism
Polymorphism (many, forms) is the provision of a single interface to entities of different types.
Polymorphism is the ability (in programming) to present the same interface for differing underlying forms (data types).
Polymorphism is the characteristic of being able to assign a different meaning or usage to something in different contexts.
Inheritance
Inheritance enables new objects to take on the properties of existing objects. A class that is used as the basis for inheritance is called a superclass or base class. A class that inherits from a superclass is called a subclass or derived class.
Basic JavaScript
JavaScript is an Object Oriented Programming (OOP) language. A programming language can be called object-oriented if it provides four basic capabilities to developers −
-
Encapsulation − the capability to store related information, whether data or methods, together in an object.
-
Aggregation − the capability to store one object inside another object.
-
Inheritance − the capability of a class to rely upon another class (or number of classes) for some of its properties and methods.
-
Polymorphism − the capability to write one function or method that works in a variety of different ways.
Objects are composed of attributes. If an attribute contains a function, it is considered to be a method of the object, otherwise the attribute is considered a property.
Prototype Language
JavaScript is a prototype based language.
Every JavaScript Object has a prototype property, which makes inheritance possible.
The prototype property of an object is where we put methods and properties that we want other objects to inherit.
The constructor's prototype property is NOT the prototype of the constructor itself, it's the prototype of ALL instances that are created through it.
When a certain method (or property) is called, the search starts in the object itself, and if it cannot be found, the search moves on to the object's prototype. This continues until the method is found: Prototype Chain
JavaScript Engine
- parser
- generates abstract syntax tree
- passed to conversion to machine code
- generates machine code
- runs the code
Execution Contexts
A box, container or a wrapper which stores variables and in which a piece of our code is evaluated and executed.
The Default is the Global Execution Context.
- Code that is not inside any function
- Associated with the global object
- In the browser, that is the window object
For example
var name = 'john';
function first() {
var a = 'Hello!';
second();
var x = a + name;
}
function second() {
var b = 'Hi!';
third();
var z = b + name;
}
function third() {
var c = 'Hey!';
var z = c + name;
}
first();
Variables within function first() are stored within the Execution Context: first()
When third() is invoked, Execution stack is
Execution Context: third()
Execution Context: second()
Execution Context: first()
Global execution context
Execution Context Object
Variable Object (VO) - alls variables and function
Scope Chain
"this" variable
- Creation Phase
- Creation of the Variable Object
- The argument object is created, containing all the arguments that were passed into the function.
- Code is scanned for function declarations; for each function, a property is created in the Variable Object, pointing to the function.
- Code is scanned for variable declarations; for each variable, a property is created in the Variable Object and set to undefined.
The last 2 points are called Hoisting.
- Creation of the Scope chain
- Determine the value of the "this" variable
- Execution Phase
- The code of the function that generated the current execution context is run line by line.
Hoisting
Function declaration is hoisted.
calculateAge(1965);
abc = 'something';
function calculateAge(year) {
console.log(2016 - year);
}
var abc;
console.log("abc "+abc);
Variable is hoisted and = undefined
console.log(age);
var age = 23;
- Function expressions are not hoisted.
Scope
JavaScript uses function scope. Variables are visible to the function in which they are defined and in functions within the function.
List or a chain of objects that defines the variables that are in scope for that code.
JavaScript is a lexically scoped language.
Variables declared outside of a function are global variables and are visible everywhere in a JavaScript program.
Variables declared inside of a function have function scope and are visible only to code that appears inside that function.
Each new function creates a scope: the space/environment in which the variables it defines are accessible.
Example
var a = 'Hello!';
first();
function first() {
var b = 'Hi!';
second();
function second() {
var c = 'Hey!';
console.log(a + b + c);
}
}
produces
Hello!Hi!Hey!
second() scope has access to first() scope and Global scope.
Scope Chain
- second() scope
- first() scope
- Global scope
Execution Stack vs Scope Chain
For example
// Example to show the differece between execution stack and scope chain
var a = 'Hello!';
first();
function first() {
var b = 'Hi!';
second();
function second() {
var c = 'Hey!';
third();
}
}
function third() {
var d = 'John';
// console.log(a+b+c+d); // error b and c not defined
console.log(a+d);
}
Execution Stack - Order in which functions are called
Execution Context: third()
Execution Context: second()
Execution Context: first()
Global execution context
Scope Chain - Order in which functions are written lexically
Scope third()
a = 'Hello!'
d = 'John'
Scope second()
a = 'Hello!'
b = 'Hi!'
c = 'Hey!'
Scope first()
a = 'Hello!'
b = 'Hi!'
Global Scope
a = 'Hello!'
Determine the value of the "this" variable
Regular function call: the 'this' keyword points to the global object (the window object in the browser).
Method call: the 'this' variable points to the object that is calling the method.
The 'this' keyword is not assigned a value until a function where it is defined is actually called.
Example
console.log(this); // Window object
calculateAge(1985); // 1
function calculateAge(year) {
console.log(2016 - year);
console.log(this); // 1,
}
var john = {
name: 'John',
yearOfBirth: 1990,
calculateAge: function() {
console.log(this); // 2, 4
console.log(2016 - this.yearOfBirth);
function innerFunction() {
console.log(this); // 3
}
innerFunction();
}
};
john.calculateAge();
var mike = {
name: 'Mike',
yearOfBirth: 1984
};
mike.calculateAge = john.calculateAge;
mike.calculateAge();
1. calculateAge(1985)
* this = Window
2. john.calculateAge();
* this = Object (john)
3. innerFunction();
* this = Window
4. mike.calculateAge(); // method borrowing
* this = Object (mike)
Objects
Everything is an object, except primitives (Numbers, Strings, Booleans, Undefined, Null)
Object Properties
Object properties can be any of the three primitive data types, or any of the abstract data types, such as another object. Object properties are usually variables that are used internally in the object's methods, but can also be globally visible variables that are used throughout the page.
The syntax for adding a property to an object is −
objectName.objectProperty = propertyValue;
For example − The following code gets the document title using the "title" property of the document object.
var str = document.title;
Object Methods
Method is a function that is attached to an object.
Methods are the functions that let the object do something or let something be done to it. There is a small difference between a function and a method – at a function is a standalone unit of statements and a method is attached to an object and can be referenced by the this keyword.
Methods are useful for everything from displaying the contents of the object to the screen to performing complex mathematical operations on a group of local properties and parameters.
For example − Following is a simple example to show how to use the write() method of document object to write any content on the document.
document.write("This is test");
User-Defined Objects
All user-defined objects and built-in objects are descendants of an object called Object.
The new Operator
The new operator is used to create an instance of an object. To create an object, the new operator is followed by the constructor method.
In the following example, the constructor methods are Object(), Array(), and Date(). These constructors are built-in JavaScript functions.
var employee = new Object();
var books = new Array("C++", "Perl", "Java");
var day = new Date("August 15, 1947");
The Object() Constructor
A constructor is a function that creates and initializes an object. JavaScript provides a special constructor function called Object() to build the object. The return value of the Object() constructor is assigned to a variable.
The variable contains a reference to the new object. The properties assigned to the object are not variables and are not defined with the var keyword.
Examples
var book = new Object();
book.subject = "JavaScript";
book.author = "A.Name";
function book(title, author){
this.title = title;
this.author = author;
}
var myBook = new book("JavaScript", "A.Name");
function addPrice(amount){
this.price = amount;
}
function book(title, author){
this.title = title;
this.author = author;
this.addPrice = addPrice; // Assign that method as property.
}
var myBook = new book("JavaScript", "Name");
myBook.addPrice(5.95);
Various Objects
var val = new Number(number);
var val = new Boolean(value);
var val = new String(string);
new Date( )
new Date(milliseconds)
new Date(datestring)
new Date(year,month,date[,hour,minute,second,millisecond ])
var pi_val = Math.PI;
var sine_val = Math.sin(30);
var pattern = new RegExp(pattern, attributes);
Arrays
var names = ['John', 'Jane', 'Mark'];
var years = new Array(1990, 1969, 1948);
var john = ['John', 'Smith', 1990, 'designer', false];
john.push('blue');
john.unshift('Mr.');
john.pop();
john.shift();
console.log(john);
console.log(john.length);
if (john.indexOf('teacher') === -1) {
console.log('John is NOT a teacher.');
}
Object Literal
var john = {
name: 'John',
lastName: 'Smith',
yearOfBirth: 1990,
job: 'teacher',
isMarried: false
};
console.log(john.lastName);
console.log(john['lastName']);
new Object()
var jane = new Object();
jane.name = 'Jane';
jane.lastName = 'Smith';
jane['yearOfBirth'] = 1969;
jane['job'] = 'retired';
jane['isMarried'] = true;
Objects and methods
var mike = {
yearOfBirth: 1950,
calculateAge: function() {
this.age = 2016 - this.yearOfBirth;
}
};
mike.calculateAge();
console.log(mike);
Object.prototype
// what is this "Object.prototype" anyway...?
var prototypeType = typeof Object.prototype;
console.log(prototypeType);
// now let's examine it!
var hasOwn = Object.prototype.hasOwnProperty('hasOwnProperty');
console.log(hasOwn);
Iterating over Object properties
function StudentReport() {
var grade1 = 4; // private
var grade2 = 2;
var grade3 = 1;
this.getGPA = function() { // public
return (grade1 + grade2 + grade3) / 3;
};
}
var myStudentReport = new StudentReport();
for (var x in myStudentReport) {
if (typeof myStudentReport[x] !== "function") {
console.log("Muahaha! " + myStudentReport[x]);
}
}
// if (typeof languages[x] === "string") {
function Dog(breed) {
this.breed = breed;
}
Dog.prototype.sayHello = function() {
console.log("Hello this is a "+this.breed+" dog");
};
var yourDog = new Dog("golden retriever");
yourDog.sayHello();
var myDog = new Dog("dachshund");
myDog.sayHello();
function Person(first, last, age) {
this.firstname = first;
this.lastname = last;
this.age = age;
var bankBalance = 7500; // private
this.askTeller = function(pass) {
if (pass == 1234) return bankBalance;
else return "Wrong password.";
};
}
var john = new Person('John', 'Smith', 30);
var myBalance = john.askTeller(1234);
Private vs Public Method
Private
var returnBalance = function()
Public
this.askTeller = function()
function Person(first, last, age) {
this.firstname = first;
this.lastname = last;
this.age = age;
var bankBalance = 7500;
var returnBalance = function() { // private method
return bankBalance;
};
// create the new function here
this.askTeller = function() { // public, returns a function
return returnBalance;
};
this.getName = function() {
return this.firstname + " " + this.lastname;
}
}
var john = new Person('John', 'Smith', 30);
console.log(john.returnBalance);
var myBalanceMethod = john.askTeller(); // returns a method
var myBalance = myBalanceMethod();
console.log(myBalance);
Array of Objects
var family = new Array();
family[0] = new Person("alice", 'abcd', 40);
family[1] = new Person("bob", 'defg', 42);
for (var idx in family) {
var item = family[idx];
console.log(item.name);
}
Function Expression
var ageDifference = function(person1, person2) {
return person1.age - person2.age;
};
var olderAge = function(person1, person2) {
return person1.age > person2.age ? person1.name : person2.name;
};
var alice = new Person("Alice", 'abcd', 30);
var billy = new Person("Billy", 'defg', 25);
var diff = ageDifference (alice, billy);
console.log("The older person is " + olderAge(alice, billy));
Prototype Chain
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
this.isAlive = true;
}
function Penguin(name) {
this.name = name;
this.numLegs = 2;
}
function Emperor(name) {
this.name = name;
this.saying = "Waddle waddle";
}
// set up the prototype chain
Penguin.prototype = new Animal();
Emperor.prototype = new Penguin();
var myEmperor = new Emperor("Jules");
console.log(myEmperor.saying); // should print "Waddle waddle"
console.log(myEmperor.numLegs); // should print 2
console.log(myEmperor.isAlive); // should print true
// 3 lines required to make harry_potter
var harry_potter = new Object();
harry_potter.pages = 350;
harry_potter.author = "J.K. Rowling";
or
// A custom constructor for book
function Book (pages, author) {
this.pages = pages;
this.author = author;
}
// Use our new constructor to make the_hobbit in one line
var the_hobbit = new Book(320, "J.R.R. Tolkien");
var bob = {
firstName: "Bob",
lastName: "Jones",
phoneNumber: "(650) 777-7777",
email: "bob.jones@example.com"
};
var mary = {
firstName: "Mary",
lastName: "Johnson",
phoneNumber: "(650) 888-8888",
email: "mary.johnson@example.com"
};
var contacts = [bob, mary];
function printPerson(person) {
console.log(person.firstName+' '+person.lastName);
}
function list() {
for (var idx in contacts) {
printPerson(contacts[idx]);
}
}
function search(lastName) {
for (var idx in contacts) {
if (contacts[idx].lastName === lastName)
printPerson(contacts[idx]);
}
}
function add(firstName, lastName, phoneNumber, email) {
contacts[contacts.length] = {
firstName: firstName,
lastName: lastName,
phoneNumber: phoneNumber,
email: email
};
}
list();
search("Jones");
add("A", "B", "123456789", "abc@gmail.com");
list();
//printPerson(contacts[0]);
//printPerson(contacts[1]);
extends
class Rectangle {
constructor(w, h) {
this.w = w;
this.h = h;
}
}
Rectangle.prototype.area = function () {
return this.w * this.h;
}
class Square extends Rectangle {
constructor(w) {
super(w, w);
}
}
const rec = new Rectangle(3, 4);
const sqr = new Square(3);
console.log(rec.area());
console.log(sqr.area());
new Object()
var square = new Object();
square.sideLength = 6;
square.calcPerimeter = function() {
return this.sideLength * 4;
};
// help us define an area method here
square.calcArea = function() {
return this.sideLength * this.sideLength;
};
var p = square.calcPerimeter();
var a = square.calcArea();
console.log("p "+p+" a "+a);
this keyword
/*
The keyword this acts as a placeholder, and will refer to whichever object called that method when the method is actually used.
*/
// here we define our method using "this", before we even introduce bob
var setAge = function (newAge) {
this.age = newAge;
};
// now we make bob
var bob = new Object();
bob.age = 30;
// and down here we just use the method we already made
bob.setAge = setAge;
// change bob's age to 50 here
bob.setAge(50);
Object in an Object
var Spencer = {
age: 22,
country: "United States"
};
// make your own object here called me
Spencer.me = {};
Spencer.me.age = 34;
Spencer.me.country = 'Mars';
Spencer
age: 22
country: "United States"
me:
age: 34
country: "Mars"
Object literal pattern
var friends = {
// firstName: '',
// lastName: '',
// number: ''
// abc() {
// return 'xyz';
// }
};
friends["bill"] = {};
friends.bill.firstName = "Bill";
friends.bill.lastName = "Last";
friends.bill.number = "12345";
friends.steve = {};
friends.steve.firstName = "Steve";
friends.steve.lastName = "Jobs";
friends.steve.number = "(408) 555-5555";
friends.steve.address1 = "1 Infinite Loop";
friends.steve.address2 = "Cupertino, CA 95014";
var myobj = {};
myobj.bill = new Object();
myobj.bill.firstName = "Bill";
myobj.steve = new Object();
myobj.steve.firstName = "Steve";
function list() {
for (var key in friends) {
console.log(key);
}
}
function search(name) {
for (var key in friends) {
if (friends[key].firstName === name) {
// console.log(friends[key]);
display(friends[key]);
return friends[key];
}
}
}
function display(friend) {
console.log("First Name: "+friend.firstName);
console.log("Last Name: "+friend.lastName);
console.log("Number: "+friend.number);
console.log("Address: "+friend.address1);
console.log(" "+friend.address2);
}
//list();
//
//console.log("search...");
//search("john");
search("Steve");
//console.log(friends.steve.abc());
Function Expression
var greeting = function (name) {
console.log("Great to see you," + " " + name);
};
greeting("fido");
var ABC = ABC || {};
ABC.abcd = {
do_1 : function() {
console.log("--- ABC.Subspace.do_1");
},
do_2 : function(name, path) {
console.log("--- ABC.Subspace.do_2; name " + name + " path " + path);
}
};
function test1() {
ABC.abcd.do_1();
}
ABC.abcd.do_1();
// test1();
Function Constructor
var Person = function(name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
var john = new Person('John', 1990, 'teacher');
var jane = new Person('Jane', 1969, 'designer');
var mark = new Person('Mark', 1948, 'retired');
Inheritance
var Person = function(name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
this.myfunc = function() {
console.log("in myfunc");
};
};
Person.prototype.calculateAge = function() {
console.log(2016 - this.yearOfBirth);
};
Person.prototype.lastName = 'Smith';
var john = new Person('John', 1990, 'teacher');
var jane = new Person('Jane', 1969, 'designer');
var mark = new Person('Mark', 1948, 'retired');
john.calculateAge();
jane.calculateAge();
mark.calculateAge();
console.log(john.lastName);
console.log(jane.lastName);
console.log(mark.lastName);
john.myfunc();
john.hasOwnProperty('job'); // true
john.hasOwnProperty('lastName'); // false
john instanceof Person; // true
Array Prototype
var x = [2, 4, 6];
console.log(x);
x.__proto__ is Array()
Object.create
var personProto = {
calculateAge: function() {
console.log(2016 - this.yearOfBirth);
}
};
var john = Object.create(personProto);
john.name = 'John';
john.yearOfBirth = 1990;
john.job = 'teacher';
var jane = Object.create(personProto, {
name: { value: 'Jane' },
yearOfBirth: { value: 1969 },
job: { value: 'designer' }
});
Primitives vs Objects
Primitives
Primitive holds the value
var a = 23;
var b = a;
a = 46;
console.log(a);
console.log(b);
Objects
var keeps a reference to the object
var obj1 = {
name: 'John',
age: 26
};
var obj2 = obj1;
obj1.age = 30;
console.log(obj1.age);
console.log(obj2.age);
Functions
Object Arguments are references
var age = 27;
var obj = {
name: 'Jonas',
city: 'Lisbon'
};
function change(a, b) {
a = 30;
b.city = 'San Francisco';
}
change(age, obj);
console.log(age);
console.log(obj.city);
Functions
Functions are objects.
JavaScript functions are called "First-Class Functions"
- A function is an instance of the Object type.
- A function behaves like any other object.
- We can store functions in a variable.
- We can pass a function as an argument to another function.
- We can return a function from a function.
Passing functions as arguments - Callback Function
var years = [1990, 1965, 1937, 2005, 1998];
function arrayCalc(arr, fn) {
var arrRes = [];
for (var i = 0; i < arr.length; i++) {
arrRes.push(fn(arr[i]));
}
return arrRes;
}
function calculateAge(el) {
return 2016 - el;
}
function isFullAge(el) {
return el >= 18;
}
function maxHeartRate(el) {
if (el >= 18 && el <= 81) {
return Math.round(206.9 - (0.67 * el));
} else {
return -1;
}
}
var ages = arrayCalc(years, calculateAge);
var fullAges = arrayCalc(ages, isFullAge);
var rates = arrayCalc(ages, maxHeartRate);
console.log(ages);
console.log(rates);
Callback
A callback is a function that is to be executed after another function has finished executing — hence the name call back
.
or
In JavaScript, functions are objects. Because of this, functions can take functions as arguments, and can be returned by other functions. Functions that do this are called higher-order functions. Any function that is passed as an argument is called a callback function.
Why Callbacks
JavaScript is an event driven language. This means that instead of waiting for a response before moving on, JavaScript will keep executing while listening for other events.
For example
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
will print
2
1
JavaScript executed our functions in the correct order, first() and the second(), it's just that JavaScript didn’t wait for a response from first() before moving on to execute second().
Callbacks are a way to make sure certain code doesn’t execute until other code has already finished execution.
function app(name, callback) {
console.log(`In app, name ${name}`);
callback();
}
function callback() {
console.log('In callback');
}
app('my app', callback);
Functions returning functions
Uses Anonymous function.
Returns a function that can be used later. This is possible because functions are First-Class functions in JavaScript because they are effectively objects.
function interviewQuestion(job) {
if (job === 'designer') {
return function(name) {
console.log(name + ', can you please explain what UX design is?');
}
} else if (job === 'teacher') {
return function(name) {
console.log('What subject do you teach, ' + name + '?');
}
} else {
return function(name) {
console.log('Hello ' + name + ', what do you do?');
}
}
}
var teacherQuestion = interviewQuestion('teacher'); // is a function
var designerQuestion = interviewQuestion('designer');
teacherQuestion('John');
designerQuestion('John');
designerQuestion('jane');
designerQuestion('Mark');
designerQuestion('Mike');
interviewQuestion('teacher')('Mark');
Notice
interviewQuestion('teacher')('Mark');
interviewQuestion('teacher')
returns a function, thus is
function('Mark')
Function declaration
// Function declaration: starts with "function"
function isNil(value) {
return value == null;
}
Function expression
// Function expression: starts with "var"
var isTruthy = function(value) {
return !!value;
};
Self-executing closure
(function() {
})();
Immediately Invoked Function Expression (IIFE)
No function name is not allowed.
function() {
}
make as a IIFE
(function() {
})();
// Function expression (IIFE): starts with "("
(function messageFunction(message) {
return message + ' World!';
})('Hello again');
// passes 'Hello Again' as parameter to the function.
Simple app
function game() {
var score = Math.random() * 10;
console.log(score >= 5);
}
game();
Rewritten using IIFE, providing data privacy.
(function () {
var score = Math.random() * 10;
console.log(score >= 5);
})();
IIFE with arguments
(function (goodLuck) {
var score = Math.random() * 10;
console.log(score >= 5 - goodLuck);
})(5);
Closure
“A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.”
Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.
An inner function has always access to the variables and parameters of its outer function, even after the outer function has returned.
function retirement(retirementAge) {
var a = ' years left until retirement.';
return function(yearOfBirth) {
var age = 2016 - yearOfBirth;
console.log((retirementAge - age) + a);
}
}
var retirementUS = retirement(66);
// var retirementGermany = retirement(65);
// var retirementIceland = retirement(67);
retirementUS(1990);
// retirementGermany(1990);
// retirementIceland(1990);
//retirement(66)(1990);
Notice var retirementUS = retirement(66);
retirementUS
is function(yearOfBirth)
with Scopes
Closure (retirement)
a: " years left until retirement."
retirementAge = 66
Global
When var retirementUS = retirement(66)
has executed
retirement() is removed from the execution stack.
retirement() scope stays on the Scope Chain.
retirementUS(1990)
causes
retirementUS() to be added to the execution stack
retirementUS() scope to be added to the scope chain.
retirementUS()
scope now has access to the retirement() scope.
The current execution context has "closed in" on the outer variable object, so that it can use it, so that is why it is called a closure.
The scope chain always stays intact.
Another example
function interviewQuestion(job) {
return function(name) {
if (job === 'designer') {
console.log(name + ', can you please explain what UX design is?');
} else if (job === 'teacher') {
console.log('What subject do you teach, ' + name + '?');
} else {
console.log('Hello ' + name + ', what do you do?');
}
}
}
interviewQuestion('teacher')('John');
Another example
A function inside a function can access variables defined in the parent function.
var name = "Fred";
function sayMyName() {
var lastname = "Flintstone";
function sayMyLastName() { // a closure
console.log(lastname);
}
sayMyLastName();
}
sayMyName();
or
function sayMyName(firstname) {
var lastname = "Flintstone";
function sayMyLastName() { // a closure
console.log(`Name ${firstname} ${lastname}`);
}
sayMyLastName();
}
sayMyName('Fred');
or
function sayMyName(firstname) {
var lastname = "Flintstone";
function sayMyLastName() { // a closure
console.log(`Name ${firstname} ${lastname}`);
}
sayMyLastName();
}
sayMyName('Fred');
sayMyName('Bill');
or
function sayMyName(firstname) {
var lastname = "Flintstone";
return function makeName(middlename) { // a closure
return `${firstname} ${middlename} ${lastname}`;
}
}
var p1 = sayMyName('Fred');
console.log('name 1 ', p1('Sid'));
console.log('name 1 ', sayMyName('Fred')('Sid'));
console.log('name 2 ', sayMyName('Bill')('Vic'));
Bind, Call and Apply
By example
var john = {
name: 'John',
age: 26,
job: 'teacher',
presentation: function(style, timeOfDay) {
if (style === 'formal') {
console.log('Good ' + timeOfDay + ', Ladies and gentlemen! I\'m ' + this.name + ', I\'m a ' + this.job + ' and I\'m ' + this.age + ' years old.');
} else if (style === 'friendly') {
console.log('Hey! What\'s up? I\'m ' + this.name + ', I\'m a ' + this.job + ' and I\'m ' + this.age + ' years old. Have a nice ' + timeOfDay + '.');
}
}
};
var emily = {
name: 'Emily',
age: 35,
job: 'designer'
};
john.presentation('formal', 'morning');
which produces
Good morning, Ladies and gentlemen! I'm John, I'm a teacher and I'm 26 years old.
Call
Method borrowing with a general form of
myobj.myfunction.call(obj2,….)
for ‘this’ within myfunction
, set this to obj2
For example
john.presentation.call(emily, 'friendly', 'afternoon');
which produces
Hey! What's up? I'm Emily, I'm a designer and I'm 35 years old. Have a nice afternoon.
Apply
Apply is similar to Call, except Apply accepts its arguments as an array.
Method borrowing with a general form of
myobj.myfunction.apply(obj2,[params as an array])
for ‘this’ within myfunction
, set this to obj2
For example
john.presentation.apply(emily, ['friendly', 'afternoon']);
which produces
Hey! What's up? I'm Emily, I'm a designer and I'm 35 years old. Have a nice afternoon.
Bind
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
var var1 = myobj.myfunction.bind(obj2,
for ‘this’ within myfunction
, set this to obj2
var1
is now an object that is a reference to a function for which ‘this’ now means obj2
.
This var can now be executed multiply, with different parameters.
Very useful for creating functions with preset arguments.
For example
var johnFriendly = john.presentation.bind(john, 'friendly');
johnFriendly('morning');
which produces
Hey! What's up? I'm John, I'm a teacher and I'm 26 years old. Have a nice morning.
and
johnFriendly('night');
which produces
Hey! What's up? I'm John, I'm a teacher and I'm 26 years old. Have a nice night.
For example
var emilyFormal = john.presentation.bind(emily, 'formal');
emilyFormal('afternoon');
which produces
Good afternoon, Ladies and gentlemen! I'm Emily, I'm a designer and I'm 35 years old.
Another example
var years = [1990, 1965, 1937, 2005, 1998];
function arrayCalc(arr, fn) {
var arrRes = [];
for (var i = 0; i < arr.length; i++) {
arrRes.push(fn(arr[i]));
}
return arrRes;
}
function calculateAge(el) {
return 2016 - el;
}
function isFullAge(limit, el) {
return el >= limit;
}
var ages = arrayCalc(years, calculateAge);
var fullJapan = arrayCalc(ages, isFullAge.bind(this, 20));
var fullOther= arrayCalc(ages, isFullAge.bind(this, 28));
console.log(ages);
console.log(fullJapan);
console.log(fullOther);
which produces
[26, 51, 79, 11, 18]
[true, true, true, false, false]
[false, true, true, false, false]
Currying
Briefly, currying is a way of constructing functions that allows partial application of a function’s arguments.
What this means is that you can pass all of the arguments a function is expecting and get the result, or pass a subset of those arguments and get a function back that’s waiting for the rest of the arguments.
Arguments
arguments variable is a keyword, just like this
function isFullAge5() {
//console.log(arguments);
var argsArr = Array.prototype.slice.call(arguments);
argsArr.forEach(function(cur) {
console.log((2016 - cur) >= 18);
});
}
Binary
AND Operator: &
The AND &
operator compares each binary digit from two integers. If both of the two digits are 1, then
the corresponding output digit will also be 1, otherwise it will be 0.
function isOdd(num) {
const mask = 1;
const bool = !!(num & mask);
}
Convert to boolean
const bool = !!(num & mask);
OR Operator: |
In the OR |
operator, instead of needing both input bits to be 1 for the output bit to be 1, the resultant bit value will be
set to 1 as long as either of the input bits are 1
const ans2 = num1 | num2;
XOR Operator: ^
The XOR ^
operator produces 1 in the truth table when both bits are different;
that is when one of the bits is a 1 and the other is a 0
function xor(num1, num2) {
return num1 ^ num2;
}
NOT Operator: ~
The NOT ~
operator is the simplest of the operations involving binary values. The ~
operator operates on
only a single bit and provides the complement (opposite) value
const result = ~num;
Use Binary
function exercise(num) {
let mask = 0b100;
let result = num | mask;
console.log(`mask ${mask.toString(2)}; num ${num}, ${num.toString(2)} result ${result}, ${result.toString(2)}`);
}
Set as binary
let mask = 0b100
Display as binary
${result.toString(2)}
Shift Operators
-
Left Shift Operator:
<<
-
Right Shift Operator:
>>
-
Zero-Fill Right Shift Operator:
>>>
function leftShift(num, shift) {
return num << shift;
}
function rightShift(num, shift) {
return num >> shift;
}
function zeroFillRightShift(num, shift) {
return num >>> shift;
}
Using Shift Operators
function isSet(num, bitPosition) {
return !!(num & (2 ** bitPosition));
}
function clearBit(number, bitPosition) {
const mask = ~(1 << bitPosition);
return number & mask;
}
function setBit(number, bitPosition) {
return number | (1 << bitPosition);
}
function updateBit(number, bitPosition, bitValue) {
const bitValueNormalized = bitValue ? 1 : 0;
const clearMask = ~(1 << bitPosition);
return (number & clearMask) | (bitValueNormalized << bitPosition);
}
function getBit(number, bitPosition) {
return (number & (1 << bitPosition)) === 0 ? 0 : 1;
}
typeof
let year = 23;
let day = '12';
let before = false';
let abc;
console.log(typeof year);
console.log(typeof day);
console.log(typeof before);
console.log(typeof abc);
number
string
boolean
undefined
const question = new Map();
question.set(1, 'ES5');
etc
for (let [key, value] of question.entries()) {
if (typeof(key) === 'number') {
console.log(`Answer ${key}: ${value}`);
}
}
Truthy and Falsy values
undefined, null, 0, '', NaN
Not falsy values
Other
arr.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
Require and Exports
const mediaTags = require('./mediaTags').mediatags;
const tags = mediaTags(pathname);
const jsmediatags = require('jsmediatags');
function mediatags(filename) {
return new Promise((resolve, reject) => {
jsmediatags.read(filename, {
onSuccess(tag) {
resolve(tag);
},
onError(error) {
reject(error);
}
});
});
}
module.exports = { mediatags };
Utilities
Some useful utilities follow
/*
word = 'abc'
returns:
{ a: false, b: false, c: false }
*/
export function convertStringtoObject(word) {
const obj = [...word].reduce((ac,a) => ({...ac,[a]: false}),{});
return obj;
}
/*
word = 'abc'
returns:
[ { id: 0, key: 'a', value: false }, { id: 1, key: 'b', value: false }, { id: 2, key: 'c', value: false } ]
*/
export function convertStringtoArrayObject(word) {
const obj = [...word].map((letter, id) => ({ id, key: letter, value: false }));
return obj;
}
/*
[ { id: 0, key: 'a', value: false }, { id: 1, key: 'b', value: false }, { id: 2, key: 'c', value: false } ]
returns:
'abc'
*/
export function convertArrayObjectsToString(arr) {
const str = arr.reduce((ac, a) => (ac + a.key), '');
return str;
}
/*
[ { id: 0, key: 'A', value: false }, { id: 1, key: 'B', value: false }, { id: 2, key: 'C', value: false } ], 'B'
returns:
[ { id: 0, key: 'A', value: false }, { id: 1, key: 'B', value: true }, { id: 2, key: 'C', value: false } ]'
*/
export function updateArrayObjectsForLetter(arr, key) {
const obj = arr.map(letter => ({
id: letter.id,
key: letter.key,
value: (key === letter.key ? true : letter.value)
}));
return obj;
}
/*
[ { id: 0, key: 'A', value: false }, { id: 1, key: 'B', value: false }, { id: 2, key: 'C', value: false } ], 'B'
returns:
true
*/
export function isLetterInArrayObjects(arr, key) {
let bool = false;
arr.forEach(letter => { if (key === letter.key) bool = true });
return bool;
}
/*
[ { id: 0, key: 'A', value: true }, { id: 1, key: 'B', value: true }, { id: 2, key: 'C', value: true } ]
returns:
true
*/
export function isArrayObjectsComplete(arr) {
let bool = true;
arr.forEach(letter => {
if (! letter.value) bool = false;
});
return bool;
}
function doubleDigits(num) {
const str = `${num}`;
if (str.length < 2) {
return `0${str}`;
}
return str;
}
export function defaultDate() {
const date = new Date();
// prettier-ignore
const str = `${date.getFullYear()}-${doubleDigits(date.getMonth() + 1)}-${doubleDigits(date.getDate())}`;
return str;
}
export function remainingProperties(props, types) {
// console.log('---utils::remainingProperties, props ', props, ' types ', types);
const ret = {};
Object.entries(props).forEach(([key, value]) => {
// console.log(`${key} ${value}`);
if (!types[key]) {
// console.log('key ', key, ' not found');
ret[key] = value;
}
});
// console.log('---utils::remainingProperties, ret ', ret);
return ret;
}
export function initcap(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
export function isDesktop() {
return window.matchMedia('(max-width: 767px)').matches;
}
export function isMdUp() {
return window.matchMedia('(min-width: 960px)').matches;
}
export function copyMoves(original) {
const moves = [ ...original];
return moves;
}
const board = JSON.parse(JSON.stringify(original));
export default function random() {
return Math.floor(Math.random() * 6);
}
export function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
capitalize(s) {
if (typeof s !== 'string') return '';
return s.charAt(0).toUpperCase() + s.slice(1);
}
improveText(s, replacement) {
if (typeof s !== 'string') return '';
const arr = [];
s.split(' ').forEach((item) => {
arr.push(capitalize(item));
});
return arr.join(replacement);
}
createName(s) {
if (typeof s !== 'string') return '';
const arr = [];
s.split('-').forEach((item) => {
arr.push(this.capitalize(item));
});
const result = arr.join('');
// console.log('createName; result ', result);
return result;
}
getWeekDay(date) {
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
return days[date.getDay()];
}
getMonth(date) {
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
return months[date.getMonth()];
}
splitter(str) {
const result = str.match(/^([\d]{4}-[\d]{2}-[\d]{2})-(.+)$/);
return result;
}
formatDate(date) {
return `${this.getMonth(date)} ${date.getDate()}, ${date.getFullYear()}`;
}