JS变量与作用域-2

1.作用域
变量起作用的区域或范围:变量的生命周期和能访问到变量的区域
全局作用域:函数体外部,函数内也可以访问,当所有的程序执行完毕才释放(全局变量会污染,尽量少写)
局部作用域:函数作用域,只能在函数体内部访问,函数执行完毕就释放
JS中没有块级作用域{…}

function fn(){
	var x = y = 1;
}
fn();
console.log(y);
console.log(x);

结果为1 报错,在函数内部不用var声明的是全局变量,y可以输出

var name = 'xm';
function fn(){
	name = 'xh';
	console.log(name);
}
fn();
console.log(name);

结果为 xh xh,函数中的name没有使用var定义,会先在函数中查找是否定义了name。如果没有定义,会向上一级作用域也就是全局下查找name。发现全局中已经定义了name,所以函数中name='xh’是为全局变量name重新赋值了。即在全局下输出和在函数中输出结果都是‘xh’。

2.变量对象
所有全局空间的属性和函数,都是window的属性和方法

var name = 'xm';//等价于window.name
function fn(){//等价于window.fn
	var sex = 'male';//等价于fn.sex,局部作用域的变量对象看不见摸不着,但JS引擎会用到
	function fn2(){//等价于fn.fn2
		var age = 18;
	}
}
console.log(person);//报错
console.log(window.person);//不存在的属性并不会报错,返回undefined

3.作用域链

var name = 'xm';
function fn(){
	var name = 'xh';
	var sex = 'male';
	function fn2(){
		var name = 'xhei';
		var age = 18;
	}
}

作用域链如下
在这里插入图片描述
当在fn2中输出属性时,会先查找自身作用域,如果找到则输出并停止查找,如果未找到则查找上一层作用域,若一直未找到最终会查找window的作用域,即内层可以调用外层的变量,但外层无法调用内层变量
同名变量越内层优先级越高
作用域链越长查询越慢,局部变量优于全局变量,内层优于外层变量

延长作用域链

var person = {};
person.name = 'xm';
person.sex = 'male';
var score = 4;

with(person){
	name = 'xh';
	sex = 'female';
	score = 44;
}

可以通过with增加一个以person为变量对象的小作用域,其内的name相当于person.name,当没有person.score时它会查找外层作用域(with容易出问题,尽量避免使用)

<html>
<head>
    <meta charset="utf-8">
	<title>变量、作用域</title>
    
</head>
<body>
	<button>1</button>
	<button>2</button>
	<button>3</button>
    <script type="text/javascript">
         var btns = document.getElementsByTagName('button');
         for (var i = 0; i < 3; i++) {
            	btns[i].onclick = function () {
		    	alert(i + 1);
	    	};
	   }
    </script>
</body>
</html>

由于点击按钮触发事件函数,建立一个新的作用域,但此时循环已经结束,i值为3,所以每个按钮弹出的都是4

    var btns = document.getElementsByTagName('button');
	for (var i = 0; i < 3; i++) {
		OOO(i);
	};
	function OOO(i){
		btns[i].onclick = function (){
		alert(i+1);
	}
	}

将点击事件置于单独的函数中,每一次循环都将当前的i值传入函数作用域,当点击事件发生时往上寻找,找到的都是函数内的i值,就可以正常弹出1/2/3

4.JS的解析机制
过程:先进行预解析,再逐行解读代码
预解析(解读代码时函数的声明部分直接跳过):先全局后局部进行,首先查找var,并将所有声明的变量赋值undefined,再查找function关键字,直接对函数初始化。当变量名与函数名冲突时,比如都为name,预解析只保留函数(优先级更高);当两个函数重名时,预解析保留后面那个。
firefox老版本的浏览器无法预解析{…}代码块内的函数。
补充:函数的参数与局部变量同等对待

<script>
	console.log(a);
</script>
<script>
	var a = 1;
</script>

由于预解析分标签进行,浏览器会报错,如果将两条语句调换位置,则不会有问题(即先声明后打印)

var a = 1;
function fn(){
	console.log(a);
	a = 2;
}
fn();
console.log(a);

由于函数内部没有预解析,所以执行到函数调用时打印出的是全局变量的值!但若函数带有参数,函数内部就有预解析。

5.垃圾收集机制
释放无用的数据,回收内存
分为自动、手动收集
JS有自动回收机制
原理:找出没用的数据,打上标记,释放其内存(垃圾收集器按照一定时间间隔周期性执行)

标识无用数据的策略:
标记清除:一次性为所有变量都打上标记,去掉环境中的变量(还没有离开执行环境的变量)和被这些变量所引用变量的标记,回收剩下的变量对应的内存(主流方法)
引用计数:跟踪记录每个数据被引用的次数,当值的引用次数变成0时就回收内存(由于循环引用的存在,已经放弃)–IE6-8浏览器依然存在循环引用的问题

6.内存管理
由于分配给Web浏览器的内存少于桌面应用程序的内存,内存需要优化,只保留内存中有用的数据,没用的就释放掉(手动设置为null)

补充:没用var的声明方式,不管在哪里声明,它都是全局变量(不会预解析)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值