js中的预解析(变量提声)、作用域链、闭包机制

JavaScript的数据类型分为基本数据类型引用数据类型。基本数据类型包括number、string、boolean、null和undefined,引用数据类型主要是对象object: [ ]-->数组、{ }-->对象、/$/-->正则表达式、Date。(区别:基本数据类型是按照值来进行操作的,引用数据类型是按照引用地址来进行操作的。)

js中的预解析(变量提声)、作用域链、闭包机制
js中的预解析(变量提声)、作用域链、闭包机制
   ≯注意:基本数据类型是通过值来操作的,引用类型是通过引用地址来操作的,特别注意的是,函数的存储是把代码块作为字符串进行存储的。
   浏览器在加载html页面的时候,首先会提供一个供全局js代码执行的环境,这个环境叫做全局作用域(window).
    JavaScript中内存主要分为栈内存堆内存
       栈内存:用来提供一个供减速带吗执行的环境(全局作用域或私有作用域);
       堆内存:用来存放引用数据类型的值,如对象存储的是属性名和属性值,函数存储的是代码字符串。
 1、作用域链 
    JavaScript中有全局变量私有变量,如何区分全局变量和私有变量?
        全局变量:在全局作用域中声明的变量,在一开始会被预解释的变量。
        私有变量:在私有作用域中声明的变量(var)或者是函数的形式参数。
    函数执行的目的是让函数体中的代码执行,而函数执行的步骤为:1、如果函数有形参,则先给形参赋值 2、进行私有作用域中的预解释 3、私有作用域中的代码从上到下执行。
    所以按照函数的执行步骤,在私有作用域中,我们代码在执行的时候遇到一个变量,我们要先确定它是否为私有变量,如果是私有变量,那该变量就和函数外的操作没有任何关系,如果不是私有变量,那就要从当前作用域的上级作用域开始查找,如果上级作用域中也没有则继续进行查找直到window,这就叫做作用域链
 2、“闭包”机制
     因为函数会形成一个新的私有作用域,私有作用域会保护函数里面私有变量不受外界干扰,也就是说在外面修改不了私有的变量,在私有变量也修改不了外面的变量。这就是一种保护机制,叫做“闭包”。
  3、预解释:
     在当前作用域中,js代码执行之前,浏览器会默认把所有带var和function进行提前声明(declare)或者提前定义(defined)。
       声明:如var num;,就是告诉浏览器在全局作用域中有一个num变量了。
       定义:如num=12;,给变量num赋值为12。
     ≯注意:预解释只发生在当前作用域下,如一开始的时候只是在window下执行。而在函数的私有作用域中,只有函数执行的时候才对函数中的变量/函数进行预解释。
  3.1 对于带var和function关键字在预解析中的操作是不一样的:
     带var关键字:在预解释时只是进行提前的声明。
      带function关键字:在预解释时把提前声明和定义都完成。
 4 全局变量的细节问题
	console.log(num1);//undefined
	var num1=12;

	console.log(num2);//错误Uncaught ReferenceError:num2 is not defined
	num2=12;
 运行结果:
js中的预解析(变量提声)、作用域链、闭包机制js中的预解析(变量提声)、作用域链、闭包机制
 结果分析:带var的变量在一开始可以进行预解释,所以在执行代码的时候已经存在了变量num1,只是没有声明赋值,所以在声明前输出不会出现错误,但是输出为undefined,而不带var的变量不能进行预解释,所以在复制前执行会报错。(这就是在全局作用域中,声明变量时带关键字var和不带的区别)
	var num1=12;
	console.log(num1);//输出12

	num2=12;
	console.log(num2);
//输出12
 运行结果:
js中的预解析(变量提声)、作用域链、闭包机制js中的预解析(变量提声)、作用域链、闭包机制
结果分析:如果都在声明赋值后面进行输出操作,那么都正常输出12,这是因为:
 1、num2=12:相当于给window增加一个叫做num2的属性名,属性值为12。
  2、num1=12:相当于给全局作用域增加一个全局变量num1,也相当于给window增加一个属性名为num1,属性值为12。
js中的预解析(变量提声)、作用域链、闭包机制 js中的预解析(变量提声)、作用域链、闭包机制
js中的预解析(变量提声)、作用域链、闭包机制js中的预解析(变量提声)、作用域链、闭包机制
结果分析:在函数fn中,total是私有变量,但输出在定义之前,则输出为undefined,又因为私有的不能改变全局的,所以在外面输出的total为0.
js中的预解析(变量提声)、作用域链、闭包机制 js中的预解析(变量提声)、作用域链、闭包机制
js中的预解析(变量提声)、作用域链、闭包机制js中的预解析(变量提声)、作用域链、闭包机制
结果分析:在函数fn中total不是私有变量,所以输出时会报一个错误,程序报了错误,后面的代码将不会再执行。
js中的预解析(变量提声)、作用域链、闭包机制 js中的预解析(变量提声)、作用域链、闭包机制
js中的预解析(变量提声)、作用域链、闭包机制js中的预解析(变量提声)、作用域链、闭包机制
结论分析:在fn函数中total不是私有变量,total=100在当前作用域的上级作用域中增加一个属性名为total,属性值为100,输出total相当于window.total。
≯注意:如果是获取值,如console.log(total)--->会报错
        如果是设置值,如total=100---->不报错,相当于给window增加一个属性名为total,属性值100