var let const 无关键字定义变量

作用域控制着变量与参数的可见性与生命周期。首先理解两个概念:块级作用域与函数作用域。

1.全局作用域
(1) 全局作用域在页面打开时被创建,页面关闭时被销毁
(2) 编写在script标签中的变量和函数,作用域为全局,在页面的任意位置都可以访问到
(3) 在全局作用域中有全局对象window,代表一个浏览器窗口,由浏览器创建,可以直接调用
(4) 全局作用域中声明的变量和函数会作为window对象的属性和方法保存

1.块级作用域

任何一对花括号 {} 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。比如if() {} ,for() {}中的花括号都是块级作用域

为什么需要块级作用域?

  在ES5中,只有全局作用域和函数作用域,不存在块级作用域,这就会导致如下问题的发生

  • 1)内层变量覆盖外层变量
  • 2)用于循环的计数变量会泄露为全局变量

2.函数作用域

很明显是function(){}的形式,定义在函数中的参数和变量在函数外部是不可见的

调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁。每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的。在函数作用域中可以访问到全局作用域的变量,在函数外无法访问到函数作用域内的变量。在函数作用域中访问变量、函数时,会先在自身作用域中寻找,若没有找到,则会到函数的上一级作用域中寻找,一直到全局作用域

var是忽视块级作用域的,也就是说在块级作用域中用var定义,在外部是可以访问到变量值得,var只有在函数作用域中声明外部才不能访问。而且var声明的变量会被声明提前,被提升到作用域顶部,并被赋值为undefinded

const和let是有块级作用域概念的,也就是说在块级作用域中用const或者let定义,外部无法访问变量,且不可以声明提前

var

1)可重复定义 

2) 声明时可以不赋值

3)js程序在正式执行之前,会将所有var 声明的变量和function声明的函数,预读到所在作用域的顶部,但是对var 声明只是将声明提前,赋值仍然保留在原位置

4)无法定义块级作用域变量,在块级作用域中定义相当于定义了一个全局变量

let

1)可以声明时不赋值

2)在同一作用域中不可以重复定义(也包括不能和var,const变量名重复)

3)不会被声明提前(与var有区别)

4)可以声明块级作用域的变量,块级作用域外无法访问内部变量

const

1)当声明时不赋值报错

2)当试图改变const常量时报错

3)在同一作用域中重复定义报错

4)不会被声明提前(与var有区别)

5)可以声明块级作用域的变量,块级作用域外无法访问内部变量

本质:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
    - 简单数据类型( 数值、字符串、布尔值): 值就保存在变量指向的那个内存地址,因此等同于常量
    - 复合数据类型( 对象和数组) : 变量指向的内存地址,保存的只是一个指向实际数据的指针 , const只能保证这个指针是固定的 至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
对象冻结:如果希望将一个对象进行冻结,可使用Object.freeze():

const person = Object.freeze({})

但上面的冻结方式只是将其对象本身冻结,其对象的属性也应该冻结,我们可以使用如下函数:

var constantize = (obj) => {
    Object.freeze(obj);
    Object.keys(obj).forEach( (key, i) => {
        if ( typeof obj[key] === 'object' ) {
            constantize( obj[key] );
        }
    });
};

无关键字定义变量

在函数作用域中,不使用变量关键字声明的变量,在赋值时会往上一级作用域寻找已经声明的同名变量,直到全局作用域时还没找到,则会成为window的属性

小结:建议多使用let,毕竟for中的i一般不想被泄露出来,而且if中定义的变量一般只想在条件成立时才定义,实现这些都需要用let,而且let没有变量被声明提前的困扰,其他两者没有太大区别,所以还是改成用let声明变量吧

猜你喜欢

转载自www.cnblogs.com/icctuan/p/12132190.html