背景
和其他编程语言一样,JavaScript也要考虑变量和作用域的问题,JavaScript中的变量和其他编程语言的变量有一些不同,这些不同值得我们注意,具体如下:
基本类型和引用类型的值
基本类型值:
- 指那些保存在栈内存中的简单数据,即这种值完全保存在内存中的一个位置,其占据的空间大小是固定的。
- 基本类型的复制:基本类型在内存中占有的空间大小是固定的,复制的时候会重新在栈内存中开辟一块空间,按值来访问。
引用类型值:
- 指那些保存在堆内存中的对象,这些类型的真正数据是保存在堆内存中的,而在栈内存中保存的只是一个指针,这个指针指向的是这个对象在堆内存中的地址。
- 引用类型的复制:引用类型所占的空间大小是不固定的,存放在堆内存中。
- 但内存的地址大小是固定的,故栈中存放的是对象在堆内存的地址。
- 查找引用类型值时,先从栈内存中取出地址,然后再到堆内存中找到对应的值,这就是引用访问。
- 复制时是复制的栈内存的值,只是拷贝一个引用,两个引用变量指向的堆内存中的对象是同一个对象。
函数中传递参数
- 在js中参数传递都是值传递,不存在引用传递。
值类型:
- 传递的是变量本身的值,和复制是一样的,函数中改变了变量的值,不会影响源变量值
引用类型:
- 同样是值传递,传递的是变量在栈内存空间中的地址值,如果在函数中改变了对象某一个属性的值,源变量中的值也会改变,因为在堆内存中它们是指向的同一个对象。
1 | function func(num){ |
检测变量数据类型
typeof
- 只返回的几大基本的数据类型,在检测Object类型时则不宜使用。
- Null,Object,Array,RegExp等都会返回object,那样就不知道变量到底是什么类型。
- instanceof:确定变量是哪种具体的引用类型。
1 | var box = [1,2,3] |
作用域
- 作用域规定了变量或者函数有权访问其他数据的权限,规定了各自的行为。
全局作用域
- 在web浏览器中,全局执行环境被认为是window对象,所有的全局变量和函数都是以window对象的属性和方法创建的,
- 全局作用域在网页关闭或者应用程序退出后才会被销毁。
作用域链
- 当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的用途是保证执行环境有权访问的所有变量和函数的有序访问。
- 函数体内还包含着函数,只有这个函数才可以访问内一层的函数。而内部函数的变量可以通过作用域链访问外部函数的变量,可以向上搜索作用域链,以查询变量。但是不能反过来。
块级作用域
- 块级作用域表示诸如if等有花括号封闭的代码段块,所以支持条件判断来定义变量。 像 if,for 等代码块中定义的变量在花括号外面是可以访问的,这和其他语言中有很大的差别。
if(true){
var color = 'red';
}
console.log(color); //red
var关键字在函数中的区别
- 在函数中声明变量的时候,如果不加上关键字 var 那变量会被认为是全局的,函数外面也可以访问它,当然在访问之前要先执行一次函数,加了则是局部的。
- 一般确定某一个变量的时候是通过搜索来确定的,现在本级作用域上找。若无,则在向上级作用域找,依次类推,故访问局部变量要比访问全局变量的效率更高。
内存问题
- js中存在垃圾回收机制会自动的管理内存的分配和无用内存的回收。
- JS中最常用的垃圾回收的方式是标记清除,就是在运行的时候会给内存中的所有变量加上一个标记,然后去掉环境中正在使用的变量的标记。
- 最后垃圾清理器完成内存清理的工作,销毁那些带有标记的变量,并且回收他们所占用的内存空间 。
删除引用
- box = null 来释放引用,这种方式叫做删除引用,这种方式使用大多数的全局变量和全局对象。
- 为确保页面占用的内存更少可以让页面获得更好的性能,最好的减少内存占用量的方式就是:一旦变量或者对象不再使用的时候,将其赋值为空(null)