原始值和引用值
1、原始值: 就是简单的数据类型,储存的是值
例如: Undefined 、 Null 、 Boolean 、 Number 、 String 和 Symbol
2、引用值:就是由多个值构成的对象,它是保存在内存中的对象,javascript不允许直接访问内存位置,因此是不能操作对象所在的内存空间,所以操作对象其实是操作的对该对象的引用而非对象本身,因此报错引用值的变量是按引用访问的。
动态属性
1、引用值可以随时添加、修改、删除其属性
2、复制值
原始值和引用值再通过变量复制值的时候也有所不同,
(1)原始值复制值的时候会被复制到新变量的位置
(2)在把引用值变量赋值给另一个变量的时候储存在变量中的值也会被复制到新的变量的位置中去,区别在于这里复制的实际上是一个指针,它指向储存在对内存中的对象,因此两个变量实际指向的是同一对象。
3、参数传递(函数参数传递)
(1)在按值传递参数的时候,值会被复制到一个局部变量。即一个命名参数,或者用 ECMAScript 的话说,
就是 arguments 对象中的一个槽位。
(2)在按引用类型传递的时候,值在内存中的位置会被保存在一个局部变量。这样的话本地变量的修改会反应到函数外部。
// 按值传递
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";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
4、 确定类型
使用typeOf 判断一个变量是否为原始类型(字符串,数值,null , undefined 等),但是typeOf对原始类型有用,但是对引用类型的作用不大。
使用instanceof:如果变量是给定的引用类型,可以同过这个操作符来判断引用类型的数据类型
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 ,
因为原始值不是对象。
执行上下文
1、所谓上下文就是指的是变量或者函数可以访问哪些数据,也可以说,就是作用域
2、全局上下文,指的就是全局环境,也就是我们说的window对象。
通过var定义的全局变量和函数都会成为window对象的属性和方法。
使用let 和const 定义的顶级声明不会在全局上下文中,但在作用域链解析上是一样的。
注意:上下文在其所有代码都执行完毕后会被销毁,包括定义
在它上面的所有变量和函数(全局上下文在应用程序退出前才会被销毁,比如关闭网页或退出浏览器)。
3、作用域链增强
上下文分为全局上下文和函数上下文:
const 和 let 声明的变量的作用域都是块级的 ,块级作用域由一对 { } 界定。因此, if 块、 while 块、 function 块,甚至连单独
的块也是 let 声明变量的作用域。
使用const 的常量声明必须初始化某个值,一经声明 在其生命周期内的任何时候都不能在重新赋予新值。
注意:const 声明只应用到顶级原语或者对象。换句话说,赋值为对象的 const 变量不能再被重新赋值
为其他引用值,但对象的键则不受限制。
如果想让整个对象都不能修改,可以使用 Object.freeze() ,这样再给属性赋值时虽然不会报错,
但会静默失败:
垃圾回收
1、标记清理
2、引用计数
3、性能
4、内存管理
5、内存泄漏
6、静态分配与对象池
总结:
小结
JavaScript 变量可以保存两种类型的值:原始值和引用值。原始值可能是以下 6 种原始数据类型之
一: Undefined 、 Null 、 Boolean 、 Number 、 String 和 Symbol 。原始值和引用值有以下特点。
原始值大小固定,因此保存在栈内存上。
从一个变量到另一个变量复制原始值会创建该值的第二个副本。
引用值是对象,存储在堆内存上。
包含引用值的变量实际上只包含指向相应对象的一个指针,而不是对象本身。
从一个变量到另一个变量复制引用值只会复制指针,因此结果是两个变量都指向同一个对象。
typeof 操作符可以确定值的原始类型,而 instanceof 操作符用于确保值的引用类型。
任何变量(不管包含的是原始值还是引用值)都存在于某个执行上下文中(也称为作用域)。这个
上下文(作用域)决定了变量的生命周期,以及它们可以访问代码的哪些部分。执行上下文可以总结
如下。
执行上下文分全局上下文、函数上下文和块级上下文。
代码执行流每进入一个新上下文,都会创建一个作用域链,用于搜索变量和函数。
函数或块的局部上下文不仅可以访问自己作用域内的变量,而且也可以访问任何包含上下文乃
至全局上下文中的变量。
全局上下文只能访问全局上下文中的变量和函数,不能直接访问局部上下文中的任何数据。
变量的执行上下文用于确定什么时候释放内存。
JavaScript 是使用垃圾回收的编程语言,开发者不需要操心内存分配和回收。JavaScript 的垃圾回收
程序可以总结如下。
离开作用域的值会被自动标记为可回收,然后在垃圾回收期间被删除。
主流的垃圾回收算法是标记清理,即先给当前不使用的值加上标记,再回来回收它们的内存。
图灵社区会员 aSINKz(1561821892@qq.com) 专享 尊重版权
102 第 4章 变量、作用域与内存
引用计数是另一种垃圾回收策略,需要记录值被引用了多少次。JavaScript 引擎不再使用这种算
法,但某些旧版本的 IE 仍然会受这种算法的影响,原因是 JavaScript 会访问非原生 JavaScript 对
象(如 DOM 元素)。
引用计数在代码中存在循环引用时会出现问题。
解除变量的引用不仅可以消除循环引用,而且对垃圾回收也有帮助。为促进内存回收,全局对
象、全局对象的属性和循环引用都应该在不需要时解除引用。