变量

  1. 全局变量:在全局作用域下定义的变量
  2. 私有变量:在私有作用域中定义的变量,只有两种情况是私有变量
  • 声明的变量:带var和function的
  • 形参

此外所遇到的变量都需要基于作用域链机制向上查找

变量提升

当浏览器开辟出供代码执行的栈内存后,代码不是自上而下的立即执行,在此之前需要完成:
把当前作用域里带有var/function关键字的进行提前的声明和定义=>变量提升机制** ,变量提升只发生在当前作用域里面**

  1. var的只提前声明(declare)不定义 ,类似于'var q'的情况,默认值是undefined
  2. function的会完成声明和定义(defined),“a=13”定义其实就是赋值,这是让变量和某个值进行关联
  3. let/const定义变量时,不能进行变量提升

私有作用域的变量提升

  1. 私有作用域形成后,也不是立即代码执行,需要先进行变量提升,**在变量提升之前需要形参赋**值。
  2. es3/es5语法中,只有全局作用域和函数执行的私有作用域(栈内存),其他大括号不会形成栈内存

带var的区别与不带var的区别

全局作用域

  • 不带var,相当于给全局作用域对象window设置一个属性a,变量的值就是属性值,不加VAR的本质是WIN的属性
  • 带var的,是在全局作用域下声明一个变量b(全局变量),但在全局下声明的变量也同样相当于给window增加一个对应的属性(只有全局作用域具备此特点)

私有作用域

  • 带var的在任何私有作用域变量提升阶段,都声明为私有变量,和外界没有任何的关系
  • 不带var的不是私有的变量,会向他的上级作用域查找,看是否为上级的变量,不是的话,继续向上级查找,一直找到window为止(此种机制叫做:作用域链),相当于私有作用域操作的这个非私有变量是一直操作别人的。

    特殊情况下的变量提升

  1. 只对等号左边进行变量提升

    1. /*1注意函数表达式的情况:
    2. 使用函数表达式时,var会进行变量提升,只声明不定义,因此右边的函数处理一样是如此(项目里常用)
  2. 条件判断下的变量提升

    1. 在条件判断中,带function的在旧版本浏览器中会在变量提升时完成声明和定义,但是在新版本浏览器里,为适应ES6,条件判断带function的不管该条件是否成立,只会完成声明,不会进行定义。
    2. 在条件判断中,首先是变量提升,然后才是代码执行。
  1. f = function () {return true;};//=>window.f=...(TRUE)
  2. g = function () {return false;};//=>window.g=...(FALSE)
  3. ~function () {
  4. /*
  5. * 变量提升:
  6. * function g; //=>g是私有变量 g=undefined
  7. */
  8. if (g() && [] == ![]) {//=>Uncaught TypeError: g is not a function (此时的g是undefined)
  9. //=>[]==![]:TRUE g()=>undefined()
  10. f = function () {return false;};//=>把全局中的f进行修改 window.f=...(FALSE)
  11. function g() {return true;}
  12. }
  13. }();
  14. console.log(f());
  15. console.log(g());
  16. /*
  17. * 变量提升:
  18. * function fn;
  19. */
  20. // console.log(fn);//=>undefined
  21. if (1 === 1) {
  22. console.log(fn);//=>函数本身:当条件成立,进入到判断体中(在ES6中它是一个块级作用域)第一件事并
  23. 不是代码执行,而是类似于变量提升一样,先把FN声明和定义了,也就是判断体中代码执行之前,FN就已经赋值
  24. function fn() {
  25. console.log('ok');
  26. }
  27. }
  28. // console.log(fn);//=>函数本身

  1. return 出去的内容不进行变量提升,但是return下面的代码需要进行变量提升
  1. function sum(){
  2. var a=10;
  3. console.log(b);//[function fn]
  4. console.log(c);//undefined
  5. console.log(fn);//fn is not defined
  6. return function(){
  7. console.log("hello");
  8. };
  9. console.log(b);//此处代码不执行
  10. var c=100;
  11. function b(){
  12. var d=10;
  13. }
  14. }
  15. var f=sum();
  16. //
  17. f();//函数的定义发生在变量提升阶段
  18. console.log(a);
  1. 变量名重复,那么不再进行声明,但是要重新定义
  1. console.log(a);// 函数
  2. var a = 100;
  3. console.log(a);// 100
  4. // var a = 1000;
  5. function a() {
  6. }
  7. fn()// 3
  8. var fn = function () {
  9. console.log(0)
  10. }
  11. fn()// 3 0
  12. function fn() {
  13. console.log(1)
  14. }
  15. fn()// 3 0
  16. function fn() {
  17. console.log(2)
  18. }
  19. var fn = 10
  20. function fn() {
  21. console.log(3)
  22. }
  23. fn();// 报错 10() 不成立
  1. 匿名函数不进行变量提升
  1. function f(){}
  2. //函数表达式
  3. var fn=function(){};
  4. fn();
  5. //自执行函数定义和执行是一起完成的
  6. (function(){
  7. console.log(1);
  8. })()
  9. var c=10
  10. var c=1;
  1. es6中的let/const等创建变量或者函数时,不存在变量提升机制
  1. 1. let/const切断了全局变量和window属性的映射机制
  2. 2. 相同的作用域里,基于let创建的变量不能重复声明相同名字的变量(不论之前如何创建,再次使用let创建都会报错)
  3. 3. let/const中没有变量提升,但是有词法解析,在当前作用域代码自上到下执行前,浏览器会进行语法检测,检查所有的变量,当发现有重复的时候
  4. 就会抛出错误代码就不会执行了
  5. 4. 基于LET创建变量,会把大部分{}当做一个私有的块级作用域(类似于函数的私有作用域)
  6. 5. 在基于es6语法时,没有声明变量时,使用typeof检测会直接报错,不是es5之前的undefined,可以解决js的死区

重名问题

  1. 带VAR和FUNCTION关键字声明相同的名字,是重名(就是同一个FN,只是存储值的类型不一样)
  2. 重名处理:名字重复,不会重新的声明,但是会重新的定义(重新赋值)[不管是变量提升还是代码执行阶段皆是如此]
  3. 所谓重复是:不管之前通过什么办法,只要当前栈内存中存在了这个变量,我们使用let/const等重复再声明这个变量就是语法错误
    1. fn();//=>4
    2. function fn() {console.log(1);}
    3. fn();//=>4
    4. function fn() {console.log(2);}
    5. fn();//=>4
    6. var fn=100;//=>带VAR的在提升阶段只把声明处理了,赋值操作没有处理,所以在代码执行的时候需要完成赋值 FN=100
    7. fn();//=>100() Uncaught TypeError: fn is not a function
    8. function fn() {console.log(3);}
    9. fn();
    10. function fn() {console.log(4);}
    11. fn();