《JavaScript高级程序设计》读书笔记-第四章(变量、作用域和内存问题)

基本类型和引用类型

  • 基本类型

    • Undefined
    • Null
    • Number
    • Boolean
    • String
    • ES6加了一个Symbol
  • 引用类型

    • 引用类型的值是保存在内存中的对象。与其他语言不通,JavaScript不允许直接防伪内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象
  • 访问变量有按值按引用两种方式,而参数只能按值传递

function setName(obj){
  obj.name = 'Nicholas'
  obj = new Object()
  obj.name = 'Greg'
}
var person = new Object()
setName(person)
console.log(person.name)  //'Nicholas'

说明即使在函数内修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写obj时,这个变量利用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。

总结:说明了变量是按值传递的,而不是按引用传递的。

检测类型

typeof

注意 :

typeof null = object
  • 使用 typeof 操作符检测函数时,该操作符会返回'function'。
  • ECMA-262规定任何在内部实现[[Call]]方法的对象都应该在应用typeof操作符时返回'function',在Safari 5 及之前版本和Chrome 7 及之前版本中使用typeof检测正则表达式时,由于规范的原因,这个操作符也返回‘function’
  • IEFirefox中,对正则表达式应用typeof会返回'object'
  • 检测基本数据类型时typeof是非常得力的助手
  • 检测引用类型的值时,这个操作符的用处不大,这个时候一般用 instanceof 操作符
person instanceof Object      //变量perison是Object吗
colors instanceof Array      //变量colors是Array吗
pattern instanceof RegExp    //变量pattern是RegExp吗
  • 如果使用instanceof操作符检测基本类型的值,则该操作符始终会返回false,因为基本类型不是对象

执行环境及作用域

执行环境
  • 在Web浏览器中,全局执行环境被认为是window对象
  • 某个执行环境中的所有代码执行完毕后,该环境被销毁保存在其中的所有变量和函数定义也随之销毁
  • 每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,在函数执行之后,栈将其环境弹出
作用域链
  • 作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
延长作用域链

执行流进入下列任何一个语句时,作用域链就会得到加长

  • try-catch语句的catch
  • with语句
没有块级作用域
垃圾收集
  • JavaScript程序所需内存的分配以及无用内存的回收完全实现了自动管理。

  • 原理:找出那些不再继续使用的变量,然后释放其占用的内存。 垃圾收集器会按照固定的时间间隔(或代码执行中预定的手机时间),周期性地执行这一操作

  • 垃圾收集器必须追踪哪个变量有用哪个变量没用,对于不再有用的变量打上标记,以备将来收回其占用的内存

  • 通常有两个策略

    • 标记清除
      当变量进入环境时,就将这个变量标记为'进入环境',从逻辑上讲,永远不能释放进入环境的变量所占用的内存。当变量离开环境时,则将其标记为'离开环境'
    • 引用计数
      引用计数的含义是跟踪记录每个值被引用的次数
      引用计数有一个很严重的问题,就是当遇到循环引用的时候
function problem(){
  var objectA = new Object()
  var objcetB = new Object()

  objectA.object = objectB
  objectB.anotherObject = objectA
}

IE中又一部分的对象并不是原生JavaScript对象,其BOM和DOM中的对象就是使用C++以COM(Component Object Model,组件对象模型),而COM对象的垃圾收集机制采用的就是引用计数策略,就会存在循环引用的问题

var element = document.getElementById('some_element')
var myObject = new Object()
myObject.element = element
element.someObject = myObject

即使例子中的DOM从页面中移除,它也永远不会被回收

避免类似的循环引用问题,最好是在不使用他们的时候手工断开连接

myObject.element = null
element.someObject = null

为了解决上述问题,IE9把BOM和DOM对象转换成了真正的JavaScript对象。这样就避免了两种垃圾收集算法并存导致的问题,也消除了常见的内存泄漏现象。

性能问题
  • 垃圾收集器是周期性运行的
  • IE的垃圾收集器是根据内存分配量运行的,达到256个变量、4096个对象(或数组)字面量和数组元素(slot)或者64kb的字符串,垃圾收集器就会运行。如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量。
  • IE7的发布,JavaScript引擎的垃圾收集例程改变了工作方式:触发垃圾收集的变量分配,字面量和数组元素的临界值被调整为动态修正
  • 在IE中,调用window.CollectGarbage()方法会立即执行垃圾收集
  • 在Opera7及更高版本中,调用window.opera.collect()也会启动垃圾收集例程
管理内存

浏览器的可用内存数量通常要比分配给桌面应用程序的少。这样做的目的主要出于安全方面的考虑,目的是防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。

  • 优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null,来释放其引用——这个做法叫做解除引用
function createPerson(name){
  var localPerson = new Object()
  localPerson.name = name
  return localPerson
}
var globalPerson = createPerson('Nicholas')

//解除
globalPerson = null
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容