var let const

var

接受重复声明

var a = 1;
var a = 2; 
console.log(a) // 2

变量预解析

有时候叫 变量提升,就是在声明前使用

console.log(a)//undefined
var a = 12;

function fn(){
    alert(a);  // undefined
    var a = 5;
}
fn()

不支持块级作用

支持全局作用域局部(函数)作用域

for(var i = 0;i < 10; i++){
    // 
}
// 输出10,i=10结束
console.log(i)

if(false){
	var a = 10
}
console.log(a) // 10

if(true){
	var a = 10
}
console.log(a) // 10

挂载window

在ES5中,全局变量直接挂载到全局对象window的属性上,

所以能在window上看到 var 和 function声明的全局变量

var a = 10;
function f(){};

console.log(window.a); // 10
console.log(window.f); // f(){}

let

不接受重复声明

let a = 1;
let a = 10; //报错

不支持变量预解析

console.log(a); //报错,没有变量预解析
let a = 1;

let a = 1;
function fn(){
    console.log(a);  
    let a = 5;
}
fn();

var m = 10;
function fun(){
    m = 20;  
    let m;
    console.log(m);
}
fun();//报错,暂时性死区

//支持块级作用域
   {
      var a=1
      let g='zhou'
   }
      console.log(a)//1
     //console.log(g)//报错  ReferenceError: a is not defined.

不影响作用域链

   {
      let s='外层块级'
      function fn(){
        console.log("s");
      }
      fn();
   }

不能挂载window

使用 let / const 声明全局变量,会被绑定到Script对象而不是Window对象

而let、const声明的全局变量在window对象上看不到,在script中形成了一个块级作用域

这样在全局就可以访问到

let a = 1;
const B = 2;

console.log(window.a); // undefined
console.log(window.B); // undefined
console.log(a);     // 1  通过块作用域访问到的
console.log(B);   // 2 通过块作用域访问到的

使用var / let / const 声明的局部变量都会被绑定到 Local (本地)对象。

注:Script对象、Window对象、Local对象三者是平行并列关系。

块级作用域

1、通过var定义的变量可以跨块作用域访问到。

 {
        var a = 1;
        console.log(a); // 1
    }
    console.log(a); // 1

2、通过var定义的变量不能跨函数作用域访问到

 (function A() {
        var b = 2;
        //console.log(b); // 2
    })();
   console.log(b); // 报错,

3、var定义的变量没有块级作用域

 if(true) {
        var c = 3;
    }
 console.log(c); // 3

有意思的地方

for(var i = 0; i < 4; i ++) {
        var d = 5;
    console.log(i)// 0 1 2 3
    };
 console.log(i); // 4(循环结束i已经是4,所以此处i为4)
 console.log(d); // 5

if 语句和 for 语句中用 var 定义的变量可以在外面访问到,可见,if语句和for语句属于块作用域,不属于函数作用域。

关于for循环的循环变量问题

for(var i =0 ;i < 5; i++){
    
}
alert(i); // 5  可以获取括号里的 i

let i = 7;
for(let i =0 ;i < 5; i++){
    //let i="里面的i"//这里会覆盖上面括号的i
    console.log(i)//0 1 2 3 4
}
console.log(i); //7  括号()里应该也算块作用域,和{}不是同一个,下面有解释

let i = "window";
for(let i = 0; i < 10 ;i++){
    let i = 5
    
for(let j = 0,i = 101; j < 10 ;j++){
    let i = 102
    console.log(i)
            }
        }

for(let i =0 ;i < 10; i++){
    console.log(i); 
}
alert(i); //window
for循环的计数器,就很合适使用let命令。

for (let i = 0; i < 10; i++) {
  // ...
}

console.log(i);
// ReferenceError: i is not defined

for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域(同一个作用域 let 不能重复声明同一个变量)

暂时性死区

使用let、const声明的变量,在声明之前使用这些变量,就会报错。

var tdz = 123;

if (true) {
  tdz = 'abc'; // 报错
  let tdz;
}

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(TDZ)

const

特性同let

(不接受重复声明、不支持变量预解析、块作用域、不挂载window)

const声明一个只读的常量一旦声明常量的值不能改变

一般常量使用大写(潜规则)

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

一旦声明,必须立即初始化,不能留到以后赋值

const foo;
// SyntaxError: Missing initializer in const declaration

const a;
a = 1;
console.log(a);  // 报错  语法错误
//Uncaught SyntaxError: Missing initializer in const declaration 
//缺少初始值在常量定义时

不接受重复声明

var message = "Hello!";
let age = 25;

// 以下两行都会报错
const message = "world";
const age = 30;

const定义的对象属性是否可以改变

const person = {
     name : 'zs',
     sex : '男'
 }
 
person.name = 'kk'
 
console.log(person.name)//test

const a = [];
a.push('Hello'); // 可执行
a.length = 0;    // 可执行

a = ['Dave'];    // 报错

const person = {
   name : 'zs',
 
   sex : '男'
}
 
person = {
   name : 'test',
   sex : '男'
}
//报错

声明赋值的是基本数据类型不能修改

声明赋值的是引用数据类型不可修改引用类型的指针(地址),但是具体的值是可以修改的。

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。

对于基本类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

对于引用类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

Object.freeze

如果真的想将对象冻结,应该使用 Object.freeze 方法。

const FOO = Object.freeze({});

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
FOO.prop = 123;

常量FOO指向一个冻结的对象,所以添加新属性不起作用,严格模式时还会报错。

只能冻结第一层, 不能冻结子属性的值。

 // 只能冻结第一层, 不能冻结子属性的值。
        const OBJ = {
            name: 'zs',
            person: {
                name: 'ls'
            }
        };
        Object.freeze(OBJ)
        OBJ.person.name = 'ww'
        console.log(OBJ.person.name)//ww

除了将对象本身冻结,对象的属性也应该冻结。

下面是一个将对象彻底冻结的函数

var constantize = (obj) => {
  Object.freeze(obj);//冻结对象及对象里的非对象属性
  Object.keys(obj).forEach( (key, i) => {
    //冻结对象里的对象属性
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};

Object.keys

数组的形式返回对象所有属性名(key),获得由对象属性名组成的数组;

返回一个 由一个给定对象的自身可枚举属性组成的数组,数组中属性名的

排列顺序和正常循环遍历该对象时返回的顺序一致

let obj={
name:'vue',
age:5,
author:'鱿鱼西'
}
console.log(Object.keys(obj))
//["name","age","author"]

foreach

对数组的每个元素执行一次提供的函数。

主要有三个参数,分别是 数组内容(item)、数组索引(index)、整个数组(array)

let obj={
name:'vue',
age:5,
author:'鱿鱼西'
}
console.log(Object.keys(obj))

Object.keys(obj).forEach(key=>{
console.log(obj[key])
})
//vue
//5
//鱿鱼西

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值