let const关键字定义变量、块作用域

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013862108/article/details/83216781

let 声明的变量只能在它所在的代码中有效

{
    let a=10;
    var b=1;
}
console.log(a);
console.log(b);

for循环 中let变量

var a=[];
for(let i=0; i< 10; i++){
    //每一次循环的变量i其实都是一个新的变量
    //for循环的一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
    a[i] = function () {
        console.log(i);
    };
}

a[6]();

a[5]();
// console.dir(a[5]);
// console.dir(a[6]);

函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域

for(let i=0; i< 3;i++){
    let i = 'abc';
    console.log(i);
}
//上面的例子证明了: 函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
//let 声明的变量不存在"变量提升"!
console.log(foo);
var foo = 2;

//let的情况
//console.log(bar);  //报错 bar is not defined
let bar = 2;

暂时性死区TDZ  temporal dead zone 

好习惯:在使用变量之前一定要先声明!


//暂时性死区TDZ  temporal dead zone  TDZ
var tmp = 123;
if(true){
    //TDZ开始
    //tmp = 'abc';  //ReferenceError 报错
    //TDZ结束
    let tmp;
}
//ES6规定,如果区块中存在let 和const命令,这个区块对这些命令声明的变量,一开始就形成了封闭作用域,凡是在声明之前就使用这些变量,就会报错。

//"暂时性死区"也意味着typeof不再是一个百分之百安全的操作
typeof x;
let x;
//在没有let 之前,typeof运算符是百分之百安全的,现在不成立了。
//所以呢, 好的习惯是:在使用变量前一定要先声明!!!

function bar(x=2, y=x) {
//function bar(x=y, y=2) {   //报错了y未定义
    return [x,y];
}

bar();

//ES6 规定暂时性死区; let, const语句不出现变量提升

不允许重复声明


//不允许重复声明; 不允许重复声明
function func() {
    let a = 10;
    var a = 1;
}

func();

function func() {
    let a = 10;
    let a = 1;
}

func();  //调用就报错

//不能在函数内部重新声明参数
function func(arg) {
    let arg;   //报错
}

function func(arg) {
    {
        let arg;   //不报错
    }
}

块级作用域

ES5 只有全局作用域和函数作用域,没有块级作用域,会出现场景

一: 内层变量可能覆盖外层变量

//一: 内层变量可能覆盖外层变量
var tmp = new Date();

function f(){
    console.log(tmp);
    //if(false){
    if(true){
        console.log('b:',b);
        //var tmp = 'hello world';
        let tmp = 'hello world';
        var b=3;
    }
    console.log(tmp);
    console.log('b:',b);
}

f();
//用来计数的循环变量泄露为全局变量。
var s = 'hello';
for(var i =0; i< s.length; i++){
    console.log(s[i]);
}
console.log(i);

ES6块级作用域

function f1() {
    //let n = 5;
    var n = 5;
    if(true){
        let n = 10;
        //var n = 10;
    }
    console.log(n);  //5
}
f1();
ES6允许作用域任意嵌套
外层作用域无法读取内层作用域的变量
内层作用域可以定义外层作用域的同名变量
{{{{
    let insane = 'Hello world';
    {let insane = 'Hello'}
}}}}
块级作用域的出现,使得广泛应用的立即执行函数表达式不再必要
(function () {
    var tmp = "...";
})();
    //块级作用域写法
{
    let tmp = "..."
}
ES6中规定块级作用域中,可以声明函数,函数的行为类似于let ,在块级作用域外不可引用

实际上ES6浏览器中://node 中也是这样
--允许在块级作用域内声明函数
---函数声明类似于var ,即会提升到全局作用域或函数作用域的头部
---同时,函数声明还会提升到所在的块级作用域的头部
//所以以下会报错
function f() {
    console.log('I am outside!');
}

(function () {
    console.log(f);
    console.log(typeof f);
    console.dir(f);
    //if(false){
    if(true){
        //重复声明一次函数f
        // function f() {  //注释掉看看
        //     console.log('I am inside!')
        // }
    }
    f();
}());

 考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数,如果确实需要,应该写成函数表达式。!

//小细节,如果想在块级作用下声明函数,必须有大括号;不重要的知识点

const  

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

const 一旦声明,就必须马上初始化

const foo=123;

if(true){
    const MAX = 5;
}

//console.log(MAX)  // 报错 MAX is  not defined

注意, const声明的常量也是不提升,同样存在暂时性死驱,只能在声明的位置后面使用。
const 声明的常量,也与let 一样不可重复声明
var message = "Hello!";
let age = 25;

//以下两行都会报错
//const message = "Goodbye!";
//const age = 30;
const 本质
只能保证 指向的地址是固定的, ;简单的类型数据(数值,字符串,布尔值)就保存在变量指向的那个内存地址,因此等于常量;
const foo = {};
foo.prop = 123;
foo.prop

//将foo指向另一个对象就会报错
//foo = {}

const a = [];
a.push('hello');  //可执行
a.length = 0;     //可执行
//a = ['Dave'];     //报错

确实想把对象冻结,怎么做?

const foo = Object.freeze({name: 'zhaosi', age : 29, order :{}});

foo.prop = 123;  //不起作用; 严格模式下,该行会报错。

console.log(foo);

foo.age = 40;   //不可修改; 不起作用,也不报错
console.log(foo);

foo.order.num = 3;  //还是能修改的,还是不彻底的呀!

console.log(foo);  //{ name: 'zhaosi', age: 29, order: { num: 3 } }

彻底冻结该怎么做?

//写一个冻结函数
var constantize = (obj) =>{
    Object.freeze(obj);
    Object.keys(obj).forEach((key, i) => {
        if(typeof obj[key] === 'object'){
            console.log('free');
            constantize(obj[key]);
        }
    })
}

var dongjie = {name : 'liang', age : 28, info :{num : 3}}

dongjie.info.num =5;
constantize(dongjie);
//Object.freeze(dongjie);
dongjie.info.num = 8;   //怎么没冻住 info呢?
dongjie.age = 22;
console.log(dongjie);
ES6声明变量的六种方式
//var  function   let  const   import class

顶层对象的属性

在浏览器环境中指的是 window 对象; Node 指的是 global 对象;
ES5 中 顶层对象 ====  全局变量

ES6中 var function 声明的的全局变量, 依旧是顶层对象的属性; let , const , class 声明的全部变量不属于顶层对象的属性。
//
var a = 1;
//console.log(global.a);  //undefined   node 中
console.log(window.a);    //1   浏览器

let b = 1;
//console.log(global.b);  //undefined   node中
console.log(window.b);   //undefined  浏览器
// //global 对象
var getGlobal = function () {
    if(typeof self !== 'undefined'){
        return self;
    }
    if(typeof window !== 'undefined'){
        return window;
    }
    if(typeof global !== 'undefined'){
        return global;
    }
}

console.log(getGlobal());

参考: http://es6.ruanyifeng.com/#docs/let

猜你喜欢

转载自blog.csdn.net/u013862108/article/details/83216781