js红宝书拾遗(二):变量、作用域与内存

这是我参与新手入门的第3篇文章。

前言

本文内容主要是关于红宝书第四章的内容,包括原始值与引用值,执行上下文相关知识,及js的垃圾回收机制。依然是以拾遗为主,对一些老生常谈的知识点不再赘述。本次我打算调整下形式,以代码为切入点,引出相关的原理。

动态属性

let name1 = 'Jack';
let name2 = new String('Rose');
name1.age = 22;
name2.age = 24;

console.log(name1.age); // undefined
console.log(name2.age); // 24

console.log(typeof name1); // string
console.log(typeof name2); // object
复制代码

上述代码中,虽然name1name2虽然看上去都是字符串。但对于原始类型的变量,若使用new关键字创建,JavaScript会创建一个Object类型的实例,但其行为类似原始值。 因此,这两个对象分别是不同的数据类型,原始值的字符串不能追加属性,引用值的对象可以追加属性。

传递参数

ECMAScript中所有函数的参数都是按值传递的。

function addTen(num) {
    num += 10;
    return num;
}

let count = 20;
let result = addTen(count);
console.log(count); // 20
console.log(result); // 30

复制代码

如上代码,由于参数是按值传递,所以函数的参数numcount的值互不干扰,修改num的值并不会引起函数外部count的值改变,他们两个唯一的关系,就是一开始两个变量保存的值相同。

在按值传递参数时,参数的值被复制给了函数的一个局部变量。这个行为在上例中很好理解,但当参数是对象时,就有些迷惑了。如下:

function setName(obj) {
    obj.name = "Jack";
    obj = new Object();
    obj.name = "Rose";
}

let person = new Object();
setName(person);
console.log(person.name); // Jack
复制代码

上述代码可能很难理解。person作为参数传给函数后,参数obj复制了person的值。当执行obj.name="Jack"时,objperson都指向同一个外部对象,因此person被添加了name这个属性。但当obj被赋值了一个新的对象时,改变的只是obj的指针,它指向了一个本地对象,这个对象在函数执行结束时就被销毁了。

上边两组代码,若参数是按引用传递的,那count的值会变成30,person的指针会指向新创建的对象,即person.name变为"Rose"

变量声明

function add(num1, num2) {
    sum = num1 + num2;
    return sum;
}

let result = add(10, 20);
console.log(sum);
复制代码

变量sum未使用关键字声明,因此在函数调用后,sum被添加到了全局上下文,在函数退出后仍然能被访问到。这样的写法是需要严格禁止的。

由于const声明暗示变量的值是单一类型且不可修改,JavaScript运行时编译器可以将其所有实例都替换成实际的值,而不会通过查询表进行变量查找。谷歌的V8引擎就执行这种优化。

应尽可能地多使用const声明。

垃圾回收

这一部分内容还是了解为主,JavaScript使用标记清理的回收算法。

前端开发者在垃圾回收这一块儿能做的比较少。如通过constlet声明提升性能,因为块级作用域可能会更早的让垃圾回收程序介入,尽早回收内存;另外,通过将全局对象、全局对象的属性和循环引用在不需要时设置为null,解除引用,也有利于垃圾回收。

后记

本次笔记内容不多,比较难理解的应该还是参数传递那一部分。虽然工作中似乎并未因此写过bug,但也从没注意过这里边的区别。个人感觉基础知识中可挖掘的点还是很多的,对于这些知识点的学习与掌握,也能够加深对以后知识的理解。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享