javascript 变量、作用域和内存问题

一、基本类型和引用类型的值  

1.基本类型和引用类型的值 

基本类型值:指那些保存在栈内存中的简单数据,即这种值完全保存在内存中的一个位置,他们所占据的空间大小是固定的。

引用类型值:指那些保存在堆内存中的对象,这些类型的真正数据是保存在堆内存中的,而同时在栈内存中保存的只是一个指针这个指针指向的是这个对象在堆内存中的一块地址

基本类型的复制:基本类型在内存中占有的空间大小是固定的,复制的时候会重新在栈内存中开辟一块空间,是按值来访问的。

引用类型的复制:由于这种对象所占的大小是不固定的,是放在堆内存中的,但是内存的地址大小是固定的,故栈中存放的是对象在堆内存的地址。这样当查找引用的时候,是先从栈内存中取出地址,然后再到堆内存中找到对应的值,这就是引用访问。复制的时候是复制的栈内存的值,也就是拷贝的一个引用而已,两个变量指向的堆内存中对象还是同一个对象。

2.复制变量的值 

基本类型:复制的是变量本身的值,复制后是在栈空间重新开辟一块空间,复制完成后两个变量是相互独立的,各不相干,故一个变量的值改变后不会影响另外一个变量的值。

引用类型:复制的时候只是复制的栈空间的地址而堆内存中还是同一个对象,也就是复制的引用,结果是两个变量指向的是同一个内存块,所以,复制后两个变量中某一个改变了对象的值那么另外一个变量输出的结果也会改变,因为他们是指向的内存中同一个对象。

3.传递参数

在js中参数传递都是值传递,不存在引用传递。 

值类型:传递的是变量本身的值,和复制是一样的,函数中改变了变量的值,不会影响源变量值    

引用类型:同样是值传递,传递的是变量再栈内存空间中的地址值,如果在函数中改变了对象某一个属性的值,源变量中的值也会改变,因为在堆内存中它们是指向的同一个对象。

function func(num){
    num.name=123;
}

var box={};
box.name='abcd';
alert(box.name);    //abcd
func(box);
alert(box.name);    //123   值在函数func中被改变了

4.检测类型

 检测变量的类型的时可以用 typeof 来实现,但是这个只是返回的几大基本的数据类型,在检测Object类型的时候则不是那么好用,因为Null,Object,Array,RegExp 等都会返回object,那样就不知道变量到底是什么类型。    

可以 用instanceof 来确定变量是某种具体的引用类型。

var box = [1,2,3]

alert(box instanceof Object);  //true

alert(box instanceof Array);  console.log(Array.isArray(box))  //true  //准确检测类型是否是数组 

如果是这种类型就返回true,否则就返回false

二、执行环境及作用域

执行环境也就是作用域在很多的编程语言中都是一个很重要的概念,规定了变量或者函数有权访问其他数据的权限,规定了各自的行为。

全局执行环境是最外围的执行环境,在web浏览器中,全局执行环境被认为是window对象,故所有的全局变量和函数都是以window对象的属性和方法创建的。

每个函数都有自己的执行环境当执行环境中代码执行完成后,就会销毁该执行环境,也会销毁里面的变量和函数等。(全局执行环境是需要在网页关闭或者应用程序退出后才会被销毁。)

当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的用途是保证执行环境有权访问的所有变量和函数的有序访问。

函数体内还包含着函数,只有这个函数才可以访问内一层的函数。而内部函数的变量可以通过作用域链访问外部函数的变量,可以向上搜索作用域链,以查询变量。但是不能反过来。

没有块级作用域

块级作用域表示诸如if等有花括号封闭的代码段块,所以支持条件判断来定义变量。 像 if,for 等代码块中定义的变量在花括号外面是可以访问的,这和其他语言中有很大的差别。

if(true){
    var color = 'red';
}
console.log(color);     //red

var关键字在函数中的区别

在函数中声明变量的时候,如果不加上关键字 var 那变量会被认为是全局的,函数外面也可以访问它,当然在访问之前要先执行一次函数,加了则是局部的

最好不要不用var关键字就初始化变量,因为这种情况下可能会导致各种错误,所有初始化变量的时候一定要加上关键字 var。

一般确定某一个变量的时候是通过搜索来确定的,现在本级作用域上找,如果没有,在向上级作用域找,依次类推,故访问局部变量要比访问全局变量的效率更高。因为不需要向上收索作用域链

3、内存相关 

js中也存在垃圾回收机制,我们不需要担心内存的泄露问题,垃圾回收机制会自动的管理内存的分配和无用内存的回收。  

  JS中最常用的垃圾回收的方式是标记清除,就是在运行的时候会给内存中的所有变量加上一个标记,然后去掉环境中正在使用的变量的标记,而没有被去掉标记的变量将被视为准备删除的变量。最后垃圾清理器完成内存清理的工作,销毁那些带有标记的变量,并且回收他们所占用的内存空间 。   

垃圾收集器是周期性的运行,不是随时运行,这样可能会遇到一些性能问题,但是一般情况下不需要担心这个问题。

一般来说,确保页面占用的内存更少可以让页面获得更好的性能,最好的减少内存占用量的方式就是,一旦变量或者对象不再使用的时候,将其赋值为空,即:box=null; 来释放引用,这种方式叫做删除引用,这种方式使用大多数的全局变量和全局对象。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏锦小年的博客

python学习笔记6.2-类常见的编程模式

上一次写过一篇有关于python类的博客,现在回头去看看,发现好多语法还是比较低级,表达不是很清晰。现在谈一谈对python类的表达的新的理解。 本篇博客的...

25290
来自专栏吴裕超

ES6之模版字符串

  但是我们可以看到:这样的传统做法需要使用大量的“”(双引号)和 + 来拼接才能得到我们需要的模版。但是这样是十分不方便的。

8310
来自专栏零基础使用Django2.0.1打造在线教育网站

关于JAVA你必须知道的那些事(二):封装

时隔近一年,我突然想起来这个文章还没有发完,所以就继续开始写。也不知道自己上次写到哪里了,不管了这里从面向对象的三个特性说起。

8810
来自专栏深度学习之tensorflow实战篇

python 字典操作提取key,value

python 字典操作提取key,value dictionaryName[key] = value 1.为字典增加一项 ? 2.访问字典中的值 ...

48250
来自专栏北京马哥教育

Linux Shell 流程控制语句实例

linux shell 有一套自己的流程控制语句,其中包括条件语句(if),循环语句(for,while),选择语句(case)。下面我将通过例子介绍下,各个...

39470
来自专栏web前端教室

var a="xx";a=a+"ss";a的值变了,但"xx"字符串并没有变

如题目所示, var a="xx"; a=a+"ss"; console.log(a); //xxss 一般情况下,我们就可以认为此时a的值,由'xx'变成了'...

21680
来自专栏LEo的网络日志

python技巧分享(十一)

27480
来自专栏IT可乐

深入理解计算机系统(3.5)------特殊的算术操作指令

  在上一篇博客 算术和逻辑操作 我们介绍了如下图几种常用的算术逻辑指令,但是大家发现没,这几种指令如果在 IA32 上只能操作32位寄存器,比如我用乘法指令I...

21270
来自专栏Python中文社区

Python中典型内建函数的用法

专栏作者简介 王 洪 永 在读大学生,学习过C, C++, Python, 了解java,html, javascript基础。其中就Python而言,自己写过...

21760
来自专栏Python

python2/3 中删除字典中value为空的键值对方法

只是在for循环中,相当于对链表的操作,它会自动调用next方法! 字典的迭代器会遍历它的键,在这个过程中,不能改变这个字典!不能删除、添加数据 要先记录要删...

24730

扫码关注云+社区

领取腾讯云代金券