JavaScript高级程序设计——第四章(两种类型及作用域解析)

一.前言

本章主要介绍的是两种类型的区别和引用方法,这个很重要,引用方法的特殊性是必须掌握的。还有执行环境与作用域,帮助我们理解代码的执行过程,最后的垃圾回收做了解即可,用于面试

二.基本类型和引用类型

  1. 引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript不允许直接访问内存中的位置,就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。

  2. 不能给基本类型的值添加属性,虽然不会报错。

    var name = 'nico'
    name.age = 27
    alert(name.age) //undefined
    
  3. 复制变量值

    从一个变量向另一个变量复制的基本类型值和引用类型值是不同的。
    ①基本类型值

    var num1 = 5;
    var num2 = num1
    

    num1的值是5,执行第二行代码时会在变量num2上创建一个新值,然后把num1的值5复制到新变量分配的位置上。
    num1的5和num2的5是完全独立的,此后的任何操作都不会互相影响。
    ②引用类型值

    var obj1 = new Object();
    var obj2 = obj1;
    obj1.name = 'nico'
    alert(obj2.name)  //'nico'
    

    执行第二行代码时,也会将存储在obj1中的值复制一份到obj2分配的空间中。但是这个值实际上只是一个指针,指针指向的是存储在堆中的一个对象。**复制操作结束后,两个变量实际上指向的是同一个变量。**所以obj2.name = obj1.name

  4. 传递参数
    ECMAScript中所有函数的参数都是按值传递的。基本类型值的传递如同基本类型变量的复制一样,引用类型值的传递如同引用类型变量的复制一样。
    变量的访问有按值和按引用两种,但是函数参数的传递只能按值传递。

    基本类型值的参数传递好理解,内部值的变化不会影响外部基本类型变量的变化。
    但是如何证明对象时按值传递的。

    function setName(obj){
    	obj.name = 'nico'
    	obj = new object()
    	obj.name = 'love'
    }
    var person = new Object();
    setName(person);
    alert(person.name)  //‘nico’
    

    如果是按引用传递,那么person就会自动被修改为name指向‘love’的新对象,然而这里新创建的对象只是个局部对象而已,在函数执行完毕后立即被销毁。

  5. 检测类型
    ①监测一个变量是不是基本数据类型,最好的工具是typeof()
    ②如果变量是给定引用类型,则instanceof会返回true

    alert(a instanceof Object) //a是Object嘛
    alert(b instanceof Array) //a是Array嘛
    alert(c instanceof RegExp) //a是RegExp嘛
    

三.执行环境及作用域

  1. 在web浏览器中,全局执行环境被认为是window对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的

  2. 每个函数都有自己的执行环境,执行流进入一个函数之后,函数的环境会被推入一个环境栈中,函数执行之后,栈就会将环境推出,把控制权返回给之前的执行环境。

  3. 代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的前端,始终是当前执行代码所在环境的变量对象。如果这个环境是函数,则函数的活动对象作为变量对象。
    什么是活动对象呢:最开始只包含一个变量,即arguments对象(在window中是不存在的)。
    作用域链中下一个变量对象是来自外部环境,下下个变量是来自下一个外部环境。作用域链中的最后一个对象时全局执行的变量对象。

  4. 内部环境可以根据作用域链访问外部环境,但外部环境不能访问内部环境中的任何变量和函数。

  5. 延长作用域链。虽然执行环境的类型只有两种——全局和局部(函数),但是有些语句可以在作用域的前端临时增加一个变量对象。该变量对象会在代码执行后被移除。
    ①trt-catch语句的catch块。
    ②with语句。

function buildUrl(){
	var qs = 'a'
	with(location){
		var url = href+qs
	}
	return url
}

在此,with语句接受的是location对象,因此其变量对象中包含了location对象中的所有属性和方法,这个变量对象被添加到了作用于链的前端。在with内部定义了一个名字是url变量,因此url就成了函数执行环境的一部分,可以被返回。

6.没有块级作用域
JavaScript的花括号之间代码块没有自己的作用域。比如说for循环定义的变量i在循环结束后仍然保存在循环外部的执行环境中。
①声明变量
使用var声明的变量会自动添加到最接近的环境中。如果初始化时没有使用var声明,该变量会自动被添加到全局环境。

function add(num1,num2){
	sum = num1 + num2
	return sum
}
var result = add(10,20)
alert(sum)  //30

如上,没有使用var声明sum,所以在全局环境中可以接收到。
不过在严格模式下,不声明变量就初始化会导致错误。

7.查询标识符
在某个环境为了读取或写入一个标识符,搜索过程从作用域链前端开始,向上逐级查询与给定名字匹配的标识符。搜素过程一直追溯到全局环境的变量对象。

四.垃圾收集

1. 标记清除
垃圾回收器会在运行的时候给存储在内存中的所有变量都加上标记。然后会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在这之后还是被加上标记的变量就视为准备删除的变量。

2.引用计数
跟踪记录每一个值被引用的次数。**声明变量并将引用类型值赋给变量时,这个值的引用次数是1,又赋值给另一个变量,则引用次数加1。如果包含这个值的引用又取到了另外一个值,则引用次数减一。**当这个值的引用次数为0,则会被回收。

但是IE中有一部分对象不是原生的JavaScript对象,比如bom,dom是使用c++以com对象的形式实现的会存在com对象循环引用的问题(详情见书)。不过IE9把bom和dom对象都转换成了真正的JavaScript对象,就不会有两种垃圾收集算法并存导致的问题,也消除了常见的内存泄漏现象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值