js变量提升

js变量提升

js变量提升_第1张图片

堆栈内存 以及 基本&引用数据类型

基本数据类型&引用数据类型

浏览器加载我们js时候,首先会形成一个全局作用域window提供一个代码自上而下执行的环境;

  1. 引用类型会在作用域外 新开辟一块内存空间(有一个16进制地址),键值对依次存储到这个内存中;基本数据类型是直接在作用域开了一个位置就存了。

js变量提升_第2张图片
js变量提升_第3张图片
  1. 想让代码执行就得有一个执行的环境,所以函数执行首先都会形成一个私有的作用域。

js变量提升_第4张图片

作用域:

  1. 提供代码自上而下执行的环境

  2. 存储基本数据类型,所有基本数据类型都是直接在该作用域开辟一个位置

栈内存:即作用域

堆内存:存储引用数据类型

释放内存,让其不被占用,arr=null,

js变量提升_第5张图片

变量提升机制

在代码自上而下执行之前,浏览器会把带var或者function关键字的进行“声明”或“定义”,这就叫变量提升

变量提升只发生在当前作用域

私有作用域的变量提升和全局基本一致。私有作用域下的这些变量也就是私有变量,那我们就把保护私有作用域下的私有变量叫做闭包。

js变量提升_第6张图片

带var和不带var

全局的var变量和window属性存在映射关系

不加var:添加了window的一个属性

js变量提升_第7张图片

私有作用域

带var:私有变量,跟外界没有关系

不带var:就会向上级作用域查找,“作用域链”机制

js变量提升_第8张图片

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

function fn(){
    console.log(a,b); // undefined 12
    
    var a=b=13;
    console.log(a,b) // 13 13

}
fn();
console.log(a,b); // 12 13

function fn(){
    b=13;
    console.log(b) // 13

}
fn();
console.log(b) // 13
console.log(window.b) // 13

提升的一些细节问题

函数表达式和普通函数的区别

普通函数:用function关键词来处理的

函数表达式:只对函数左边进行变量提升

console.log(fn);
fn() // Uncaught TypeError: fn is not a function
sum()

var fn=function(){
    console.log(1)
}
function sum(){
    console.log(2)
}

条件判断下的变量提升

当前作用域下,不管条件是否成立,都要进行变量提升

console.log(a) // undefined
if(1===2){
    var a = 2;
}
console.log(a); // undefined
// 另一种情况
console.log(a)
if('a' in window){
    var a = 100;
}
console.log(a);

function的一道题

  • 全局下没有变量提升(自执行没有名字所以也没有变量提升)。

window.f = ...

window.g = ...

  • 自执行函数部分:

创建一个函数并且把它执行了。只要是函数执行,肯定会形成一个私有作用域。

变量提升:带function的也只剩声明了g,但没有定义。私有作用域中声明一个变量是私有的,跟全局作用域是没有关系的。

  • [] -> []==false -> 0==0

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

js变量提升_第9张图片

这里还有块级作用域

console.log(fn);
// if(1===2) 那么结果又不一样 undefined
if(1===1){
    console.log(fn);
    function fn(){
        console.log('ok');
    }
}
console.log(fn);

但是这里又不是完整的块级作用域,因为这个fn还是全局的。

js变量提升_第10张图片

重名问题的处理

重名时会重新赋值不会重新声明

js变量提升_第11张图片

fn(); // 4
function fn(){ console.log(1) };
fn(); // 4
function fn(){ console.log(2) };
fn(); // 4
var fn = 100;
fn(); // Uncaught TypeError: fn is not a function
function fn(){ console.log(3) };
fn(); // Uncaught TypeError: fn is not a function
function fn(){ console.log(4) };
fn();

题外话

js变量提升_第12张图片

let不存在变量提升

let/const不存在变量提升。

let a=6;
console.log(a); // 6
console.log(window.a); // undefined 不存在映射机制的

语法检测:

es6机制下,代码执行之前首先会做语法检测。

  1. 重复定义的会报错

  2. 并且它说,这些定义的变量在正式定义之前是不能使用的。

// 这个例子很好
// 全局 a,b,fn
// fn执行形成一个私有作用域:let a,所以用a只能用在创建a的后面;b不是let,这里没有出现b,往上级去找
let a=10,b=10;
let fn=function(){
    // console.log(a,b);
    let a = b=20;
    console.log(a,b);
}
fn();
console.log(a,b);

js变量提升_第13张图片

a=3;
let a=8;
console.log(a);

js变量提升_第14张图片

暂时性死区

总结:

首先先形成一个栈内存全局作用域,或私有作用域私有栈内存,在私有作用域下也会先验证它是不是私有变量,如果是的话就是自己的,如果不是则向上级作用域查找。

代码执行之前会做很多事情:

老规范会对变量进行提前声明或者定义,则按照变量提升机制走,新规范重复检测机制。

let 会形成一个块级私有作用域,同上面函数作用域一样,在定义之前不能使用。

// 题目
var a=12;
if(true){
    console.log(a); // 同理,这里使用也报错
    let a=13;
    console.log(a);
}
console.log(a);

js变量提升_第15张图片

// 这是typeof的一个bug
console.log(typeof a); // undefined

js变量提升_第16张图片

javascript 暂时性死区_Novice-XiaoSong的博客-CSDN博客_js暂时性死区

你可能感兴趣的:(javascript,前端,开发语言)