《JS高级程序设计》Note2-Variables, Scope, and Memory

Working with primitive and reference values in variables

基本ss类型(primitive values) 有5种:Undefined, Null, Boolean, Number, and Strin 引用类型(Reference values) 在操作对象时,是通过引用访问的,而非直接操作对象。

Dynamic Properties (动态的属性)

对引用添加属性,如下

 
var person = new Object();
person.name = "Nicholas";
alert(person.name); //”Nicholas”

对基本类型添加属性,不会报错,但是并未真正能添加的属性。如下

 
var name = "Nicholas";
name.age = 27;
alert(name.age); //undefined

Copying Values (复制变量值)

复制基本类型,如下

 
var num1 = 5;
var num2 = num1;

复制之后,num1和num2是相互独立的,占有不同的空间,如下

num1 and num2

复制引用类型时,如下

 
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"

复制之后,obje1和obje2两个变量指向同一个对象,操作同一个地址的数据。如下图

num1 and num2

Argument Passing (传递参数)

访问变量有安值和按引用两种方式,而参数只能按值传递

为函数传递基本类型,很容易理解,如下

 
function addTen(num) {
    num += 10;
    return num;
}
                   
var count = 20;
var result = addTen(count);
alert(count); //20 - no change
alert(result); //30

为函数传递引用类型,如下面这个例子(有点类似Java语言)

 
function setName(obj) {
    obj.name = "Nicholas";
}
                   
var person = new Object();
setName(person);
alert(person.name); //”Nicholas”

看上面的例子,很容易理解为引用类型的参数传递,是按引用传递,其实不然

看下面的例子

function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
                   
var person = new Object();
setName(person);
alert(person.name); //”Nicholas”

这样理解,传递近来的obj和person是指向同一个Object对象的两个指针,之所以它们指向同一个对象,是因为赋值的作用 而当obj被赋予新的对象时,则和person不再指向同一个对象。

Determining Type (检测类型)

对基本类型进行类型检测,使用typeof,如下

var s = "Nicholas";
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object();
                   
alert(typeof s); //string
alert(typeof i); //number
alert(typeof b); //boolean
alert(typeof u); //undefined
alert(typeof n); //object
alert(typeof o); //object

在检测引用类型时,使用typeof只能检测出是Object类型,而我们想要检测出是属于哪种Object

于是我们用instanceof操作符,如下

alert(person instanceof Object); //is the variable person an Object?
alert(colors instanceof Array); //is the variable colors an Array?
alert(pattern instanceof RegExp); //is the variable pattern a RegExp?

使用instanceof检测一个基本数据类型是不是Object,始终返回false

使用typeof操作函数时,该操作符返回“function”, 使用typeof操作正则表达式时,部分浏览器返回”function”,部分返回”object”.

EXECUTION CONTEXT AND SCOPE (执行环境及作用域)

执行环境概念就是作用域,而作用域链,则是作用域的连接,其中内层的作用域能访问到外层作用域的数据。

其实这里的概念与其他语言的作用域很类似,看几个例子即可

var color = "blue";
                   
function changeColor(){
    var anotherColor = "red";
                   
    function swapColors(){
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        
        //color, anotherColor, and tempColor are all accessible here
    }
                   
    //color and anotherColor are accessible here, but not tempColor  

 swapColors();
}
                   
//only color is accessible here
changeColor();

如下图, window ,changeColor(),swapColor()及其各自下方的矩形,代表3个执行环境, 而其中的树状结构则代表作用域链。

num1 and num2

Identifi er Lookup (搜索标识符)

如下代码

var color = "blue";
                   
function getColor(){
    return color;
}
                   
alert(getColor()); //”blue”

该段代码中,对color的搜索过程如下

num1 and num2

如果子环境和父环境拥名字相同的变量,如下

var color = "blue";
                   
function getColor(){
    var color = "red";
    return color;
}
                   
alert(getColor()); //”red”

如果要返回全局变量中的color,则需要使用

return window.color;

Scope Chain Augmentation (延长作用域链)

延长作用域链的方法有两个

  • try-catch语句的catch块
  • with语句

此处主要讲解with语句,看下面例子

function buildUrl() {
    var qs = "?debug=true";
                   
    with(location){
        var url = href + qs; 
    }
                   
    return url;
}

注意两点 * with语句的功能类似于java中的静态引入,原本你要写location.href,现在只需要写href * with块中声明定义的变量,属于包含着with块的作用域中。(外一层可以访问,因为js中没有块作用域的概念)

No Block-Level Scopes (没有块级作用域)

如下代码

if (true) {
    var color = "blue";
}
                   
alert(color); //”blue”

再比如下代码

for (var i=0; i < 10; i++){
    doSomething(i);
}
                   
alert(i); //10

Variable Declaration (声明变量)

初始化变量时没有使用var声明,则该变量会自动成为全局变量

如下两段代码

function add(num1, num2) {
    var sum = num1 + num2;
    return sum;
}
                   
var result = add(10, 20); //30
alert(sum); //causes an error since sum is not a valid variable

如下:

function add(num1, num2) {
    sum = num1 + num2;
    return sum;
}
                   
var result = add(10, 20); //30
alert(sum); //30

不声明变量而直接初始化变量是一个错误的习惯

GARBAGE COLLECTION (垃圾收集)

垃圾收集有两种方式, * 标记清除,目前主流的方式 * 引用技术,会有循环引用的隐患