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

本文深入探讨JavaScript中变量的基本类型与引用类型,解释了执行环境、作用域链以及垃圾回收机制,帮助理解内存管理。

一、基本类型和引用类型的值

  1. 基本类型:

    • Undefined
    • Null
    • Boolean
    • Number
    • String
      这5种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值
  2. 引用类型:

    引用类型的值是保存在内存中的对象。

    JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。

    在操作对象时,实际上是操作对象的引用而不是实际的对象

    为此,引用类型的值是按引用访问的

  3. 引用类型可以动态添加属性但是基本类型不行

    	var person = new Object()
    	person.name = 'Nike'
    	alert(person.name)
    
  4. 复制变量值

    • 基本类型原变量与复制后的变量是完全独立的

    • 引用类型原变量与复制后的变量将引用同一个对象:复制后的变量的值实际上是一个指针,而这个指针指向存储在堆中的对象。
      如果改变其中一个变量就会影响另一个变量

        var obj1 = new Object()
        var obj2 = obj1
        obj1.name = 'Nike'
        alert(obj2.name) // 'Nike'
      
  5. 传递参数:

    • 基本类型值的传递如同基本类型变量的复制一样
    • 引用类型值的传递如同引用类型变量的复制一样
    	function addTen(num) {
    		num += 10
    		return num
    	}
    	
    	var count = 20
    	var result = addTen(count)
    	alert(count) // 20
    	
    	// 基本类型的变量传入后就变成了局部变量
    	alert(redult) // 30
    
    	function aetName(obj) {
    		obj.name = 'Nike'
    	}
    	
    	var person = new Object()
    	setName(person)
    	// 全局对象
    	alert(person.name) // 'Nike'	
    
    	function setName(obj) {
    		obj.name = 'Nike'
    		obj = new Object()
    		obj.name = 'Greg'
    	}
    	
    	var person = new Object()
    	setName(person)
    	// 函数内部重写obj时,这个变量引用的就是一个局部变量
    	// 这个局部变量在函数执行完毕后会被立即销毁
    	alert(person.name) // 'Nike'
    
  6. 检测类型

    • typeof(检测基本类型时)
    	var s = 'Nike'
    	console.log(typeof s) // 结论为字符串的形式:'string'
    	
    	var b = true
    	console.log(typeof b) // 结论为字符串的形式:'boolean'
    	
    	var d = 22
    	console.log(typeof d) // 结论为字符串的形式:'number'
    	
    	var u
    	console.log(typeof u) // 结论为字符串的形式:'undefined'
    	
    	var n = null
    	console.log(typeof n) // 结论为字符串的形式:'object'
    	
    	var o = new Object()
    	console.log(typeof o) // 结论为字符串的形式:'object'
    	
    	var f = function() { let c = 1 }
    	console.log(typeof f) // 结论为字符串的形式:'function'
    	
    	var p = /\D/gi
    	console.log(typeof p) // 结论为字符串的形式:'object'
    
    • instanceof(检测引用类型时)
    	var a1 = { a: 1}
    	var a2 = [1,2,3]
    	var a3 = /\D/gi
    	
    	console.log(a1 instanceof Object) // 结论为布尔类型的形式:'true'
    	console.log(a2 instanceof Array) // 结论为布尔类型的形式:'true'
    	console.log(a3 instanceof RegExp) // 结论为布尔类型的形式:'true'
    

二、执行环境及作用域

  1. 执行环境定义了变量或函数有权访问的其它数据,决定了它们各自的行为
  2. 机理:每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
  3. 全局执行环境是最外围的一个执行环境
  4. 根据ECMAScript,所在的宿主环境不同,表示的执行环境对象也不一样
  5. 在Web浏览器中,全局执行环境是window对象,关闭网页或浏览器是销毁
  6. 每个函数都有自己的执行环境
  7. 作用域链的产生:当代码在一个环境中执行时,会创建变量对象的一个作用域链(这里变量对象是一个特定名词)
  8. 作用域链的用途:保证对执行环境有权访问的所有变量和函数的有序访问
  9. 作用域链的长相:
    • 当前执行代码所在环境的变量对象
    • 包含(外部)环境的变量对象
    • 包含(外部)环境的变量对象
    • 全局执行环境的变量对象

如果这个环境是函数,则其活动对象作为变量对象(对下)

	// 全局作用域
	var color = 'blue'
	
	function changeColor() {
		// 局部作用域
		if (color === 'blue') {
			color = 'red'
		} else {
			color = 'blue'
		}
	}
	changeColor()
	console.log("Color is now " + color )
	// 全局环境
	var color = 'blue'
	function changeColor() {
	
		// changeColor()局部环境
		var anotherColor = 'red'
		function swapColors() {
		
			// swapColors()局部环境
			var tempColor = anotherColor 
			anotherColor = color         
			color = tempColor
			// 这里可访问 color anotherColor tempColor
		}
		
		// 这里可访问 color anotherColor
		swapColors()
	}
	
	// 这里可访问color
	changeColor()
  1. 延长作用域链:

    • 在作用域链的最前面添加一个变量对象
      • try-catch语句的catch块:会创建一个新的变量对象,其中包含被抛出的错误对象
      • with语句:会将指定的对象添加到作用域链中
      	function buildUrl() {
      		var qs = "?debug=true"
      		
      		/** 
      		** with语句接收location对象
      		** 因此其变量对象包含了location对象的所有变量和方法
      		*/
      		with(location){
      			// href 相当于 location.href
      			var url = href + qs
      		}
      		
      		return url
      	}
      
  2. 没有块级作用域
    例如:

    if块

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

    for块

    		for (var i = 0; i < 10; i++){
    			doSomething(i)
    		}
    		
    		alert(i) // 10
    
  • 声明变量:

    1.使用var声明的变量会自动被添加到最接近的环境

    2.函数内部,最接近的环境是函数军局部环境

    3.with语句中,最接近的环境是函数环境

    4.如果初始化变量没有用var,该变量会自动被添加到全局环境中

    • 函数内声明:
    	function add(num1, num2) {
    		var sum = num1 + num2
    		return sum
    	}
    	
    	var result = add(10, 20) // 30
    	alert(sum) // 由于sum不是有效的变量,因此会导致错误
    
    • 函数未声明:
    	function add(num1, num2) {
    		sum = num1 + num2
    		return sum
    	}
    	
    	var result = add(10, 20) // 30
    	alert(sum)				 // 30
    
  • 查询标识符

    1.搜索从作用域链的前端开始,向上级查询与给定名字匹配的标识符

    2.局部环境中找到则停止,否则继续沿作用域链向上搜索

    3.搜索过程追溯到全局环境的变量对象

    4.如果全局环境中没有,则该变量未声明

    	var color = 'blue'
    	
    	function getColor() {
    		return color
    	}
    	
    	alert(getColor()) // 'blue' 搜索至全局才停止
    
    	var color = 'blue'
    	
    	function getColor() {
    		var color = 'red'
    		return color
    	}
    	
    	alert(getColor()) // 'red' 搜索至函数环境停止
    

三、垃圾收集

  1. JavaScript垃圾回收机制的原理:

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

  2. 垃圾回收策略:标记清除(主流) 与 引用计数

  3. 有时间可以深究一下这个单元

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值