zoukankan      html  css  js  c++  java
  • 有关js的变量、作用域和内存问题

      来自《javascript高级程序设计 第三版:作者Nicholas C. Zakas》的学习笔记(四)

      js共有5种基本数据类型:Undefined、NULL、Boolean、Number、String。5种基本数据类型是按值访问的,因此可以操作保存在变量中的实际值。而引用类型则不同,因为引用类型的值是保存在内存对象中的,而js不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象的时候,是在操作对象的引用而不是实际的对象。所以有“引用类型的值是按引用访问的”说法。

      基本数据类型与引用类型的值的区别,总结如下:

    1. 我们可以给引用类型的值添加属性和方法;如:
      var person = new object();
      person.name = "carol";
      alert(person.name);   //"carol"

      我们不能给基本类型的值添加属性。尽管不会报错,但是访问的属性会不见,如:

      var name = "carol";
      name.age = 27;
      alert(name.age);    //undefined

      说明:只能给引用类型值动态地添加属性,以便将来使用。

    2. 基本类型值的复制是独立的,如:
      var num1 = 5;
      var num2 = num1;     //num1和num2之间其实是独立的,相互不影响

      引用类型的复制时,副本实际上一个指针,这个指针指向存储在堆中的一个对象,并非独立,存在相互影响,如:

      var obj1 = new object();
      var obj2 =obj1;
      obj1.name = "Nicholas";
      alert(obj2.name);    //"Nicholas"

      ECMAScript中所有函数的参数传递都是按值传递的。但是需要指出的是,这个值分为“基本类型值”和“引用类型值”。为什么我这么说呢?先看两个例子:

    1. function addTen(num) {
        num += 10;
        return num;  
      }
      
      var count = 20;
      var result = addTen(count);
      alert(count);       //20
      alert(result);      //30

      num作为“基本类型值”的传递时,是独立的,即num和count互不相识。

    2. function setName(obj) {
        obj.name = "carol";    
      }
      
      var person = new Object();
      setName(person);
      alert(person.name);    //"carol"

      obj作为“引用类型值”传递,会互相影响。

        但是总结起来,就是按值传递,并非有引用传递之说。即使是obj第二种情况,还是按值传递的方式,为什么呢?你可能会说,按值传递不是不会改变实参值的吗?且分析:

    1. function setName(obj) {
        obj.name = "carol";
        obj = new Object();
        obj.name = "gof";
      }
      
      var person = new Object();
      setName(person);
      alert(person.name);   //“carol"  而不是”gof"

      当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。从alert的结果看,如果是引用传递,person.name的结果应该是gof而不是carol。   

      3. 确定一个值是那种基本类型可以使用typeof操作符,而确定一个值是哪种引用类型可以使用instanceof操作符。

      全局执行环境直到应用程序退出——例如关闭网页或浏览器时才会销毁。

      作用域链:  

      用途:保证对执行环境有权访问的所有变量和函数的有序访问。标识符解析是沿着作用域链一级一级地搜索标识符的过程。即向后回溯。内部环境可以通过作用域链访问到所有外部环境,反之不行。

      js没有块级作用域。解释如下:

      

    if (true) {
      var color = "blue";
    }
    
    alert(color);    //"blue"

      if语句中变量声明会将变量添加到当前执行环境。在使用for循环时,尤其需要注意:

    for (var i = 0;i < 10;i++) {
      dosomething(i);
    }
    
    alert(i);     //10

      用var声明的变量自动添加到最近的环境中。而没有var则添加到全局环境中。

      js的垃圾收集:具有自动垃圾收集机制。常用的有标记清除和引用计数。但是引用计数会出现循环引用问题,最好是采用手动断开连接:

    myObject.element = null;
    element.someObject = null;

      

      管理内存:即手工解除引用。同上js的手工断开连接。为什么要管理内存呢???其实js是具有垃圾收集机制的,按道理,开发人员是不需要操心内存管理问题的,因为对离开作用域的值将被自动标记为可回收,因此将在垃圾收集期间被删除。但js有一点特殊,出于安全方面的考虑,防止运行js的网页耗尽全部系统内存而导致系统崩溃,分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及一个线程中能够同时执行的语句数量。确保占用最少的内存可以让页面获得更好的性能。所以有了优化内存占用之说!

      优化内存占用的最佳方式:为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用——这个做法叫做解除引用。这一做法适用于大多数全局变量和全局对象的属性。局部变量会在它们离开执行环境时自动被解除引用。

      注意:解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

    function createPerson(name) {
      var localPerson = new Object();
      localPerson.name = name;
      return localPerson;
    }
    
    var globalPerson = createPerson("carol");
    
    //手工解除globalPerson的引用
    
    globalPerson = null;

      学习笔记。

  • 相关阅读:
    固定表头/锁定前几列的代码参考[JS篇]
    盘点mysql中容易被我们误会的地方
    cookie&session的Q&A故事[原理篇]
    网络第一道防线:验证码的故事[安全篇]
    2016,把一年的牛皮先吹了吧[生涯规划篇]
    微软职位内部推荐-Software Engineer II
    微软职位内部推荐-Senior Software Engineer
    微软职位内部推荐-Senior Software Engineer
    微软职位内部推荐-SW Engineer II for Cloud Servi
    微软职位内部推荐-SW Engineer II for Cloud Servi
  • 原文地址:https://www.cnblogs.com/Iwillknow/p/3581511.html
Copyright © 2011-2022 走看看