JavaSript高级程序设计-第四章学习笔记

2018-01-22  本文已影响0人  一包

4.1基本类型和引用类型的值

ECMASript变量可能包含两种不同数据类型的值

graph LR
ECMAScript变量-->基本类型值
ECMAScript变量-->引用类型值

4.1.1动态的属性

  1. 对引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法
  2. 对基本类型值,我们不能给其添加属性(虽然添加了不会导致错误),如下,当我们访问添加的属性,会发现该属性不见了
var name="Mike";
name.age=27;
alert(name.age); //undefined

4.1.2复制变量值

  1. 复制基本类型值:会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,复制后的值是原来值的一个副本,此后这两个变量可以参与任何操作而不会相互影响
  2. 复制引用类型的值:同样会复制,但与上面不同是这个值的副本实际上是一个指针,而这个指针指向储存在堆内存中的一个对象。此后,两个变量实际上将引用同一个对象,改变其中一个变量,会影响另一个。如下。
var obj1=new Object();
var obj2=obj1;
obj1.name="JJ";
alert(obj2.name); //JJ

4.1.3传递参数

  1. 向参数传递基本类型的值时,被传递的值会复制给一个局部变量(即命名参数),如下:
function addTen(num){
    num+=10;
    return num;
}
var count=20;
var result=addTen(count);
alert(count); //20,没有变化
alert(result); //30

假如num是按引用传递,则count的值将变成30,从而反映内部的修改,而实际并不是,参数是按值传递。

  1. 向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数外部,如下:
function setName(obj){
    obj.name="jj";
}
var person=new Object();
setName(person);
alert(person.name); //jj

可能有人会认为,在局部作用域修改的对象会在全局作用域反映出来,则说明参数是按引用传递,如下证明对象是按值传递:

function setName(obj){
    obj.name="jj";
    /*增加两段代码*/
    obj=new Object();
    obj.name="gg";
}
var person=new Object();
setName(person);
alert(person.name); //jj

如果person是按引用传递,则person会自动修改为指向name属性值为“gg”的新对象,而结果不是,说明即使函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当函数内部重写obj时,这个变量引用的就是一个局部对象了,这个局部对象会在函数执行完毕立即被销毁。

4.1.4检测类型(学习第六章再看)


4.2执行环境及作用域

执行环境
作用域
var color="blue";
function changeColor(){
    var anotherColor="red";
    
    function swapColors(){
        var tempColor=anotherColor;
        anotherColor=color;
        color=tempColor;
        //局部作用域中定义的变量可以在局部环境中与全局变量互换使用
        //这里可以访问color,anothercolor,tempColor;
    }
    //这里可以访问color,anotherColor
}
//这里只能访问color,changeColor();
  1. 以上代码涉及三个执行环境:全局环境,changeColor()的局部环境和swapColors()的局部环境。
graph LR
window-->color
window-->changeColor

changeColor-->anotherColor
changeColor-->swapColors
swapColors-->tempColor

  1. 内部环境可以通过作用域链访问所有外部环境,外部环境不能访问内部环境的任何变量和函数。
  2. swapColors()的作用域链包含三个对象:swapColors()的变量对象,changeColor()的变量对象和全局变量对象。(swapColors()的内部可以访问其他两个环境中的所有变量,因为那两个环境是它的父执行环境;)
  3. changeColor()的作用域链包含两个对象
    它自己的变量对象和全局变量对象。(不能访问swapColors()的环境;)

4.2.1延长作用域链(看不懂)

4.2.2没有块级作用域

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

以上代码,如果在c,c++或java(有块级作用域),color会在if语句执行完毕后被销毁。但在js中,if语句中的变量声明会将变量添加到当前的执行环境(这里是全局环境中),==使用for语句时要牢记这一差异==,如:

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

对有块级作用域的语言,for语句初始化变量的表达式所定义的变量,只会存在于循环的环境中。而对于js,由for语句创建的变量i即使在for循环执行结束后,也依旧会存在于循环外部的执行环境中。

  1. 声明变量
function add(num1,num2){
    var sum=num1+num2;
    return sum;
}
var result=add(10,20); //30
alert(sum); //由于sum不是有效变量,因此导致错误

如果省略var关键字,那么当add()执行完毕后,sum也将可以访问到,因为sum添加到了全局环境:

function add(num1,num2){
    sum=num1+num2;
    return sum;
}
var result=add(10,20); //30
alert(sum); //30
  1. 查询标识符
var color="blue";
function getColor(){
    return color;
}
alert(getColor()); //"blue",在全局环境中找到
var color="blue";
function getColor(){
    var color="red";
    return color;
}
alert(getColor()); //"red",在局部环境中找到

4.3垃圾收集(引用计数?)

  1. 4.3.1标记清除:JavaScript 中最常用的是垃圾收集方式是标记清除( mark-and-sweep )。当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
  2. 4.3.2引用计数:通过跟踪每个值被引用的次数来清除所占用的内存。

Author:YY

Date:2017.7.11

上一篇 下一篇

猜你喜欢

热点阅读