JAVAScript的变量、作用域和内存问题

前言:

按照ECMA-262的定义,JavaScript的变量与其他语言的变量有很大的区别。JavaScript变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须保存何种数据类型值得规则,变量的值以及数据类型可以在脚本的生命周期内发生改变。尽管从某种角度看,这可能是一个既有趣又强大,同时又容易出现问题的特性,但JavaScript变量实际的复杂程度还远不止如此。

目录大纲

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

1.赋值变量的值

2.传参

3.检测类型

1.操作符typeof
2.操作符instanceof

二.执行环境以及作用

1.arguments介绍

2.延长作用域链

1.with语句
2.try-catch语句

3.js没有块级作用域

三.垃圾收集机制

1.标记清除

2.引用计数

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

变量包括两种不同的数据类型的值
1.基本类型指的是简单的数据段,包括Undefined、Null、Boolean、Number和String。
2.引用类型指的是保存在内存中,由多个值组成的对象。
创建对象举例

var person = new Object();
person.name = "Nicholos";

注意
1.Object的‘O’一定大写。
2.直接增加属性并且赋值。
3.只能给引用类型才能添加属性,是动态地添加属性。

1.赋值变量的值

基本类型的赋值方法与C语言相同,会增加一个新的空间用于存放副本,变量保存在栈内存中。

var num1= 5;
var num2=num1;
1.png

引用类型的值则不同,引用类型的值是保存在堆内存对象中,JS不允许直接访问内存中的位置,所以引用类型的值是按照引用类型访问的。当一个变量复制到另一个变量中,副本其实是一个指针,两个对象指的是同一个对象。


2.png

2.传参

传参就是把变量的值复制给函数内部的变量,是复制值的过程,永远满足值传递的关系。
引用类型也是复制一个新的指针,实际上指的还是同一个对象。

function setName(obj){
obj.name ="Ac";
obj = new Object();
obj.name = "Bc";
}
var person =new Object();
setName(person);
//person.name ="Ac";

一开始函数内的obj是和person指向同一个对象的,但是obj新声明了一个对象,引用类型的值不再是指向原来的对象的值,而且函数运行完后被销毁。

3.检测类型

1.操作符typeof
var s="Nicholas";
var b= true;
var i =22;
var u;
var n= null;
var o= new Object();

alert(typeof s);  //string
alert(typeof b); //boolean
alert(typeof i);  //number
alert(typeof u); //undefine
alert(typeof n); //object
alert(typeof o); //object

null和object都是返回object

2.操作符instanceof
alert(person instanceof Object);// person 是Object吗?
alert(colors instanceof Array );// colors 是Array吗?
alert(pattern instanceof RegExp);// pattern 是RegExp吗?

是的话,就返回一个true,不是的话就返回一个false。

二.执行环境以及作用

执行环境(简称 环境)定义了变量和函数有权访问的其他的数据。每一个环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
全局环境是一个最外围的执行环境,web中一般认为全局环境是window对象,全局环境会一直运行到应用退出它所定义的函数和变量才会被销毁。
每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,函数执行完后,栈将环境弹出,把控制权返回给之前的执行环境。
当函数在一个环境中执行的时候,会创建一个作用域链,是为了保证对执行环境有权访问的所有变量和函数有序的访问,作用域链的前端,始终都是当前执行代码所在环境中变量对象。如果环境是函数,将其活动对象作为变量对象。活动对象最开始只包含一个变量-----arguments(arguments在全局环境中不存在)对象,作用域链的下一个变量对象来自包括外部的环境,一直延续到全局执行环境。

1.arguments介绍

arguments是JS中每个函数(除全局环境外)都有的类数组对象,用于储存函数传入的参数。

  • arguments.length 记录参数个数。
  • arguments.callee 储存调用这个函数的代码。
  • arguments可以实现函数的重载。
function add() {
    var len = arguments.length,
        sum = 0;
    for(;len--;){
        sum += arguments[len];
    }
    return sum;
}

console.log( add(1,2,3) );   //6
console.log( add(1,3) );     //4
console.log( add(1,2,3,5,6,2,7) );   //26

标识符解析是沿着作用域链一级一级的搜索标识符的过程,从作用域链的前端开始,逐级地向后回溯,直到找到标识符为止。
搜索标识符举例:

      var scope = "global";   //全局
      function fn1(){
         return scope; 
      }
      fn2();
作用域链

函数嵌套的作用域链举例:

  
作用域链

说明:当调用outer函数,inner函数的作用域链已经初始化了(即复制父函数的作用域链,再在前端插入自己的活动对象)

2.延长作用域链

1.with语句:

作用:接收一个对象,将指定对象添加到作用域链中。
with语句使用方法:

with(people) 
{ 
       var str = "姓名: " + name + "
"; str += "年龄:" + age + "
"; str += "性别:" + gender; document.write(str); }

优点是不用多次写对象的名字,在代码块里直接使用对象的值,但是注意with语句内不能改变对象的属性,改变对象的属性还是要引用对象来改变。

2.try-catch语句:

作用:catch语句产生一个新对象添加到作用域链的前端,主要用来检测代码中的错误。
try-catch的用法:

try{
    //可能会导致出错的代码
}catch(error){
  alert("catch an error");
}

当try运行的代码运行出现错误的时候,就会立即退出代码进程,执行catch语块,catch接收到一个包含错误对象的信息,对象下的message是包含错误信息,对象的名字要自己起。

3.JS没有块级作用域

花括号的边界表示一个块,但是在JS中,花括号封闭的的代码中声明的变量会添加到当前的执行环境。

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

用关键字let让生命的变量只在块作用域内有效。

for(let i=0;i<5;i++){
  //操作
}
alert(i); //ReferenceError: i is not defined

三.垃圾收集机制

JS中会自动找出不再使用的变量,释放其占用的内存,按照固定是时间间隔,周期性地重复操作。

1.标记清除

当变量进入环境的时候就标记“进入环境”,当环境离开环境的时候就标记为“离开环境”。

2.引用计数

引用计数是根据每个变量使用的次数。
1.声明一个变量并且将引用类型的值赋值给该变量,这个的引用次数加一。
2.同一个值赋值给另一个变量,该值的引用次数加一。
3.包含这个值的引用变量又取得了另外一个值,该值的引用次数减一。
4.该值的引用次数变成0时,等待垃圾收集器运行时释放该值所占的内存。

但是此机制有弊端:

function problem(){
     var  a =new Object();
     var  b =new Object();
     
     a.some = b;
     b.some = a;
}

例子中的两个对象通过各自的属性相互引用,两个对象的引用次数都是2,不会是0。

参考文献:

  • 《JavaScript高级程序设计(第三版)》
  • https://blog.csdn.net/whd526/article/details/70990994
  • https://blog.csdn.net/qq_16339527/article/details/53231725
  • https://www.jianshu.com/p/f7abecee0691
  • https://www.jb51.net/article/12326.htm

你可能感兴趣的:(JAVAScript的变量、作用域和内存问题)