《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题

时间:2021-11-20 13:34:21

欢迎关注本人的微信公众号“前端小填填”,专注前端技术的基础和项目开发的学习。

《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题本节内容对应《JavaScript高级程序设计》的第四章内容。

1、函数:通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。ECMAScript中的函数用function关键字来进行声明,后面跟一组参数以及函数体。不必指定是否有返回值

 function functionName(args0,args1,...argsN){
      //statements
 }

2、函数的重载:为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。ECMAScript函数没有签名,因为其参数是由包含零个或多个值得数组来表示的,而没有函数签名,真正的重载是不可能做到的。如果在ECMAScript中定义两个名字相同的函数(函数名和参数的个数均相同),则该名字只属于后定义的函数。

function add(num){
     return num + 100 ;
}

function add(num){
     return num + 200 ;
}

3、JavaScript变量松散类型的本质决定了它至少在特定时间用于保存特定值的一个名字而已,由于不存在定义某个变量必须保存何种数据类型值得规则,变量的值及其数据类型可以在脚本的生面周期内改变。

4、ECMAScript变量包含两种不同的数据类型:基本类型值和引用类型值。基本类型值指的是简单的数据段,引用类型值指那些可能由多个值构成的对象。注意:在JavaScript中字符串是基本类型,是按值访问的,这一点与java中的不一样。对于引用类型的值(即对象),我们可以动态地为其添加属性和方法:

var person = new Object() ;
person.name = "Jack" ;  //添加属性name

5、变量值的复制:

  • 对于简单类型值:复制前后的两个变量没有任何关系,某一个变量的改变并不影响另一个变量的值
  • 而对于引用类型值:复制的内容实际上是一个指针,指向该对象的存储地址,所以复制前后的两个变量实际上指向同一个对象,某一个变量的值的改变会影响另一个变量的值。

6、ECMAScript中所有函数的参数都是按值传递的,即将函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样,应用类型的复制实际上是对象的存储地址的复制。

7、前面提到检测变量的数据类型用typeof,但是typeof的返回值只有string、number、boolean、undefined、function(函数和正则表达式均返回function)、object(null和引用类型均返回object)。所以,对于引用类型或null,我们无法具体确定是属于哪一种引用类型的对象。要确定属于哪一种引用类型,我们可以用instanceof操作符,如果变量是给定引用类型的对象,则instanceof操作符将返回true。因此,在检测一个引用类型值和object构造函数时,始终会返回true,而如果使用instanceof操作符检测基本类型的值,则该操作符始终会返回false,因为基本类型不是对象。

8、在javascript中,执行环境定义了变量或函数有权访问的其他数据类型,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中

  • 根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样。
  • 某个执行环境中的所有代码执行完毕后,该环境就被销毁,保存在其中的所有变量和函数定义也随之销毁。
  • 全局执行环境是最外围的一个执行环境。在web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。
  • 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行完毕后,栈将其环境弹出,把控制权返回给之前的执行环境。
  • 当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端始终都是当前执行的代码所在环境的变量对象。作用域链的下一个变量对象来自包含环境,再下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境,全局执行环境的变量对象始终是作用域链中的最后一个对象。
  • 标识符的解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前段开始,然后逐级地向后回溯,直至找到标识符为止(如果找不到标识符,通常会导致错误发生)。
  • 当执行流进入到try-catch语句的catch语句或者with语句中时,作用域链就会得到延长。
  • javascript中没有块级作用域
    if(true){
        var color = "blue" ;
    }
    
    alert(color) ;  //在java中,存在块级作用域,此时在if外面用到color变量则是不合规范的,但是在javascript中不存在这种问题

9、垃圾收集:javascript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中是用得内存。这样,在编写javascript程序时,我们不需要关心内存使用问题,所需内存分配以及无用内存的回收完全实现了自动管理。则也解决了C++/C语言存在的很大一部分问题。对于垃圾收集,通常用到两种策略来判断一个变量是否是垃圾:

  • 标记清除(mark-and-sweep):当变量进入环境时,就将该变量标记为进入环境,当变量离开环境时,标记为离开环境。
  • 引用计数(reference counting):一个变量被引用(赋值给另一个变量)一次则应用数加1,相反,如果包含该对象应用的变量又取得了另外一个值,则减1。当一个变量计数为0时,表示该变量不再需要,可以清除了。注意循环引用的情况会导致变量无法被清除。

10、确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再用,最好通过将其值设置为null来释放其引用(这个方法叫解除引用)。