搜索
首页web前端js教程JavaScript 变量、作用域及内存_javascript技巧

JS变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已;
由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变;

一 变量及作用域
1.基本类型和引用类型

// JS变量包含两种不同的数据类型的值:基本类型值和引用类型值;

// 1.基本类型值:保存在栈内存中的简单数据段;即这种值完全保存在内存中的一个位置;
// 基本类型值包含:Undefined|Null|Boolean|Number|String;
// 这些类型在内存中占有固定大小的空间;它们的值保存在栈空间,我们按值来访问;

// 2.引用类型值:保存在堆内存中的对象(可能由多个值构成),即变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象;
// 引用类型的值的大小不固定,因此不能保存在栈内存,必须保存在堆内存中;但可以将引用类型的值的内存地址保存在栈内存中;
// 当查询引用类型的变量时,先从栈内存中读取内存地址,然后通过地址找到堆内存中的值;=>按引用访问;

2.动态属性

// 定义基本类型值和引用类型值的方式相似:创建一个变量并为该变量赋值;
// 但当这个值保存到变量中以后,对不同类型值可以执行的操作则不一样;
  var box = new Object();           // 创建引用类型;
  box.name = 'lee';              // 新增一个属性;
  console.log(box.name);           // =>lee;

  var box = 'lee';              // 创建基本类型
  box.age = 15;                // 给基本类型添加属性;
  console.log(box.age);            // =>undefined;

3.复制变量值

// 在变量复制方面,基本类型和引用类型也有所不同;
// 基本类型赋值的是值本身;
  var box = 'lee';              // 在栈内存中生成一个box'lee';
  var box2 = box;               // 在栈内存中再生成一个box2'lee';
  // box和box2完全独立;两个变量分别操作时互不影响;

// 引用类型赋值的是地址;
  var box = new Object();          // 创建一个引用类型;box在栈内存中;而Object在堆内存中;
  box.name = 'lee';             // 新增一个属性;
  var box2 = box;              // 把引用地址赋值给box2;box2在栈内存中;
  // box2=box,因为它们指向的是同一个对象;
  // 如果这个对象中的name属性被修改了,box.name和box2.name输出的值都会被修改掉;

4.传递参数

// JS中所有函数的参数都是按值传递的,即参数不会按引用传递;
  function box(num){             // 按值传递,传递的参数是基本类型;
    num +=10;               // 这里的num是局部变量,全局无效;
    return num;
  }
  var num = 50;
  var result = box(num);
  console.log(result);           // 60;
  console.log(num);             // 50;

  function box(num){
    return num;
  }
  console.log(num);             // num is not defined;

  function box(obj){
    obj.name = 'lee';
    var obj = new Object();       // 函数内部又创建了一个对象,它是局部变量;但在函数结束时被销毁了;
    obj.name = 'Mr';           // 并没有替换掉原来的obj;
  }
  var p = new Object();
  box(p);                 // 变量p被传递到box()函数中之后就被复制给了obj;在函数内部,obj和p访问的是同一个对象;
  console.log(p.name);           // =>lee;

  // JS函数的参数都将是局部变量;也就是说,没有按引用传递;

5.检测类型

// 要检测一个变量的类型,通过typeof运算符类判断;
// 多用来检测基本类型;
  var box = 'lee';
  console.log(typeof box);          // =>string;

// 要检测变量是什么类型的对象,通过instanceof运算符来查看;
  var box = [1,2,3];
  console.log(box instanceof Array);     // =>true;
  var box2 = {};
  console.log(box2 instanceof Object);
  var box3 = /g/;
  console.lgo(box3 instanceof RegExp);
  var box4 = new String('lee');
  console.log(box4 instanceof String);   // =>true;是否是字符串对象;

  var box5 = 'string';
  console.log(box5 instanceof String);   // =>false;
  // 当使用instanceof检查基本类型的值时,它会返回false;

6.执行环境及作用域

// 执行环境:定义了变量或函数有权访问的其他数据,决定了它们各自的行为;
// 在Web浏览器中,全局执行环境=window对象;
// 因此所有的全局变量和函数都是作为window对象的属性和方法创建的;
  var box = 'blue';             // 声明一个全局变量;
  function setBox(){
    console.log(box);           // 全局变量可以在函数里访问;
  }  
  setBox();                 // 执行函数;
  // 全局的变量=window对象的属性;
  // 全局的函数=window对象的方法;

// PS:当执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁;
// 如果是在全局环境下,需要程序执行完毕,或者网页被关闭才会销毁;

// PS:每个执行环境都有一个与之关联的变量对象,就好比全局的window可以调用全局变量和全局方法一样;
// 局部的环境也有一个类似window的变量对象,环境中定义的所有变量和函数都保存在这个对象中;
// (我们无法访问这个变量对象,但解析器会处理数据时后台使用它);
  var box = 'blue';
  function setBox(){
    var box = 'red';           // 这里是局部变量,在当前函数体内的值是'red';出了函数体就不被认知;
    console.log(box);
  }  
  setBox();
  console.log(box);

// 通过传参可以替换函数体内的局部变量,但作用域仅限在函数体内这个局部环境;
  var box = 'blue';
  function setBox(box){           // 通过传参,将局部变量替换成了全局变量;
    alert(box);              // 此时box的值是外部调用时传入的参数;=>red;
  }
  setBox('red');
  alert(box);

// 如果函数体内还包含着函数,只有这个内函数才可以访问外一层的函数的变量;
// 内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数;
  var box = 'blue';
  function setBox(){
    function setColor(){
      var b = 'orange';
      alert(box);
      alert(b);
    }
    setColor();              // setColor()的执行环境在setBox()内;
  }
  setBox();
  // PS:每个函数被调用时都会创建自己的执行环境;当执行到这个函数时,函数的环境就会被推到环境栈中去执行,而执行后又在环境栈中弹出(退出),把控制权交给上一级的执行环境;

  // PS:当代码在一个环境中执行时,就会形成一种叫做作用域链的东西;它的用途是保证对执行环境中有访问权限的变量和函数进行有序访问;作用域链的前端,就是执行环境的变量对象;

7.延长作用域链

// 有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除;
// with语句和try-catch语句;这两个语句都会在作用域链的前端添加一个变量对象;
// with语句:会将指定的对象添加到作用域链中; 
// catch语句:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明;
  function buildUrl(){
    var qs = '?debug=true';
    with(location){            // with语句接收的是location对象,因此变量对象中就包含了location对象的所有属性和方法;
      var url = href+qs;        // 而这个变量对象被添加到了作用域链的前端;
    };
    return url;
  }

8.没有块级作用域

// 块级作用域:表示诸如if语句等有花括号封闭的代码块,所以,支持条件判断来定义变量;
  if(true){                 // if语句代码块没有局部作用域;
    var box = 'lee';           // 变量声明会将变量添加到当前的执行环境(在这里是全局环境);
  }
  alert(box);

  for(var i=0; i<10; i++){         // 创建的变量i即使在for循环执行结束后,也依旧会存在与循环外部的执行环境中;
    var box = 'lee';
  }
  alert(i);
  alert(box);

  function box(num1,num2){
    var sum = num1+num2;         // 此时sum是局部变量;如果去掉var,sum就是全局变量了;
    return sum;
  }
  alert(box(10,10));
  alert(sum);                // sum is not defined;访问不到sum;
  // PS:不建议不使用var就初始化变量,因为这种方法会导致各种意外发生;

// 一般确定变量都是通过搜索来确定该标识符实际代表什么;搜索方式:向上逐级查询;
  var box = 'blue';
  function getBox(){
    return box;              // 此时box是全局变量;如果是var box='red',那就变成局部变量了;
  }
  alert(getBox());              
  // 调用getBox()时会引用变量box;
  // 首先,搜索getBox()的变量对象,查找名为box的标识符;
  // 然后,搜索继续下一个变量对象(全局环境的变量对象),找到了box标识符;
// PS:变量查询中,访问局部变量要比全局变量更快,因为不需要向上搜索作用域链;

二 内存问题

// JS具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存;它会自行管理内存分配及无用内存的回收;

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

// 垃圾收集器是周期性运行的,这样会导致整个程序的性能问题;
// 比如IE7以前的版本,他的垃圾收集器是根据内存分配量运行的,比如256个变量就开始运行垃圾收集器,这样就不得不频繁地运行,从而降低了性能;

// 一般来说,确保占用最少的内存可以让页面获得更好的性能;
// 最佳方案:一旦数据不再使用,将其值设置为null来释放引用,这个做法叫做解除引用;
  var o = {
    name:'lee';
  };
  o = null;               // 解除对象引用,等待垃圾收集器回收;

三 小结

1.变量
// JS变量可以保存两种类型的值:基本类型值和引用类型值;它们具有以下特点:
// 1.基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
// 2.从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本;
// 3.引用类型的值是对象,保存在堆内存中;
// 4.包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;
// 5.从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向用一个对象;
// 6.确定一个值是哪种基本类型可以使用typeof操作符;而确定一个值是哪种引用类型可以使用instanceof操作符;

2.作用域
// 所有变量都存在于一个执行环境(作用域)中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量;
// 1.执行环境有全局执行环境和函数执行环境之分;
// 2.每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
// 3.函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其父环境,乃至全局环境;
// 4.变量的执行环境有助于确定应该合适释放内存;

3.内存
// JS自动垃圾收集机制
// 1.离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除;
// 2.为了确保有效地回收内存,应该及时解除不再使用的全局对象/全局对象属性以及循环引用变量的引用;

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

了解JavaScript引擎:实施详细信息了解JavaScript引擎:实施详细信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python vs. JavaScript:学习曲线和易用性Python vs. JavaScript:学习曲线和易用性Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C到JavaScript:所有工作方式从C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。