专栏首页Super 前端变量、作用域和内存问题

变量、作用域和内存问题

下述内存主要讲述了《JavaScript高级程序设计(第3版)》第4章关于“变量、作用域和内存问题”。

  1. JavaScript变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已。 (1)基本类型的值在内存中占据固定大小的空间,因此会保存在栈内存中; (2)引用类型的值是对象,保存在堆内存中。 堆内存:随意存储,一般由程序员分配释放,或者程序结束时有OS回收。 栈内存:先进后出,有编译器自动分配释放,存放函数的参数值、局部变量的值等。
  2. JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。操作对象时,实际上是在操作对象的引用而不是实际的对象。
  3. 复制 基本类型(undefined、null、boolean、number、string)复制,会创建这个值的一个副本,完全独立; 引用类型(对象)复制,复制的其实是指针,两个变量引用同一个对象。
var num1 = 57;
var num2 = num1;
num1 = 38;
console.log(num1, num2);    // 38 57

var obj1 = new Object();
var obj2 = obj1;
obj1.name = 'ligang';
console.log(obj2.name);     // "ligang"

确定一个值是哪种基本类型可以使用typeof操作符,而确定一个值是哪种引用类型可以使用instanceof操作符。 4. ECMAScript中所有函数的参数都是按值传递的。 (1)传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,或者用ECMAScript的概念来说,就是arguments对象中的一个元素) (2)传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部

// 示例--论证值传递:
function setName(obj) {
    obj.name = "ligang";
    obj = new Object();
    obj.name = "lg";
}
var person = new Object();
setName(person);
console.log(person.name);   // ligang

如果是按引用传递,person会自动被修改为name为“lg”的新对象。 但是结果却是“ligang”,说明在函数内部修改了参数的值,但原始的引用仍然保持不变。 实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁

5. 执行环境和作用域 所有变量都存在一个执行环境(也成为作用域)当中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。 (1)每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链。 (2)函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含父环境,乃至全局环境。 (3)全局变量只能访问全局环境中定义的变量和函数,不能直接访问局部环境中的任何数据。 (4)变量的执行环境有利于确定该如何释放内存。

var color = "blue";
function getColor() {
    return color;
}
console.log(getColor());

6. 垃圾收集机制:标记清除和引用计数 当代码中存在循环引用现象时,“引用计数”算法就会导致问题。 解除引用(myObj = null;)是管理内存的好方式,切断变量与它此前引用的值之间的连接,让其脱离执行环境,以便垃圾收集器下次运行时将其回收。 7. 动态的属性 不能给基本类型添加属性

var str1 = new String("123");
str1.name = "string";
console.log(str1.name);     // "string"

var str2 = "456";
str2.name = "string";
console.log(str2.name);     // undefined

引用类型和基本包装类型的主要区别就是对象的生命周期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着不能在运行时为基本类型值添加属性和方法。

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 解决PKIX问题:unable to find valid certification path to requested target

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

    奋飛
  • JavaScript的工作原理:内存管理+如何处理4个常见的内存泄漏

    这篇文章将讨论日常编程中另一个复杂且容易被忽视的问题 — 内存管理。其中还提供了一些关于如何处理 JavaScript 内存泄露的提示,来防止导致内存泄漏以及不...

    奋飛
  • 10 分钟了解 webpack 核心内容

    Tapable 是 webpack 核心工具之一,提供了插件接口。webpack 中许多对象扩展自 Tapable 类(如,负责编译的 Compiler 和负责...

    奋飛
  • Swift入门: 常量和变量

    每个有用的程序都需要在某个时刻存储数据,在Swift中有两种方法:变量和常量。变量是一个可以随时更改其值的数据存储,而常量是一个可以设置一次且永远不会更改的数据...

    韦弦zhy
  • 数据类型强制转换

    上次提到过数据类型转换在输出的之前(),括号内加入需要转换的类型,这个是临时的转换,下面介绍一下临时转换和永久性数据类型转换。

    十月梦想
  • 猿学-深入理解Java中的反射机制

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对...

    黑客联盟
  • java反射原来是这么玩的(反射一开,谁都不爱)

    这个代号为Oak(橡树)的版本,在发布后的第二年,1997年02月19日,发布jdk 1.1版本,这次版本发布中引入了反射机制。

    java之旅
  • java父类,子类静态块和构造方法的执行顺序

    一个面试笔试题中没什么什么卵用但经常出的题,父类,子类静态块和构造方法的执行顺序 package com.gulf.test; public class Fa...

    用户1220053
  • 日志系统实战(一)—AOP静态注入

    蘑菇先生
  • httpclient接口测试中重试控制器设置

    本人在使用httpclient做接口测试的过程中,之前并没有考虑到请求失败自动重试的情况,但有时又需要在发生某些错误的时候重试,比如超时,比如响应频繁被拒绝等等...

    FunTester

扫码关注云+社区

领取腾讯云代金券