跳到主要内容

变量、作用域和内存

原始值和引用值

原始值的类型有NumberStringBooleanNullUndefinedSymbol

引用值的类型有ObjectArrayFunction

对象是引用值来看下面的一个例子

let a = 10;
let b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20

以上的两个变量都是独立的 Number 类型的变量,所以改变其中一个不会影响另一个

let a = { name: "fanceir" };
let b = a;
b.name = "fanceir2";
console.log(a.name); // fanceir2
console.log(b.name); // fanceir2

因为对象是引用值,所以改变其中一个会影响另一个

确定类型

之前讲到过typeof是判断一个对象是否为原始类型,但是对于null来说还是会返回object,所以可以使用Object.prototype.toString.call()来判断

let a = null;
let b = 1056;
let c = "fanceir";
let d = new String("fanceir");
console.log(typeof a); // object
console.log(typeof b); // number
console.log(typeof c); // string
console.log(typeof d); // object

在上面的例子中,有一个 String 的实例,这里typeof返回的是object。 如此可以发现,typeof 只能分辨原始值的类型,但是对引用值的用处不是很大,我们想知道一个对象具体是什么类型的对象,这里可以使用instanceofinstanceof可以通过原型链来判断一个函数是否是另一个函数的实例

let a = new String("fanceir");
console.log(a instanceof String); // true

执行上下文和作用域

执行上下文可以理解为当前代码的执行环境,上下文代码在执行的时候会创建变量的一个作用域链。这个作用域链会决定哪些数据可以被访问到。

let a = 10;
function foo() {
let aa = 20;
function bar() {
let aaa = 30;
console.log(a, aa, aaa);
}
bar();
//这里不能访问aaa
}
foo();
//这里不能访问aa和aaa

var 的变量提升

console.log(a); // undefined
var a = 10;
console.log(a);
let a = 10;

下面的一个例子会报错,这是因为letconst声明的变量不会被提升

堆地址和栈地址

基本数据类型的值会出现在栈内存中,就是我们说的变量

对象是保存到堆内存中的,每次创建一个新的对象都会在堆内存中创建一个空间而此时变量保存的是对象的内存地址。

如果两个变量保存的是同一个对象的引用,当一个通过变量修改属性的同时,另一个也会改变

let a = 1;
let b = a;
b = 2;

在上面的例子中,ab 是基本数据类型(number),它们的值存储在栈内存中。当我们将 a 的值赋给 b 时,b 得到了 a 的副本,因此修改 b 不会影响 a

let obj1 = { name: "Alice" };
let obj2 = obj1;
obj2.name = "Bob";
console.log(obj1.name); // 输出 'Bob'

在这个例子中,obj1obj2 都引用了同一个对象。当我们通过 obj2 修改对象的属性时,obj1 也会反映出这个变化,因为它们指向的是同一个堆内存中的对象。

基本数据类型的值存储在栈内存中,赋值到变量时,变量保存的是值的副本,修改副本不会影响原值。 而对象引用存储堆内存中,赋值到变量时,变量保存的是对象的内存地址,修改对象属性会影响其他变量引用的对象属性。

基本数据类型对象引用
numberobject
stringArray
booleanFunction
nullDate