5-11、JS变量和作用域

查漏补缺:
  • 变量本质是保存数据的容器
  • 变量名的命名规则: 只能出现 $ _ 字母数字,数字不能开头
  • js变量名区分大小写
  • 关键字和保留字不能用作变量名
  • 命名使用驼峰法 或 _ 连接
  • 计数器for嵌套里边的使用 i / j / k
  • 声明变量使用var 可以用 , 命名多个。
数据类型和堆栈
  • 基本类型和引用类型

基本类型不可变,存放在栈内存中
引用类型是可修改的,保存再堆内存

堆栈:
两者都是存放临时数据的地方。
栈是先进后出的,就像一个桶,后进去的先出来,它下面本来有的东西要等其他出来之后才能出来。
堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。对于堆,我们可以随心所欲的进行增加变量和删除变量,不用遵循次序。
栈区(stack) 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
堆区(heap) 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。

访问的时候,基本类型直接访问栈,引用类型访问栈中保存的堆的地址,然后指向堆中的数据。

变量比较

基本变量可以直接比较。
引用变量不可以直接比较。看上去一样,但是地址并不一样。
在这里插入图片描述
如果进行xh=xm; 那么就一样了,因为已经把xm的地址赋值给xh了。

值的复制

基本数据类型复制相当于新增。

引用类型复制相当于复制了栈地址,如果操作其中一个,那么都是操作了数据本体。
在这里插入图片描述

如何复制一个引用类型呢?
声明一个新的对象,遍历旧的对象,给到新的对象
在这里插入图片描述
这种拷贝叫做浅拷贝,因为只能基本类型的复制,如果里边有引用类型,例如数组family:[];,那么两个对象中的family都是指向一个。
深拷贝涉及到递归,以后再讲。

参数传递

12是实参,ab是形参。

    function add(a,b){
      return a+b;
    }
    add(1,2);

基本类型传递参数:
直接复制,没什么特殊的。
在这里插入图片描述
引用类型:
引用类型传递的是地址,所以再里边修改,外部的person也变了。

在这里插入图片描述
参数的传递都是按值传递的。
基本类型的数据传递是按值来传递的。
引用类型传递传递的也是值,但是传递的是地址值。

例子:输出的是xm
obj = {};是指向了一个新的对象,所以后边操作的不是person所指向的数据。
在这里插入图片描述

类型检测

typeof检测数据类型。
console.log(typeof 4);

instanceof 检测引用类型,且只能检测引用了类型,否则返回false。

变量的作用域

分为 全局作用域、局部作用域

局部作用域一般是在函数作用域。

    var a = "a";
    function add(){
      var b = "b";
    }
    console.log(a);	//输出
    console.log(b);	//错误,无法访问到

生命周期:
全局变量的生命周期在所有的函数执行完成之后才会挂掉
局部变量的生命周期在函数结束之后就会挂掉

作用域链

在这里插入图片描述

调用某个对象的时候,根据作用域链进行查找。
层数较多的时候,查询速度会越来越慢。

延长作用域链

with可以做到,但是尽量不要用。

JS解析机制

⭐⭐⭐先预解析,后逐行读代码。
实例:

<script>
var name="xm";
var age=18;
function fn(argument){
	console.log(name);//输出未定义:undefined
	var name="xh";
	var age=12;
}
</script>

解析:

全局作用域,局部作用域,都是通过以下两个步骤进行预解析的。

1,先读取有var 的变量(没有使用var的变量是不会被预解析的),给赋值为:undefined。如果两个变量重名,并不影响预解析的过程,就写一个变量就行,因为都将变量赋值为undefined(在逐行读取时,只是不同的赋值而已。),如果有函数名和变量重名,那就直接去掉变量,不进行解析。如果函数中存在参数,那么参数也一样使用var进行解析。如:var argument=undefined;

2,再读取function后面的函数—fn,如果有多个函数名重复,那么取最后面一个函数进行声明。

上面实例有两个作用域,一个是window变量对象的全局作用域,一个是fn变量对象的局部作用域。

预解析过程如下:

1,window:

var name=undefined;
var age=undefined;

function fn(argument){
	console.log(name);
	var name="xh";
	var age=12;
}

2,fn:

	var name=undefined;
  var age=undefined;
  var argument=undefined;

预解析就完成了。然后就是逐行解读代码。
通过逐行解读代码进行赋值,改变变量属性值。如果遇到函数,那么就直接跳过,因为预解析时已经声明过。
所以,上面实例:console.log(name); 输出为: undefined。

实例1:

<script>
console.log(fn);
function fn(){}; //预解析:function fn(){};
</script>

输出结果:function fn(){};

实例2:

<script>
console.log(fn);
  var fn=function(){}; //预解析:var fn=undefined;
</script>

输出结果:undefined 未定义。

实例3:

<script>
console.log(a);
//所以这里a是没有定义,运行就报错。运行未定义变量报错,运行未定义属性返回undefined
   a=1;//预解析没有变量。
</script>

输出结果:这里的a没有定义,所以报错,未定义。

预解析遇到的问题

变量名和变量名冲突,后覆盖前。
变量名和函数名冲突,函数名留下。
函数名和函数名冲突,后覆盖前。

不要再 if for块里定义函数!!

案例:

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

结果:

a()
1
1
3
3
错误

案例:

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

案例:

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

//  undefined
//  1

案例:
这里注意,预解析的事var ,全局变量没有var

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

//  1
//  2

案例:

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

//  undefined
//  1

案例:

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

//  1
//  1
垃圾搜集机制

释放无用的数据,回收内存。
分为 自动收集 和 手动搜集。
原理:找出没用的数据,打上标记,释放其内存。

辨识无用数据的策略:

  • 标记清除(最常用)
  • 引用计数
// 引用计数举例,当引用次数为0的时候,回收
	var xm = {
      name:"xm",
      age:16
    }//1
    var xh = xm; //2
    xh = {}; //1
    xm = {}; //0
内存管理

内存分配原则:
Web浏览器 < 桌面应用程序

优化内存的方式:
将不用的内存解除引用;

一般解除全局变量,因为局部变量在局部结束的时候会被自动释放。

var arr = [...];
//用完之后:
arr = null;		//释放内存
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值