Code

显示标签为“JavaScript”的博文。显示所有博文
显示标签为“JavaScript”的博文。显示所有博文

2011年10月27日星期四

Wrapper Objects & Object Reference

In JavaScript, primitive types behave like objects. They use dot expression to access certain methods. For example

var str = "abcd";
console.log(str.length); //4


But for object, every property is mutable. If we change the length to 10, it should be changed to 10. However, this is not the case.

str.length =10;
console.log(str.length); //4


This is because, primitive types don't actually have methods or properties. The access of those methods or properties invokes creation of their Wrapper Objects, which are String(), Numeric() and Boolean(). So when str.length is evaluated, something like this line is invoked.

var tmp_str = new String(str); return tmp_str.length; delete tmp_str;

After tmp_str is returned, it is destroyed. This is a wrapper object. It abstract the actual behaviours of primitive types, making it like a read-only object. Attempting to add/modify method or properties of primitive data types results in no effects. (because changes are only made to wrapper objects which are destroyed after access)

Another thing I learned about JS today is that, all objects in Javascript are "pass by reference". All primitive types are "pass by value".
Array are objects. so
var a=[1,2,3];
var b=a;
a[2]=0;
console.log(b); //[1,2,0]

So if there is a need to copy an independent object from another object, we have to write our own copy function.

function copyArr(a) {
    var b=[];
    for (var i=0;i<a.length;i++) {
        b[i] = a[i];        
    }
    return b;
}
var a=[1,2,3];
var b=copyArr(a);
a[2]=0;
console.log(a); //[1,2,0]
console.log(b); //[1,2,3]

2011年10月25日星期二

JavaScript Closure

因为新工作的缘故这两天开始学习JavaScript。
一直在看David Flanagan的JavaScript: The Definitive Guide 6th Edition,收获颇丰。

以前在云风的博客上第一次看到closure这个词的时候就很好奇,但那篇介绍是以C作为例子,讲的也不是很清楚,所以一直都没搞懂closure这个东西。
现在读JavaScript,对这个closure算是有一定理解。
Closure 中文叫做闭包,在JavaScript里函数都是有闭包的特性。

理解闭包必须分两步:
1.JS里面函数是first-class function,就是说函数跟class是一个级别的。 函数可以直接赋值到变量上,它的类型为"function",这个变量可以直接用来invoke函数。
function test1() {
    console.log(1);
}
func_var = test1;
console.log(typeof func_var); //"function"
func_var(); // invoked test1 -> '1'

2.JS使用lexical scoping,也就是一个函数的scope在它define的时候就确定了,而不是在invoke的时候才确定。

function test2() {
    var b = 1;
    return function () {console.log(++b);};
} 
b = 10;  //无影响
test2()(); //2
test2()(); //2
func_var = test2();
func_var(); //2
func_var(); //3
func_var(); //4

可以观察到,如果直接从运行从test2那里得到的函数,得到的结果会一直都是2。因为,每次运行test2,一个新的context被建立,一个新的b在这个context里面被建立。每次返回的匿名函数被挂接在一个新的context里面,所以它使用的b的值一直都是1。
然而,将test2返回的函数赋值到func_var上的时候,被返回的匿名函数原本的context被保存,就像把这个context空间封闭住了,只有,这个匿名函数可以访问。所以每次这个func_var被运行的时候都会只用之前旧的b,它相当于这个函数的私有变量了。
这种closure使var b成为test2这个object的私有变量,把data hide起来,不受其他scope的影响。可以猜想,JS使用这种特性可以实现object-oriented programming。

PS: from SICP about first-class procedures
In general, programming languages impose restrictions on the ways in which computational elements can be manipulated. Elements with the fewest restrictions are said to have first-class status. Some of the ``rights and privileges'' of first-class elements are:
  • They may be named by variables.
  • They may be passed as arguments to procedures.
  • They may be returned as the results of procedures.
  • They may be included in data structures.
Lisp, unlike other common programming languages, awards procedures full first-class status. This poses challenges for efficient implementation, but the resulting gain in expressive power is enormous.

Javascript is like Lisp very much in this aspect.