Showing posts with label JavaScript is Different. Show all posts
Showing posts with label JavaScript is Different. Show all posts
Saturday, July 19, 2014
08 - Comparison and Type Conversion
There are two
comparison operators in JavaScript. One is ==, and the other is ===. The
difference of these two operators is about type conversion. If two values in
different types are compared with ==, they will be converted into the same type
first and then compared. There is no type conversion when values are compared
with ===.
Type Conversion with ==
Let's discuss how
types are converted when they are compared with == one by one. The first type is Boolean values false and
true. When one operand of the == operator is a Boolean value and the other
operand is an integer, the Boolean value false is converted to 0, and true is
converted 1. When one operand of the == operator is a Boolean value and the
other operand is a string, the Boolean value false is converted to
"0", and true is converted "1", as demonstrated below:
console.log(false == 0); // true console.log(true == 1); // true console.log(true == 3); // false console.log(false == "0"); // true console.log(true == "1"); // true
When one operand of
the == operator is a string and the other operand is an integer, the string
will be converted to an integer value. Therefore, "3" == 3 gets true,
as shown below:
console.log("3" == 3); // true
When a string is
compared with a Boolean value, both an empty string and "0" are converted to false, "1" converted to true. Any other strings can neither converted to true, nor false.
console.log("0" == false); // true
console.log("" == false); // true
console.log("1" == true); // true
console.log("2" == true); // false
console.log("2" == false); // false
console.log("true" == true); // false
console.log("false" == false); // false
It becomes complex
when a string is used as a condition in an if expression. In such cases, only
an empty string is treated as false, and all others are treated as true:
var valueFunction = function(name, str) {
if(str) {
console.log(name, "is true");
}
else {
console.log(name, "is false");
}
}
valueFunction("Empty string", ""); // Empty string is false
valueFunction("0", "0"); // 0 is true
valueFunction("1", "1"); // 1 is true
valueFunction("2", "2"); // 2 is true
Two special values
null and undefined are equal to each other when compared with the == operator,
but they are not equal to any other values:
console.log(null ==
undefined); // true
console.log(null == undefined); // true console.log(null == false); // false console.log(undefined == false); // false console.log(null == 0); // false console.log(undefined == 0); // false console.log(null == ''); // false
Even null and
undefined are not equal to the Boolean value false, they are treated as false
when they are used as conditions in if expressions:
var valueFunction = function(name, value) {
if(value) {
console.log(name, "is true");
}
else {
console.log(name, "is false");
}
}
valueFunction("undefined", undefined); // undefined is false
valueFunction("null", null); // null is false
The behavior of NaN
is also quite special, which does not equal to any values, including NaN
itself:
console.log(NaN == 0); // false console.log(NaN == 'NaN'); // false console.log(NaN == NaN); // false
When an instance of
a reference type is compare with a value type, the instance will be converted
by invoking valueOf method:
var a = "hello world";
var b = new String("hello world");
console.log(a == b); // true
When two instances
of reference types are compared, they equal to each other only when they are
the identical instance:
var a = [1, 2, 3]; var b = [1, 2, 3]; console.log(a == b); // false var c = a; console.log(a == c); // true;
Equality
with the == operator is reflective, but not transitive. That's to say, if A == B, B == A. However, if A == B and B == C,
it's not necessary A == C. The following is an example:
console.log("0" == 0); // true
console.log(0 == ""); // true
console.log("0" == ""); // false
No Type Conversion with ===
When two values are
compare with the operator ===, they equal to each other only when they are in
the same type and their value are identical. That's to say, no type conversion
is involved in === comparison. When two values are not in the same type, they
don't equal to each other when they are compared with the === operator. Let's
take the following piece of code as an example:
console.log(false === 0); // false
console.log(true === 1); // false
console.log("3" === 3); // false
var a = "hello world";
var b = new String("hello world");
console.log(a === b); // false
console.log(null === undefined); // false
All pairs of values
are not equal when compared with the operator ===, and two values in a pair
have different types. As we discussed before, every pair of values are equal
when compare with the operator ===.
Labels:
Javascript
,
JavaScript is Different
,
Types
Friday, July 11, 2014
07 - Arrays
Array Construction
Arrays can be
created by invoking the constructor Array:
var array1 = new Array(); array1[0] = "a"; array1[1] = 1; array1[2] = true; console.log(array1); // ["a", 1, true]
Notice that elements
in an array are not necessary to have the same type. Three elements in array1
in the code above are a string, number, Boolean value correspondingly.
There is also a more
concise way to construct an array, as shown below:
var array2 = ["a", 1, true]; console.log(array2); // ["a", 1, true]
Elements
are surrounded by a pair of square brackets during the array construction.
Iterating Array Elements
Some elements inside
an array may be undefined. When an array with some undefined elements is
traversed with different strategies, the results might be different. Let's take
the following piece of code as an example:
var array = [0, 1];
array[4] = 4;
console.log("length:", array.length); // length: 5
for(var index = 0; index < array.length; ++index) {
console.log(index + ":", array[index]);
}
// Output:
// 0: 0
// 1: 1
// 2: undefined
// 3: undefined
// 4: 4
for(index in array) {
console.log(index + ":", array[index]);
}
// Output:
// 0: 0
// 1: 1
// 4: 4
// name: linear increasing
array.forEach(function(value, index) {
console.log(index + ":", value);
});
// Output:
// 0: 0
// 1: 1
// 4: 4
Firstly, an array is
initialized with two numbers 0 and 1. The element with index 4 is set as 4. Now
array has 5 elements, but the two elements with index 2 and 3 are undefined
yet. When the array is traversed in the first for loop, both defined and undefined
elements are listed. However, when the array is traversed in the for…in loop,
only defined elements are listed.
The difference between the for...in loop and the method forEach is that for...in loop also iterates the property of the array, but the forEach does not. A property name is added into the array, and it is printed out when the array is iterated with for...in loop, but not with the forEach method.
The difference between the for...in loop and the method forEach is that for...in loop also iterates the property of the array, but the forEach does not. A property name is added into the array, and it is printed out when the array is iterated with for...in loop, but not with the forEach method.
Basic Array Functionalities
There are many
predefined array methods, which fulfill basic array functionalities. The code
below shows some most frequently used methods:
var array1 = [1, 2];
var array2 = [4, 3, 2];
var array3 = [5, 6];
var array4 = array1.concat(array2, array3);
console.log(array4); // [1, 2, 4, 3, 2, 5, 6]
var index1 = array4.indexOf(2);
var index2 = array4.lastIndexOf(2);
console.log(index1); // 1
console.log(index2); // 4
var str = array4.join("; ");
console.log(str); // 1; 2; 4; 3; 2; 5; 6
var array5 = array4.slice(2, 5);
console.log(array5); // [4, 3, 2]
array4.sort();
console.log(array4); // [1, 2, 2, 3, 4, 5, 6]
The method concat
concatenates two array into a longer one. The methods indexOf and lastIndexOf
get the first and last index of the given element out of an array respectively.
The method join convert an array into a string with the given delimiter between
elements. The method slice gets a substring out of a string. As the name
suggests, the method sort is used to sort an array.
Sort
Sometimes the result
of the method sort is surprising. The following is an example
var array = [4, 20, 10, 7]; array.sort(); console.log(array); // [10,20,4,7]
After the array with
numbers 4, 20, 10, and 7 gets sorted, the result is unexpected. That is because
the default criteria to sort in alphabetical order. If the desired behavior is
to sort based in numeric order, we have to define our own callback function to
compare elements in the array:
var array = [4, 20, 10, 7];
function compare(a, b) {
return a - b;
}
array.sort(compare);
console.log(array); // 4,7, 10, 20
Arrays as Stacks
Stacks are not
defined explicitly in JavaScript. Fortunately, arrays can be used as stacks,
because the methods push and pop are defined on arrays:
var array = [1, 2]; array.push(3); // [1, 2, 3] console.log(array); array.push(4); // [1, 2, 3, 4] console.log(array); console.log(array.pop()); // 4 console.log(array.pop()); // 3 console.log(array); // [1, 2]
As expected, the
method push appends an element into the end of an array, and the method pop
removes the last element of an array.
Similarly, there are
two more methods to manage elements at the beginning of an array. The method
unshift inserts at the beginning of an array, and the method shift deletes the
first element:
var array = [1, 2]; array.unshift(3); console.log(array); // [3, 1, 2] array.unshift(4); console.log(array); // [4, 3, 1, 2] console.log(array.shift()); // 4 console.log(array.shift()); // 3 console.log(array); // [1, 2]
Arrays as Queues
If we always insert
elements into an array with the method push, and delete elements with the
method shift, elements are in the first in first out order, as demonstrated
below:
var queue = [1, 2]; queue.push(3); // [1, 2, 3] console.log(queue); queue.push(4); // [1, 2, 3, 4] console.log(queue); console.log(queue.shift()); // 1 console.log(queue.shift()); // 2 console.log(queue); // [3, 4]
Delete, Replace, and Insert Elements
There is a more
powerful method to insert, delete, and to replace elements at any places inside
an array, which is named as splice. Where there only two parameters are passed
into the method splice, the method is used to delete elements from an array:
var array1 = [1, 2, 3, 4, 5, 6, 7]; array1.splice(3, 2); console.log(array1); // [1, 2, 3, 6, 7] var array2 = [1, 2, 3, 4, 5, 6, 7]; array2.splice(-3, 2); console.log(array2); // [1, 2, 3, 4, 7]
The first parameter
stands for the starting index of elements to be deleted. If it is a negative
number, the index starts from the right side of an array. For example, the
starting index 3 in the array [1, 2, 3, 4, 5, 6, 7] is in value 4, and the
starting index -3 in the array is in 5.
The second parameter
is for the number of elements to be deleted. When two elements starting from
the index 3 are delete from the array [1, 2, 3, 4, 5, 6, 7], it becomes [1, 2,
3, 6, 7]. And it becomes [1, 2, 3, 4, 7] when two elements are deleted starting
from the index -3.
If there are more
than two parameters are passed into the method splice, it is used two replace
elements. For instance:
var array1 = [1, 2, 3, 4, 5]; array1.splice(2, 2, -1); console.log(array1); // [1, 2, -1, 5] var array2 = [1, 2, 3, 4, 5]; array2.splice(2, 2, -1, -2); console.log(array2); // [1, 2, -1, -2, 5] var array3 = [1, 2, 3, 4, 5]; array3.splice(2, 2, -1, -2, -3); console.log(array3); // [1, 2, -1, -2, -3, 5]
In the code above,
two elements starting from the index 2 (elements with value 3 and 4) are
replaced with elements in the parameter list starting from the index 2
(negative parameters in the examples above).
If we are going to
insert elements into an array, the second parameter of the method splice should
be 0. The following is an example to insert elements:
var array = [1, 2, 3, 4, 5]; array.splice(2, 0, -1, -2); console.log(array); // [1, 2, -1, -2, 3, 4, 5]
In the code above,
two negative numbers -1 and -2 are inserted into the array [1, 2, 3, 4, 5],
starting from the index 2.
Labels:
Javascript
,
JavaScript is Different
,
Types
Tuesday, July 8, 2014
06 - Strings
In JavaScript,
characters are also strings with length 1, as demonstrated below:
var character = 'a'; var string = "abcdefg"; console.log(typeof(character)); // string console.log(typeof(string)); // string
The code above also shows that a string can be
inside both single and double quotes. Additionally, strings inside single
quotes can have double quotes, and strings inside double quotes can have single
quotes vice versa, as the strings str1 and str2 in the following piece of code.
If you would like to use double quotes in a string surrounded by double quotes,
an escape character "\" should be inserted before the double quotes
in the string. Strings with single quotes are similar. Please take the strings
str3 and str4 in the code below as examples:
var str1 = "I can't wait to learn JavaScript."; var str2 = 'He said: "JavaScript is so good".'; console.log(str1); // I can't wait to learn JavaScript. console.log(str2); // He said: "JavaScript is so good". var str3 = 'I can\'t wait to learn JavaScript.'; var str4 = "He said: \"JavaScript is so good\"."; console.log(str1 == str3); // true console.log(str2 == str4); // true
Strings can be split
into multiple lines, when a ending character "\" at the each line, as
show below:
var str = "<div> \ Learning JavaScript \ </div>"; console.log(str); // <div> Learning JavaScript </div>
Strings in
JavaScript are immutable. We could get a character from a string based on its
index, but can modify it:
var str = "hello"; console.log(str[1]); // e str[1] = 'a'; console.log(str[1]); // e
The character with
index 1 in the string "hello" is "e". If we try to modify it to "a", the
string keeps unchanged.
The type String has
many methods to modify strings. The modified contents is accessible in the
returned values, but the original strings are not modified, as demonstrated in
the following piece of code:
var str1 = "hello";
var str2 = str1.replace("h", "H");
console.log(str1); // hello
console.log(str2); // Hello
The original value
of the string str1 is "hello". When we try to replace the
"h" with "H" in the string, str1 keeps unchanged, and the
modified contents "Hello" is in the returned value which is
referenced by str2.
Labels:
Javascript
,
JavaScript is Different
,
Types
Saturday, July 5, 2014
05 - Numbers
There are no
differences between integers and floats in JavaScript. All numeric values are
represented in 64-bit floats.
var intValue = 2; var floatValue = 3.6; console.log(typeof(intValue)); // number console.log(typeof(floatValue)); // number
As demonstrated in
the code above, both the integer value 2 and the float value 3.6 are in the
type of number.
Numbers in JavaScript can be large as ±1.7976931348623157×10^308
(Number.MAX_VALUE), and as little as ±5 × 10^−324 (Number.MIN_VALUE). Since number values are in a very
wide range, it is not necessary to handle the big-data issue specially in most cases.
var bigNumber = Math.pow(2, 100); console.log(bigNumber); // 1.2676506002282294e+30
It is quite easy to
calculate big values without considering the overflow issue. As shown in the
code above, it calculates 2 to the power of 100 in a line of code.
When overflow
occurs, there are no errors thrown. The code with overflow executes normally,
and returns predefined values. The following is an example:
try
{
var tooBig = Math.pow(10, 400);
console.log("Finish without error. The returned value is:", tooBig);
}
catch(e)
{
console.log("A error was caught.");
}
// Output:
// Finish without error. The returned value is: Infinity
When overflow
occurs, the predefined special value Infinity is returned if the result is
positive. Similarly, it returns -Infinity when overflow occurs with a negative
result.
Moreover, no errors
will be thrown when a number is divided by 0, as shown below:
var result1 = 1 / 0; var result2 = -1 / 0; console.log(result1); // Infinity console.log(result2); // -Infinity
Another special
value NaN (No a Number) is returned when 0 is divided by 0, or non-numeric
values are calculated:
var result1 = 0 / 0; console.log(result1); // NaN var result2 = 5 / "hello"; console.log(result2); // NaN
Labels:
Javascript
,
JavaScript is Different
,
Types
04 - Functions as Objects
Functions in
JavaScript are objects, so functions can be assigned to variables, passed to
other functions as parameters, returned from other functions. Additionally, functions have their own properties.
Functions Assigned to Variables
Functions in
JavaScript can be defined and assigned to variables, and then invoked via the
variables, as shown in the following example:
var add = function(a, b) return a + b; }; console.log(typeof(add)); // function console.log(add(1, 2)); // 3
An anonymous is
defined, and then is assigned to variable name add. Now the variable name add is referenced to
the function, and can be invoked as the function.
Functions as Parameters
Functions can also
be passed to other function as parameters, as shown below:
function calculate(operator, a, b) {
return operator(a, b);
};
function add(a, b) {
return a + b;
};
console.log(calculate(add, 2, 5)); // 7
console.log(calculate(multiply, 2, 5)); // 10
The first parameter
of the function calculate is a function. When the function add is passed as the
parameter, it adds two numbers. Otherwise it multiplies two numbers if the
function multiply is passed.
When a function is
passed as a parameter to another function, it is called a callback function.
There are many APIs take callback functions as parameters, which provide much
flexibilities to use the APIs. For example, we could pass a callback function
to add up the elements of an array to the forEach method of an array, as shown
below:
function sum(nums) {
var total = 0;
nums.forEach(function(num) {
total += num;
});
return total;
};
var nums = [1, 2, 3, 4];
console.log(sum(nums)); // 10
An anonymous
function, which adds an element of the array to the variable total, is passed to the method
forEach. When the method forEach is invoked with the callback function, the
total sum of all elements in the array is added up.
Functions as Return Values
Similar to other
kinds of objects, functions can also be returned from functions. As shown in
the following piece of code, the function addFunc returns a function, which
adds two numbers:
function addFunc(a, b) {
return function() {
return a + b;
}
};
var func = addFunc(3, 5);
console.log(typeof(func)) // function
console.log(func()); // 8
The variable func
references to the returned function of addFunc, so the type of func is a
function. Additionally, the function can be invoked as normal functions.
Functions with Properties
Objects have their
properties. So Functions. We add a property count to the function test below:
test.count = 0;
function test() {
test.count++;
console.log(test.count);
}
test(); // 1
test(); // 2
test(); // 3
When the function
test is invoked, the property count increases. We could implement the same
functionalities with another global variable. However, the property count has
some advantages, because it will not conflict with other variables. That's to
say, it is OK for us to define a global count, since it will not conflict with
the property test.count.
Similarly,
functions can be viewed as arrays, and they can have their own elements. As we know, it is quite time-consuming
to calculate the Fibonacci sequence
recursively, if without caching. We may cache the intermediate results in the function, as listed below:
function fibonacci(n) {
if(fibonacci[n - 2] === undefined) {
fibonacci[n - 2] = fibonacci(n - 2);
}
if(fibonacci[n - 1] === undefined) {
fibonacci[n - 1] = fibonacci(n - 1);
}
return fibonacci[n - 1] + fibonacci[n - 2];
}
fibonacci[0] = 0;
fibonacci[1] = 1;
console.log(fibonacci(10)); // 55
console.log(fibonacci(50)); // 12586269025
The function
Fibonacci is also an instance of array. When a value of the Fibonacci sequence
is calculated, it is cached into the array. It is more efficient to calculate
next values based on the cached values.
Labels:
Function
,
Javascript
,
JavaScript is Different
Wednesday, July 2, 2014
03 - IIFE and Modules
Current there are
neither classes nor namespaces in JavaScript. However, we couldmodularize JavaScript code with the
Immediately Invoked Function Expression (IIFE).
Firstly, let's
define a variable and two functions as the following, without modularization:
var count = 0;
function print()
console.log(count);
}
function increase()
{
count++;
}
In the code above,
the function names print and increase are available globally, and it is highly
possible for them to conflict with other variable or function names. Therefore,
it is necessary to protect them inside a module.
The first
modularization solution is to utilize objects. The variable and functions
become members of an object, as listed below:
var module = new Object({
count: 0,
print: function() {
console.log(this.count);
},
increase: function() {
this.count++;
}
});
The problem with
this solution is that the member variable count is accessible outside the
object, which usually is not our purpose because we would like to hide data but
just expose interfaces. The following code shows how to modify the member
variable count:
module.count = 5; module.increase(); module.print(); // 6
The member variable
count is initialized as 0 firstly. It is increased to 6 then, so the output is
6.
A better solution to
modularize is to utilize IIFE. The code above can be refined into the following
section of code:
var module = function() {
var count = 0;
var print = function() {
console.log(count);
};
var increase = function() {
count++;
};
return {
print: print,
increase: increase
};
}();
In the code above,
count is a local variable inside the anonymous function, and it is inaccessible
outside the function. Therefore, only the interfaces are exposed but the
details are hidden.
We could demonstrate
that the variable count is inaccessible with the following piece of code:
module.count = 5; module.increase(); module.print(); // 1
Even though we try
to set module.count as 5, it actually inserts a property count with value 5
into the object returned by the anonymous function, but the variable count
inside the function keeps unchanged. After the variable count increases, it
becomes 1, so the output is 1, instead of 6.
Labels:
Function
,
Javascript
,
JavaScript is Different
Saturday, January 11, 2014
02 - Parameters and Arguments
The Number of Parameters and Arguments
The term parameter is used to describe the names for values that are expected to be supplied. The term argument is used for the values provided for each parameter. In many languages, the number of parameters and the number of arguments should be same. However, JavaScript behaves in a different way. The number of parameters declared in a JavaScript function signature can be different from the number of arguments passed to the function when it is invoked.If some arguments are not passed into a function when it is invoked, the values of the missing arguments are undefined. Let's take a look at the following sample code:
function greeting(name, greetingWord) {
if (greetingWord === undefined) {
greetingWord = "Hi";
}
console.log(greetingWord + ", " + name);
}
greeting("Harry", "Hello"); // Hello, Harry
greeting("Peter"); // Hi, Peter
A function greeting with two parameters is declared firstly, then it is invoked twice. When two arguments are passed, they are concatenated and logged into the console. It's more interesting when there is only one argument "Peter" passed into the function. Arguments match parameters from left to right. If some parameters are not matched to passed arguments, they remain undefined. Therefore, the parameter name becomes "Peter", and greetingWord becomes undefined. Inside the function, a default value "Hi" is assgined when greetingWord is undefined, so "Hi, Peter" is logged to the console eventually.When the number of arguments passed into the function when it is invoked is more than the number of parameter in the function declaration, the unmatched arguments will be discarded.
For exapmle, a function add with two parameters is declared in the following sample code, and then three arguments are passed when it is invoked:
function add(num1, num2) {
return num1 + num2;
}
console.log(add(1, 2, 3)); // 3
Again, arguments match parameters from left to right. If some arguments don't match any parameters, they are not in use in the function. Therefore, num1 becomes 1, and num2 becomes 2 in the code above, and the returned sum is 3.Arguments Property of Functions
Each function is an object in JavaScript, so a function can have its own properties. One of the interesting properties is arguments, which contains all the arguments passed into the function when it's invoked. Even more arguments are passed into function, all of the arguments are accessible via the arguments property.The following sample code shows how to use the arguments property:
function add() {
var sum = 0;
for(var i = 0; i < arguments.length; ++i) {
sum += arguments[i];
}
return sum;
}
console.log(add(1, 2, 3)); // 6
A function add is declared with no explicit parameters. It is then invoked with three arguments, which are 1, 2, and 3 respectively. These argument are not acutally discarded, but remain accessible via the arguments property. The arguments property is an object, which looks like an array, and have its own property length and elements are indexed beginning from 0. Therefore, the returned sum is 6, which equals to 1+2+3.No Overloading
Many programming languages have the overloading mechanism, which allows many functions are defined with same name but difference number of parameters. However, there is no overloading in JavaScript, because a function can be invoked with difference number of arguments. If multiple functions with the same name but different number of parameters are defined, the last function will overwrite the preceding ones, as shown in the sample code below:function add(num1, num2, num3) {
return num1 + num2 + num3;
}
function add(num1, num2) {
return num1 + num2;
}
console.log(add(1, 2, 3)); // 3
In the code above, a function named add is defined with three parameters are defined at first, and then another function also named add is defined with two parameters. The latter function overwrite the former one. When the function add is invoked with three arguments, only two arguments passed into the second function and the last argument 3 is not in use, so the returned value is 3 which is 1 plus 2.Property arguments.callee
The arguments property of functions is an object, and it has its own properties. Besides arguments.length, another interesting property is arguments.callee, which points to the container function of arguments.The property arguments.callee is widely used in recursive function. Recursive functions call themselves, usually through function names. There are anonymous functions in JavaScript, which don't have names. How to define recursive functions when they are anonymous? A solution is to name them explicitly, and the other one is to utilize arguments.callee. Let's have a look at the following sample code:
var threeToPowerOfTen = (function (exponent) {
if (exponent === 1) {
return 3;
}
return 3 * arguments.callee(exponent - 1);
})(10);
console.log(threeToPowerOfTen); // 59049
In order to get the value of 3 to power of 10, an anonymous function is defined which is also recursive. Since an anonymous function doesn't have a name, it can't be recursively invoked via its name. In the code above, the property arguments.caller is utilized to invoke the anonymous function. That's to say, the property arguments.callee makes it possible to define recursive anonymous functions.The property arguments.callee has its own value even a recursive function has a name. When a function is recursively invoked via its name, the recursive functionality couples with its name. The function name is just a variable name, and it can be assigned to other functions, or even other object. When the function is assign another meaning, the recursive functionality breaks. For example:
function power(base, exponent) {
if (exponent == 1) {
return base
}
return base * power(base, exponent - 1);
}
var realPower = power;
power = "More power, more powerful";
console.log(realPower(2, 3));
// Result:
// TypeError: string is not a function
A recursive function power is defined in the code above. It's recursively invoked via its name power inside the function. Following the function declaration, the function is assigned to another variable name realPower, and then power is assigned to a string. Finally the function is invoked which has can be referenced with the name realPower, but its functionality breaks. Inside the function, the it recursively invokes itself via the name power, but power now is not a function anymore. Therefore, an error is thrown complaining that a string is not a function.In order to decouple the recursive functionality and the function name, the function can be replaced with argument.callee which also points to the function. Therefore, the recursive function can be revised into the following code:
function power(base, exponent) {
if (exponent == 1) {
return base
}
return base * arguments.callee(base, exponent - 1);
}
var realPower = power;
power = "More power, more powerful";
console.log(realPower(2, 3)); // 8
In the revised code, the function recursively call itself via arguments.call. Therefore, even when the name power is assigned to a string, the recursive functionality remains.
Labels:
Function
,
Javascript
,
JavaScript is Different
Wednesday, January 8, 2014
01 - Define Functions
Two Ways to Define Functions
There are two different ways to define functions in JavaScript. The first way is to name explicitly, as shown below: function helloWorld() {
console.log("Hello world.");
}
helloWorld();
// Output:
// Hello world.
In the code above, a function renamed helloWorld is defined. When it's invoked, a line of "Hello world." is logged into the console.
We can also define an anonymous function. Since a function in JavaScript is also an object, the anonymous function can be assigned to a variable name. The function then can be invoked via the variable name. The following is an example:
var helloWorld = function () {
console.log("Hello world.");
}
helloWorld();
// Output:
// Hello world.
There is a striking differences between the two ways to define functions. An explicitly named function can be invoked ahead of its definition, as shown in the example below:
helloWorld();
function helloWorld() {
console.log("Hello world.");
}
// Output:
// Hello world.
The function helloWorld is defined when the code is loaded, so it can be invoked even though the function call appears ahead of its definition.
The same scenario does not work for anonymous functions. For example, an error will be thrown in the sample below:
helloWorld(); // TypeError: undefined is not a function
var helloWorld = function () {
console.log("Hello world.");
}
The anonymous function gets defined when the code is loaded, but the variable helloWorld won't be defined (be assigned to the anonymous function) when the line of code get executed. Therefore, when we try to call the function via the variable name helloWorld, the value of the variable is still undefined.
Immediately Invoked Function Expression
A function can be invoked immediately when it's defined. The following is an example:(function() {
console.log("Hello world.");
})();
// Output:
// Hello world.
In the code above, an anonymous function is defined. There is a pair of parentheses after the function definition, which indicate that the function is invoked immediately.
An immediately invoked function expression is a widely used design pattern in JavaScript. The singleton pattern can be implemented based on an immediately invoked function. The following is an exapmle:
Immediately invoked functions can also be utilized to keep private variables inaccessible. More details will be discussed in other posts later.
var Singleton = (function() {
function SingletonClass() {
}
var instance = new SingletonClass();
return {
getInstance: function() {
return instance;
}
};
})();
var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();
console.log(instance1 === instance2);
// Output:
// ture
Inside the outer anonymous function, a constructor SingletonClass is defined, and an instance of SingletonClass is created. In the returned instance of the anonymous function, an instance of SingletonClass is returned in the member function getInstance. Notice that the constructor SingletonClass is defined inside an anonymous function, no one else can invoke the constructor to create new instances.
Outside the anonymous function, the returned instance is assigned to a variable name Singleton, then the unique instance of SingletonClass can be accessible via the function Singleton.getInstance. If the function Singleton.getInstance is invoked for multiple times, only one instance of SingletonClass will be returned, so instance1 and instance2 are identical. It demonstrates that requirements of the singleton pattern have been fulfilled.
Labels:
Function
,
JavaScript is Different
Subscribe to:
Posts
(
Atom
)