4.1 原始值与引用值
ECMAScript变量可以包含两种不同类型的数据:原始值和引用值。原始值就是最简单的数据,引用值则是由多个值构成的对象。
在操作对象时,实际上操作的是对该对象的引用而非实际的对象本身。因此,保存引用值的变量是按引用访问的。
4.1.1 动态属性
原始值和引用值的定义方式很类似,都是创建一个变量,然后给它赋值。对于引用值而言,可以随时添加、修改和删除其属性和方法。
let person = new Object(); person.name = "Nicholas"; console.log(person.name); // "Nicholas"
原始值不能有属性,尽管尝试给原始值添加属性不会报错
let name = "Nicholas"; name.age = 27; console.log(name.age); // undefined
原始类型的初始化可以只使用原始字面量形式。如果使用的是new关键字,则JavaScript会创建一个Object类型的实例,但其行为类似原始值
let name1 = "Nicholas"; let name2 = new String("Matt"); name1.age = 27; name2.age = 26; console.log(name1.age); // undefined console.log(name2.age); // 26 console.log(typeof name1); // string console.log(typeof name2); // object
4.1.2 复制值
原始值和引用值在通过变量复制时也有所不同。在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置。(这两个变量可以独立使用,互不干扰)
在把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。区别在于,这里复制的值实际上是一个指针,它指向存储在堆内存中的对象。操作完成后,两个变量实际上指向同一个对象。
let obj1 = new Object(); let obj2 = obj1; obj1.name = "Nicholas"; console.log(obj2.name); // "Nicholas"
4.1.3 传递参数
ECMAScript中所有函数的参数都是按值传递的。这意味着函数外的值会被复制到函数内部的参数中,就像从一个变量复制到另一个变量一样。如果是原始值,那么就跟原始值,那么就跟原始值变量的复制一样。如果是引用值,那么就跟引用值变量的复制一样。
function addTen(num) { num += 10; return num; } let count = 20; let result = addTen(count); console.log(count); // 20,没有变化 console.log(result); // 30
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } let person = new Object(); setName(person); console.log(person.name); // "Nicholas"
注意 ECMAScript 中函数的参数就是局部变量。
4.1.4 确定类型
typeof操作符最适合用来判断一个变量是否为原始类型。它可以判断变量是否为字符串、数值、布尔值或undefined的最好方式。如果值是对象或null,那么typeof返回“object”
let s = "Nicholas"; let b = true; let i = 22; let u; let n = null; let o = new Object(); console.log(typeof s); // string console.log(typeof i); // number console.log(typeof b); // boolean console.log(typeof u); // undefined console.log(typeof n); // object console.log(typeof o); // object
instanceof操作符可以知道引用值是什么类型的对象:result=variable instanceof constructor
console.log(person instanceof Object); // 变量 person 是 Object 吗? console.log(colors instanceof Array); // 变量 colors 是 Array 吗? console.log(pattern instanceof RegExp); // 变量 pattern 是 RegExp 吗?
所有引用值都是 Object 的实例,因此通过 instanceof 操作符检测任何引用值和Object 构造函数都会返回 true 。类似地,如果用 instanceof 检测原始值,则始终会返回 false ,
4.2 执行上下文与作用域
执行上下文(简称"上下文")的概念在JavaScript中是颇为重要的。变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。上下文中的代码在执行的时候,会创建变量对象的一个作用域。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。
简而言之,执行上下文就是有一个变量在哪里可以访问在哪里不能访问。
4.3 垃圾回收
JavaScript通过自动内存管理实现内存分配和闲置资源回收。基本思路:确定哪个变量不会再使用然后释放它占用的内存。这个过程是周期性的,即垃圾回收程序每隔一定时间(或者说在代码执行过程中某个预定的收集时间)就会自动运行。