JavaScript的数据类型分为基本数据类型和引用数据类型。基本数据类型包括number、string、boolean、null和undefined,引用数据类型主要是对象object: [ ]-->数组、{ }-->对象、/$/-->正则表达式、Date。(区别:基本数据类型是按照值来进行操作的,引用数据类型是按照引用地址来进行操作的。)
≯注意:基本数据类型是通过值来操作的,引用类型是通过引用地址来操作的,特别注意的是,函数的存储是把代码块作为字符串进行存储的。
浏览器在加载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;
运行结果:
结果分析:带var的变量在一开始可以进行预解释,所以在执行代码的时候已经存在了变量num1,只是没有声明赋值,所以在声明前输出不会出现错误,但是输出为undefined,而不带var的变量不能进行预解释,所以在复制前执行会报错。(这就是在全局作用域中,声明变量时带关键字var和不带的区别)
var num1=12; console.log(num1);//输出12 num2=12; console.log(num2);//输出12
运行结果:
结果分析:如果都在声明赋值后面进行输出操作,那么都正常输出12,这是因为:
1、num2=12:相当于给window增加一个叫做num2的属性名,属性值为12。
2、num1=12:相当于给全局作用域增加一个全局变量num1,也相当于给window增加一个属性名为num1,属性值为12。
结果分析:在函数fn中,total是私有变量,但输出在定义之前,则输出为undefined,又因为私有的不能改变全局的,所以在外面输出的total为0.
结果分析:在函数fn中total不是私有变量,所以输出时会报一个错误,程序报了错误,后面的代码将不会再执行。
结论分析:在fn函数中total不是私有变量,total=100在当前作用域的上级作用域中增加一个属性名为total,属性值为100,输出total相当于window.total。
≯注意:如果是获取值,如console.log(total)--->会报错
如果是设置值,如total=100---->不报错,相当于给window增加一个属性名为total,属性值100