ActiveMQ Nmap 网站favicon图标制作 网络服务器 Java开发手册 acm xpath text axios angular ui router vue开发文档 android开发项目 jquery选择子元素 数据库教程 python操作mongodb python下载安装教程 java重载和重写的区别 java学习平台 java获取当前ip java判断文件是否存在 java字符比较 java网络编程 谷歌地球打不开 python封装 pr黑场过渡 3d软件下载 winhex教程 PCCAD 华为下拉开关设置 音乐狂app movavi 设备管理器在哪 autocad2004迷你版 c语言图书管理系统 qq流览器下载 qq浏览器手机 刻刀工具 excel乘积 软件工程pdf php单例模式
当前位置: 首页 > 学习教程  > 编程语言

1.变量提升&LET和VAR

2020/8/11 20:48:40 文章标签:

本文知识点:

  1. 变量提升机制:什么是变量提升、带var和不带的区别、 等号左边变量提升、条件判断下的变量提升、重名问题的处理
  2. LET和VAR的区别:重复定义、变量提升、块级作用域
  3. 作用域处理机制:全局和私有变量、作用域链、闭包的“保存8保护”、JQ源码分析、选项卡剖析、面试题练习
1. 变量提升(声)

当浏览器开辟出供代码执行的栈内存后,代码并没有自.上而下立即执行,而是继续做了一-些事情:把当前作用域中所有带var/function关键字的进行提前的声明和定义=>变量提升机制

  • 带var的只是提前声明( declare ) “var a;” 如果只声明没有赋值,默认值是undefined
  • 带function的不仅声明,而且还定义了( defined ) "a=13”定义其实就是赋值,准确来说就是让变量和某个值进行关联

例题:写出下列代码输出的结果

console.log(a);
var a = 12;
var b = a;
b = 13;
console.log(a);

console.log(sum(10, 20));
function sum(n, m) {
    return n + m;
}

上述代码的图解:
在这里插入图片描述
函数表达式方式,由于使用VAR来创建SUM, 变量提升阶段只会声明变量,不会赋值,所以此时函数在前面执行,函数是没有值的,不能执行(真实项目中这种方式最常用,因为它操作严谨)

console.log(sum);//=>undefined
//sum(10,20);// Uncaught TypeError: sum is not a function
var sum = function (n, m) {
    return n + m;
}
console.log(sum(10,20));//=>30

用ES6的箭头函数使代码更加的严谨,函数只能在声明之后使用。

//console.log(sum); //=> Uncaught ReferenceError: Cannot access 'sum' before initialization
let sum = (n, m) => n + m;
console.log(sum(10, 20));//=>30

练习题:

此练习题复习‘变量提升’的知识点引出‘带var和不带var’与 ‘let/const和var的区别’的知识点

1.写出下面代码输出的结果

console.log(a); 
var a =12;
a = 13;
console.log(a);
//----------------
console.log(a); 
let a = 12;
a = 13;
console.log(a);
//----------------
console.log(a);
a=13;
console.log(a);

解析如下:
/*全局作用域(栈内存)
1.变量提升
var a;
2.代码执行*/
console.log(a); //=>undefined
var a =12;
a = 13;
console.log(a);//=>13

//----------------
/*
*/
//不会有输出
//console.log(a); //=>引用错误  Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 12;
a = 13;
console.log(a);
2.1 let/const和var的区别(1)
  1. let和const不存在变量提升机制
    创建变量的六种方式中: var/function有变量提升,而let/const/class/import都不存在这个机制

没有变量提升更好,更严谨。

3. 带var和不带var的区别

在全局作用域下的区别

//----------------
/*全局作用域(栈内存)
1.变量提升(let没有变量提升)
2.代码执行*/
//不会有输出
console.log(a);//=>引用错误 Uncaught ReferenceError: a is not defined
a=13;//window.a=13, a不是变量而是window的一个属性名
console.log(a);
//alert() 的全称是 window.alert(),与此处的a一样,是window.a
  1. 不带var的:相当于给全局对象window设置了一个属性a,window.a = 13;
a=13;
console.1og(a); //=>window.a
  1. 带var的:栈内存变量存储空间存储了一个变量名b
    带var的:是在全局作用域下声明了一个变量b (全局变量),但是在全局下声明的变量也同样相当于给window增加了一个对应的属性(只有全局作用域具备这个特点)
var b = 14; //=>创建变量b & 给window设置了属性b
console.log(b); //=>14
console.log(window.b); //=>14
2.2 let/const和var的区别(2)
  1. let和const不存在变量提升机制
    创建变量的六种方式中: var/function有变量提升,而let/const/class/import都不存在这个机制
  2. var允许重复声明,而let是不允许的
    在相同的作用域中(或执行上下文中)
  • 如果使用var/function关键词声明变量并且重复声明,是不会有影响的(声明第一次之后,之后再遇到就不再重复声明了)
  • 但是使用let/const就不行,浏览器会校验当前作用域中是否已经存在这个变量了,如果已经存在了,则再次基于let等重新声明就会报错

不同的作用域中可以重复声明

所谓重复是:不管之前通过什么办法,只要当前栈内存中存在了这个变量,我们使用1et/const等重复再声明这个变量就是语法错误

var a = 12;
var a = 13;
console.log(a);

let b = 12;
let b = 13;//语法错误 Uncaught SyntaxError: Identifier 'b' has already been declared
console.log(b);

var c = 12;
let c = 12;//Uncaught SyntaxError: Identifier 'c' has already been declared
console.log(c);

let d = 12;
var d = 13;//Uncaught SyntaxError: Identifier 'c' has already been declared
console.log(d);

let f = 12;
function f() { }//Uncaught SyntaxError: Identifier 'c' has already been declared
console.log(f);
4. 词法解析 [不重要,了解即可]

练习题:问输出几次,结果是多少

console.log(1);
let a = 12;
console.log(a);
let a = 13;
console.log(a);

结果:一次都没输出直接报语法错误【Uncaught SyntaxError: Identifier ‘a’ has already been declared】

分析:全局作用域(栈内存)
1.变量提升
2.代码执行
在浏览器开辟栈内存供代码自上而下执行之前,不仅有变量提升的操作,还有很多其它的操作=>“词法解析”或者“词法检测”:就是检测当前即将要执行的代码是否会出现语法错误[SyntaxError],如果出现语法错误,代码将不会再执行(第一行 都不会执行)

console.log(1);//=>这行代码就 已经不会再被执行了|
let a = 12;
console.log(a);
let a = 13;//=>Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(a);

练习题:问输出几次,结果是多少

console.log(1);//=>1
console.log(a);//=>引用错误 Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 12;

let不存在变量提升这不是错误,let不允许重复声明,那么重复声明了就是语法错误

练习题:输出结果?


fn();
function fn() { console.log(1); }
fn();
function fn() { console.log(2); }
fn();
var fn = function () { console.log(3); }
fn();
function fn() { console.log(4); }
fn();
function fn() { console.log(5); } 
fn();

此题的图片解析
在这里插入图片描述
输出结果:5、5、5、3、3、3

5. 变量提升中关于条件判断的处理
  1. 练习题:下面代码的输出结果
console.log(a);
if(!('a' in window)){
    var a=13;
}
console.log(a);

全局作用域
1.变量提升
不管条件是否成立都要进行变量提升
var a; //=>创建一个全局变量a =>window.a [‘a’ in window]=>true
2.代码执行

console.log(a);//=>undefined
if(!('a' in window)){ //false
    var a=13;
}
console.log(a);//=>undefined
  1. 练习题:下面代码的输出结果
fn();
if(!('a' in window)){
    function fn(){
        console.log('哈哈哈');
    }
}
fn();

全局作用域
1.变量提升
但是做函数的有特殊性:在老版本浏览器中,确实不论条件是否成立,函数也是提前声明或者定义的,但是新版本浏览器中,为了兼容ES6严谨的语法规范,条件中的函数在变量提升阶段只能提前声明,不能提前定义
[function fn]
2.代码执行

fn();//=> Uncaught TypeError: fn is not a function
if('fn' in window){
//条件成立, 进来后的第一件事是给FN赋值,然后再代码执行
    function fn(){
        console.log('哈哈哈');
    }
}
fn();

//--------------
console.log(fn);//undefined
if('fn' in window){
    fn();//哈哈哈
    function fn(){
        console.log('哈哈哈');
    }
}
fn();//哈哈哈

tip:自执行函数:前面加的()或者!、-、~、+只有一个目的,让语法符合而已.
自执行函数本身不进行变量提升(没名字)
(function(){})();
~function(){}();
-function(){}();
+function(){}();
!function(){}();

练习题:下列代码的输出结果

f = function () { return true; }
g = function () { return false; }
~function () {
    if (g() && [] == ![]) {
        f = function () { return false; }
        function g() { return true; }
    }
}();
console.log(f());
console.log(g());

解析:全局作用域
1.变量提升:–
2.代码执行:

f = function () { return true; }
g = function () { return false; }
~function () {
/*
函数执行会形成一个私有的作用域:
1.变量提升 function g;
2.代码执行
*/
    if (g() && [] == ![]) {//Uncaught TypeError: g is not a function
        f = function () { return false; }
        function g() { return true; }
    }
}();
console.log(f());
console.log(g());

此题结果:直接报错不会有输出。
自己补充的

[] == ![];//=>true
Boolean([]);//=>true
Boolean(![]);//=>false
2.3 let/const和var的区别(3)
  1. let和const不存在变量提升机制
    创建变量的六种方式中: var/function有变量提升,而let/const/class/import都不存在这个机制
  2. var允许重复声明,而let是不允许的
    在相同的作用域中(或执行上下文中)
  • 如果使用var/function关键词声明变量并且重复声明,是不会有影响的(声明第一次之后,之后再遇到就不再重复声明了)
  • 但是使用let/const就不行,浏览器会校验当前作用域中是否已经存在这个变量了,如果已经存在了,则再次基于let等重新声明就会报错
  1. LET解决typeof检测时出现的暂时性死区问题[LET比VAR更严谨]
    ES6中LET和VAR的区别之一:暂时性死区【这个很重要】
    练习题:写出下面代码输出的结果
console.log(a);//1.js:1 Uncaught ReferenceError: a is not defined

浏览器对于typeof有一个bug:暂时性死区

//这是浏览器的BUG,本应该是报错的,因为没有a (暂时性死区)
console.log(typeof a);//"undefined"  不报错

LET解决浏览器的暂时性死区

console.log(typeof a);
// Uncaught ReferenceError: Cannot access 'a' before initialization
let a

本文链接: http://www.dtmao.cc/news_show_100426.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?