作用域/变量提升
作用域
作用域指的是变量能够被访问到的范围
JavaScript 中作用域分为局部作用域、全局作用域以及 es6 新增的块级作用域
局部作用域
在 JavaScript 函数中定义的变量叫做局部变量,这个时候只能在函数内部才能访问到它,所以它的作用域也是函数的内部,称为局部作用域
js
function getName() {
var name = "一个奕";
console.log(name); //一个奕
}
console.log(name); //undefined
全局作用域
在 JavaScript 中,在函数外面定义的变量就称作全局变量,全局变量是挂载在 window 对象下的变量,所以在网页中的任何位置都可以访问到这个全局变量。
js
var globalName = "全局的一个奕";
function getName() {
console.log(globalName); //全局的一个奕
var name = "局部的一个奕";
console.log(name); //局部的一个奕
}
getName();
console.log(name); //undefined
console.log(globalName); //全局的一个奕
function setName() {
vName = "没有定义而被直接赋值";
}
setName();
console.log(vName); //没有定义而被直接赋值
console.log(window.vName); //没有定义而被直接赋值
块级作用域
ES6 中新增了块级作用域,使用 let 定义的变量只能在块级作用域中被访问,有暂时性死区的特点,也就是说在变量在定义之前都不能被使用
if 语句以及 for 语句中的{...}
这就是块级作用域。
js
console.log(abc); //abc is not defined
if (true) {
let abc = "嘿嘿~";
console.log(abc); //嘿嘿~
}
console.log(abc); //abc is not defined
变量提升
原理:JS 引擎的工作方式是先解析代码,获取所有被声明的变量,然后再运行。JS 代码自上而下执行之前,浏览器首先会把所有带 “VAR”/“FUNCTION”
关键词的进行提前 “声明” 或者 “定义” ,这种预先处理机制称之为 “变量提升”。
js
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
私有作用域中带 var 和不带 var 的区别:
1、带 var 的在私有作用域变量提升阶段,都声明为私有变量,跟外界没有关系
2、不带 var 不是私有变量,会向它的上级作用域查找,一直找到 window 为止
对等号左边进行变量提升
先把 fn 提升至顶部,运行到那里时才进行赋值
js
sum();
fn(); // Uncaught TypeError: fn is not a function
//=>匿名函数之函数表达式
var fn = function () {
console.log("fn");
}; //=>代码执行到此处会把函数值赋值给fn
//=>普通的函数
function sum() {
console.log("sum");
}
条件判断下的变量提升
js
/*
* 在当前作用域下,不管条件是否成立都要进行变量提升
* =>带VAR的还是只声明
* =>带FUNCTION的在老版本浏览器渲染机制下,声明和定义都处理,但是为了迎合ES6中的块级作用
* 域,新版浏览器对于函数(在条件判断中的函数),
* 不管条件是否成立,都只是先声明,没有定义,类似于var
*/
console.log(a); //undefined
if (1 === 2) {
var a = 3;
}
console.log(a); //undefined
重名问题的处理
js
fn(); //=>4
function fn() {
console.log(1);
}
fn(); //=>4
function fn() {
console.log(2);
}
fn(); //=>4
var fn = 100; //=>带VAR的在提升阶段只把声明处理了,赋值操作没有处理,所以在代码执行的时候需要完成赋值 FN=100
fn(); //=>100() Uncaught TypeError: fn is not a function
function fn() {
console.log(3);
}
fn();
function fn() {
console.log(4);
}
fn();
如果名字重复了,不会重新的声明,但是会重新的定义(重新赋值)