Javascript学习笔记-变量、做用域和内存问题

一、基本类型和引用类型的值

ECMAScript 变量可能包含两种不一样数据类型的值:基本类型值和引用类型值。前端

基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。浏览器

基本数据类型:Undefined、Null、Boolean、Number 和String。这5 种基本数据类型是按值访问的。函数

引用类型的值是保存在内存中的对象。与其余语言不一样,JavaScript 不容许直接访问内存中的位置,也就是说不能直接操做对象的内存空间。工具

(1)动态的属性

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

 以上代码建立了一个对象并将其保存在了变量person 中。而后,为该对象添加了一个名为name 的属性,并将字符串值"Nicholas"赋给了这个属性。性能

而后经过alert()函数访问了这个新属性。若是对象不被销毁或者这个属性不被删除,则这个属性将一直存在。优化

只能给引用类型值动态地添加属性,好比一下例子:spa

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

为字符串name 定义了一个名为age 的属性,并为该属性赋值27。但在下一行访问这个属性时,发现该属性不见了。指针

(2)复制变量值

若是从一个变量向另外一个变量复制基本类型的值,会在变量对象上建立一个新值,而后把该值复制到为新变量分配的位置上。code

若是从一个变量向另外一个变量复制引用类型的值时,一样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不一样的是,这个值的副本其实是一个指针,而这个指针指向存储在堆中的一个对象。复制操做结束后,两个变量实际上将引用同一个对象。所以,改变其中一个变量,就会影响另外一个变量。对象

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

 (3)参数传递

ECMAScript 中全部函数的参数都是按值传递的。

function addTen(num) {
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,没有变化
alert(result); //30
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"

 (4)检测类型

typeof 操做符是肯定一个变量是字符串、数值、布尔值,仍是undefined 的最佳工具。

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

在检测引用类型的值时,这个操做符的用处不大。

想知道它是什么类型的对象,使用instanceof 操做符。

result = variable instanceof constructor
alert(person instanceof Object); // 变量person 是Object 吗?
alert(colors instanceof Array); // 变量colors 是Array 吗?
alert(pattern instanceof RegExp); // 变量pattern 是RegExp 吗?

 全部引用类型的值都是Object 的实例。所以,在检测一个引用类型值和Object 构造函数时,instanceof 操做符始终会返回true。

若是使用instanceof 操做符检测基本类型的值,则该操做符始终会返回false,由于基本类型不是对象。

二、执行环境及做用域

执行环境定义了变量或函数有权访问的其余数据,决定了它们各自的行为。每一个执行环境都有一个与之关联的变量对象(variable object),环境中定义的全部变量和函数都保存在这个对象中。

全局执行环境是最外围的一个执行环境。

全局执行环境直到应用程序退出——例如关闭网页或浏览器——时才会被销毁。

当代码在一个环境中执行时,会建立变量对象的一个做用域链(scope chain)。

做用域链的用途,是保证对执行环境有权访问的全部变量和函数的有序访问。

var color = "blue";
function changeColor(){
    var anotherColor = "red";
    function swapColors(){
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        // 这里能够访问color、anotherColor 和tempColor
    }
    // 这里能够访问color 和anotherColor,但不能访问tempColor
    swapColors();
}
// 这里只能访问color
changeColor();

 (1)延长做用域链

执行环境的类型总共只有两种——全局和局部(函数),但仍是有其余办法来延长做用域链。

就是当执行流进入下列任何一个语句时,做用域链就会获得加长:

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

(2)没有块级做用域

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

若是是在C、C++或Java 中,color 会在if 语句执行完毕后被销毁。但在JavaScript 中,if 语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境)中。

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

 

1)声明变量

使用var 声明的变量会自动被添加到最接近的环境中。

2)查询标识符

当在某个环境中为了读取或写入而引用一个标识符时,必须经过搜索来肯定该标识符实际表明什么。搜索过程从做用域链的前端开始,向上逐级查询与给定名字匹配的标识符。

三、垃圾收集

JavaScript 具备自动垃圾收集机制,执行环境会负责管理代码执行过程当中使用的内存。

(1)标记清除

JavaScript 中最经常使用的垃圾收集方式是标记清除(mark-and-sweep)。

(2)引用计数

引用计数的含义是跟踪记录每一个值被引用的次数。

(3)性能问题

垃圾收集器是周期性运行的,并且若是为变量分配的内存数量很可观,那么回收工做量也是至关大的。

(4)管理内存

确保占用最少的内存可让页面得到更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据再也不有用,最好经过将其值设置为null 来释放其引用——这个作法叫作解除引用(dereferencing)。

相关文章
相关标签/搜索