JavaScript中基本类型、引用类型、执行环境、作用域链和内存问题——JS高程第4章知识总结

第4章 变量、作用域和内存问题

4.1 内容概述

如下思维导图所示:

4.2 基本类型和引用类型的值

4.2.1 不同点

定义上的不同点:基本类型值指的是简单的数据段,引用类型值指可能由多个值构成的对象。

访问方式的不同:基本数据类型是按值访问的,因为可以操作保存在变量中实际的值。引用类型的值是保存在内存中的对象。JS中不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是操作对象的引用而不是对象本身,因此,引用类型的值是按引用访问的。

动态的属性:只能给引用类型值动态的添加属性。

eg

var name = 'lyx';
name.age = 21;
alert( name.age )   //undefined

var person = new Object();
person.name = 'lyx';
alert(person.name);  //lyx

变量的复制:如果从一个变量向另一个变量复制基本类型的值,会创建一个新值分配给另一个变量,两个变量参与任何操作相互独立,互不影响。如果从一个变量向另一个变量复制引用类型的值,同样也会将变量中存储的值复制一份放到为新变量分配的空间中,但是因为变量存储的是对象的引用,所以操作结束后,两个变量引用同一个对象。修改一个就会影响到另一个。

4.2.2相同点

这个相同点是ES中函数的特性决定的,因为只能向函数按值传递参数,就相当于把函数外部的值复制一份给函数的参数。而所谓的按址传递参数,就是把变量在内存中的址传传递给函数,函数内部修改参数值,会反映到函数外相应的变量上。而ES中变量保存的是对象的引用,所以会让人误以为是按址向函数传递的参数。

eg

function changeName ( o ){
	o.name = 'wxt';  //函数内部修改对象的属性值
}
var person = new Object();
person.name = 'lyx';
changeName( person );
alert(person.name);  //函数外部对象的属性值同步更新,为wtx

实际上这就是因为变量保存的是对象的引用,传递给函数参数的值也是对象的引用,所以会导致对象的属性值同步更新,但是修改一下上面代码,就能明显的看出是按值向函数传递参数的。如下:

function changeName ( o ){
	o = {
		name:'wtx'  //函数内改变参数引用的对象,并设置name属性
	}
}
var person = new Object();
person.name = 'lyx';
changeName( person );
alert(person.name);  //函数外部变量引用的对象并没有改变,name值仍然是lyx

4.2.3 类型检测

typeof:一般用来检测基本数据类型,因为如果是引用数据类型,typeof检测值不准确,因为只能检测到是否是对象(另外一些老版本浏览器还可能会返回function),而我们通常想知道属于什么类型的对象。

instanceof:用于检测引用类型值属于什么类型的对象。

eg:

var a = [];
alert ( a instanceof Array ) //变量是array吗?

4.3 执行环境及作用域

4.3.1 基本概念

先看图:

执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。执行环境分为两种

——全局和局部(函数)。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。我们编写代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

全局环境是最外围的执行环境,在web浏览器中,全局环境被认为是window对象。执行环境中的所有代码执行完毕后,所有变量和函数定义也随之销毁(全局环境会到应用程序退出才被销毁)。

每个函数都有自己的执行环境,当代码在一个环境中执行时会创建一个作用域链,其用途是保证有权访问执行环境的变量或函数的有序访问。作用域链最前端始终都是当前环境的变量对象。如果当前环境是一个函数,则将其活动对象作为变量对象。活动变量最开始只包arguments对象。作用域链中下一个变量对象来自包含环境,再一个来自下一个包含环境,直到延伸到全局执行环境。

标识符解析是沿着作用域链一级一级搜索标识符的过程,从最前端开始,找到就立即停止搜索。

内部环境可以通过作用域链访问所有外部环境,但是外部环境不能通过作用域链访问内部环境的任何变量或参数。

延长作用域链的方法有两种,可以在作用域链的最前端临时增加一个变量对象,代码之后完后被移除。

1、with语句,如下例子:

function buildUrl () {
	var qs = '?debug=true';
	with ( location ) {   //把location对象的所有属性和方法加到作用域链最前端
		var url = href + qs;
	}
	return url;
}
alert( buildUrl() );

2、try-catch语句的catch块,对catch语句来水,会创建一个新的变量对象,包含被抛出的错误对象的声明。

4.3.3没有块级作用域

这需要注意在for循环中定义的i在循环结束后仍然存在。

4.4垃圾收集

JS中具有自动垃圾收集机制,常用的垃圾收集方式是标记清除,还有不太常见的引用计数,后者存在循环引用问题。

确保页面占用最少的内存可获得更高的性能,可为不需要的全局变量解除引用(令其=null),解除引用并不意味着自动回收该值占用的内存,而是让值脱离执行环境,以便垃圾收起器下次运行时将其回收。












猜你喜欢

转载自blog.csdn.net/buhuo7493/article/details/80779367