Introduction to Javascript
Published: Sep 9, 2017 Tags: web, frontend Category: Engineering
Javascript is the fundumantal programming language for frontend development. This blog introduces the basic concept of Javascript language.
Javascript Basic
First, let's compare Javascript with a OOP programming language C#.
| C# | Javascript |
|---|---|
| Strongly-Typed | Loosely-typed |
| Static | Dynamic |
| Classical Inheritance | Prototypal |
| Classes | Functions |
| Constructors | Functions |
| Methods | Functions |
Strongly typed or weakly typed (loosely typed)
In general, a strongly typed language is more likely to generate an error or refuse to compile if the argument passed to a function does not closely match the expected type. On the other hand, a weakly typed language may produce unpredictable results or may perform implicit type conversion.
1var x = 0;
2var isNumber = typeof x == "number";
3x = new Object();
Duck typing
Type is less important, but shape is important
1function Feed(ani) { ani.Feed() } // accepts any object implements Feed function
Dynamic Typing
A language is statically typed if the type of a variable is known at compile time. A language is dynamically typed if the type is associated with run-time values, and not named variables/fields/etc.
1var x = {
2 name: "Shawn",
3 city: "Atlanta"
4};
5x.phone = "xxx-xx-xxx";
6x.makeCall = function() {
7 callSomeone(this.phone);
8};
Type
Type Coalescing
Javascript wants to coalesce values.
1 "test " + "me"
2 "test " + 1
3 "test " + true
4 "test " + (1 == 1)
5 100 + "25" // 10025
Most operators in Javascript are identical to .net, except…
- Equality/NotEqual (==, !=): The means determines equality with coalescing (if necessary)
- Javascript's identically Equality operators (===, !==) which is similar to .Equal(). Determines quality without coalescing
1 "hello" == "hello"; // true
2 1 == 1; // true
3 1 == "1"; // true
4 1 === "1"; // false
5 1 !== "1"; // true
Types Primitives
Javascript has basic types
- Value types: boolean, string, number
- Reference Type: object
- Delegate type: function
- Special: undefined, null
1var a = typeof 1; //number
2var b = typeof 1.0; // number
3var c = typeof true; // boolean
4var d = typeof false; // boolean
5var e = typeof "hello world"; // string
Number
Examples of number:
- 1, 1.5, 070, 0xffff, 1.34e6, 10.0
- Number.MIN_VALUE
- Number.MAX_VALUE
- Number.POSITIVE_INFINITY;
- Number.NEGATIVE_INFINITY;
Operator
1var fail = 10/"zero"; // NaN
2var test1 = NaN == NaN; // false
3var test2 = isNaN(NaN); // true
4var test3 = isNaN(fail); //true
5var test4 = isNaN(10); // false
6var test5 = isNaN("10"); //false
7var test6 = isNaN("fail");//true
All the following values are false
1if("")
2if(0)
3if(10/0)
4if(null)
5if(undefined)
Function
Overloading function
Javascript does not support function overload.
1function foo(one) {
2 alert('first);
3}
4function foo(one, two) {
5 alert('second');
6}
7foo(1); // second
The second one simply overrule the first one
Arguments object
Arguments object is available inside function body only.
1function foo(one, two, three) {
2 alert(arguments.length);
3}
4foo(1); //1
5foo(1, 2); //2
6foo(1,2,3); //3
Accessing the values through arguments object.
1function foo() {
2 for(var x = 0; x < arguments.length; x++) {
3 alert(arguments[x]);
4 }
5}
6foo(1, 2, 3); // 1,2,3
All functions return a value
If not defined then it's 'undefined'
1function foo() {
2 return;
3}
4var x = foo();
Function is just an object
Has properties and member functions
1function log(s) { alert('yup'); }
2var x = log.length; // 1 parameter
3var y = log.name; // 'log'
4var z = log.toString() // 'function log(s) { alert('yup'); }
Function Body Variable
"this" applies to the owner of the function
1var f = function() {
2 alert(this);
3};
4f(); // [Object Window]
5
6var obj = {
7 name: 'myObj',
8 myFunc: function() {
9 console.log(this.name);
10 }
11};
12obj.myFunc(); // 'myObj'
13
14var f = obj.myFunc.bind(this);
15f(); // this == global object
bind() lets you change the owner.
For details, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Closures
JavaScript closure makes it possible for a function to have "private" variables.
1var add = (function () {
2 var counter = 0;
3 return function () {return counter += 1;}
4})();
5
6add();
7add();
8add();
9
10// the counter is now 3
The variable add is assigned the return value of a self-invoking function.
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
This way add becomes a function. The "wonderful" part is that it can access the counter in the parent scope.
The counter is protected by the scope of the anonymous function, and can only be changed using the add function.
The magic is that in JavaScript a function reference also has a secret reference to the closure it was created in — similar to how delegates are a method pointer plus a secret reference to an object.
1function say667() {
2 var num = 42;
3 var say = function() { console.log(num); }
4 num++;
5 return say;
6}
7var sayNumber = say667();
8sayNumber(); //logs 43
1var gLogNumber, gIncreaseNumber, gSetNumber;
2function setupSomeGlobals() {
3 var num = 42;
4 gLogNumber = function() { console.log(num); }
5 gIncreaseNumber = function() { num++; }
6 gSetNumber = function(x) { num = x; }
7}
8setupSomeGlobals();
9gIncreaseNumber();
10gLogNumber(); //43
11gSetNumber(5);
12gLogNumber(); // 5
13
14var oldLog = gLogNumber;
15
16setupSomeGlobals();
17gLogNumber(); // 42
18oldLog() //5
Note that in the above example, if you call setupSomeGlobals() again, then a new closure (stack-frame!) is created.
The old gLogNumber, gIncreaseNumber, gSetNumber variables are overwritten with new functions that have the new closure.
Closure can also introduce tricky bugs if not used correctly.
1function buildList(list) {
2 var result = [];
3 for (var i = 0; i < list.length; i++) {
4 var item = 'item' + i;
5 result.push(function() { console.log(item + ' ' + list[i]) });
6 }
7 return result;
8}
9function testList() {
10 var fnlist = buildList([1,2,3]);
11 for (var j = 0; j < fnlist.length; j++) {
12 fnlist[j]();
13 }
14}
15testList() // logs 'item2 undefined' 3 times
This is because just like previous examples, there is only one closure for the local variables for buildList. When the anonymous functions are called on the line fnlistj; they all use the same single closure, and they use the current value for i and item within that one closure (where i has a value of 3 because the loop had completed, and item has a value of 'item2'). Note we are indexing from 0 hence item has a value of item2. And the i++ will increment i to the value 3.
Self-executing function
1(function() {
2 var private_variable = 'private';
3})();
Scope
Javascript has scope chain. When looking for the definition of a variable, the javascript engine first looks at the local execution context object. If the definition isn't there, it jumps up the scope chain to the execution context it was created in and looks for the variable definition in that execution context object, and so on until it finds the definition or reaches the global scope.
Global scope. Objects at root are 'global'.
1var a = 'Hello'
2if(true) {
3 var b = a;
4}
5var c = b; //this works
1var a = 'hello';
2function() {
3 var b = a;
4}
5var c = b; //this doesn't work
Javascript lacks real namespaces. We can mimic by creating with objects to avoid polluting the global scope.
1// Construct or Import Namespace
2var WilderMinds = WilderMinds || {};
3WilderMinds.currentTime = function() {
4 return new Date();
5};
Anonymous self-executing functions: protects the global namespace by function scope All Together: Namespaces and Anonymous Self-Executing Functions
1(function(ns) {
2 var currentDate = new Date();
3 ns.currentTime = function() {
4 return currentDate;
5 };
6})(window.WilderMinds = window.WilderMinds || {});
OOP in Javascript
Javascript also support OOP paradiam.
Inheritance
1var proto = {
2 sentence: 4,
3 probation: 2
4};
5
6var Prisoner = function (name, id) {
7 this.name = name;
8 this.id = id;
9};
10
11Prisoner.prototype = proto;
12var firstPrisoner = new Prisoner('Joe', '12A');
13var secondPrisoner = new Prisoner('Sam', '2BC');
Object.Create can also do the same thing
Javascript also has prototype chain. proto
proto is the actual object that is used in the lookup chain to resolve methods, etc. prototype is the object that is used to build proto when you create an object with new().
'Class' in Javascript
Closures can make properties private
1funciton Customer(name, company) {
2 //public
3 this.name = name;
4 this.company = company;
5
6 // private
7 var mailServer = 'mail.google.com';
8
9 this.sendEmail = function(email) {
10 sendMailViaServer(mailServer);
11 };
12}
Static Members
1function Customer(name, company) {
2 this.name = name;
3 this.company = company;
4}
5Customer.mailServer = 'mail.google.com';
Sharing a function
That way each instance doesn't have it's own copy
1Customer.prototype.send = funciton(email) { … }
Basic inheritance with the Prototype object
1function Cow(color) {
2 this.color = color;
3}
4Cow.prototype = new Animal('Hay');
5
6var c = new Cow('White');
7c.feed();
8var test = c instanceof Animal; // true
9var test2 = c instanceof Cow; // true
Can Fake Abstract Classes with some caveats
1var Animal = {
2 foodType: 'None',
3 feed: function() {
4 log('fed the animal: ' + this.foodType);
5 }
6};
7var a = new Animal(); //Fails (not a constructor)
Object Reflection
Property Syntaxes
- Dot syntax: cust.name
- Bracket Syntax: cust["name"]
Enumerating members: simplest version of reflection
1var cust = {
2 name: 'Shawn',
3 'company name': 'Wilder Minds',
4 sendMail: function() { … }
5};
6for (var prop in cust) {
7 alert(prop);
8 alert(cust[prop]);
9}
10
11var has = cust.hasOwnProperty('name');
12var isEnum = cust.propertyIsEnumerable('name');
Extension methods
prototype can be used to add extension methods Add to existing type's prototype
1Array.prototype.calculateCount = function() {
2 return this.length;
3};
4var a = ['one', 'two'];
5var count = a.calculateCount();
Written by Binwei@Trondheim