1.var关键字
1.声明赋值
声明变量的方式 | 作用 | 区别 |
---|---|---|
let | 用于声明变量 | 暂时性死区(块级作用域) |
var | 用于声明变量 | 存在变量提升 |
const | 用于声明只读的常量 | const 声明后不得修改 |
2.JavaScript奇怪现象:
- 1.函数体内变量在定义之前可被访问到,不报错。
function fn(){
console.log(a);
var a = 1;
}
fn();//undefined
- 2.函数在定义之前被调用,不报错
xxxxxxxxxx
fn();
function fn(){
console.log('我是隔壁老梁');
}
3.为何会这样?
因为JavaScript中存在一种特殊的
变量提升
和函数提升
机制
首先,先了解一下作用域
4.作用域
作用域:一个变量的定义与调用在固定的范围中。
分为:
- 全局作用域
- 函数(局部)作用域
- 块级作用域
全局作用域
var 在全局作用域下声明变量,在任何位置都能访问到
xxxxxxxxxx
var name = '隔壁老王'
// 在全局作用域中访问
console.log(name)
// 在局部作用域中访问
if (5 === 5) {
console.log(name)
}
// 隔壁老王
// 隔壁老王
局部作用域
var 在局部作用域下声明变量,在任何位置也能访问到
xxxxxxxxxx
if (5 === 5) {
var name = '隔壁老王'
console.log(name)
}
console.log(name)
// 隔壁老王
// 隔壁老王
- 全局作用域:任何位置都可以访问
- 函数(局部)作用域:只能函数内部访问
- 块级作用域:只能在代码块中访问(
ES6
新增let
、const
)
xvar a = '我是全局'
function foo () {
var b = '我是局部'
console.log(a)
console.log(b)
}
foo()
// 打印结果:我是全局
// 我是局部
{
let c = '我是块级'
console.log(c) // 我是块级
}
console.log(c) // 报错,c is not defined
5.预解析
1.基本概念
- 使用
var
定义的变量时,函数中会存在变量提升的问题
1.代码1
xxxxxxxxxx
var xxoo1 = '我是隔壁老王';
(function () {
console.log(xxoo1)
})()
// 我是隔壁老王
代码解析
//全局对象window上定义一个变量
var xxoo1;
// 赋值为隔壁老王
var xxoo1 = '我是隔壁老王';
// 定义一个立即执行函数
(function () {
// 在函数内部引用变量xxoo1
console.log(xxoo1)
})()
// // 我是隔壁老王
2.代码2
xxxxxxxxxx
var xxoo2 = "我是隔壁老王";
(function(){
console.log(xxoo2);
var xxoo2 = "我是你大爷"
})();
// undefined
- 代码2中涉及了变量提升
var 定义的变量,在输出时,会优先在函数内部作用域中寻找变量。如果内部没有,则去父级作用下找对应的变量。
- 执行过程
xxxxxxxxxx
代码2解析
// 在window上定义一个变量xxoo2
var xxoo2;
// 赋值为隔壁老王
var xxoo2 = "我是隔壁老王";
(function(){
// 内部同样定义了一个变量xxoo2
var xxoo2;
console.log(xxoo2);//undefined
// 赋值语句并未提升
var xxoo2 = "我是你大爷"
})();
2.变量预解析
如果给 var 声明的变量赋值,声明会被提升到当前作用域的最前面
xxxxxxxxxx
// 原代码
console.log(a) // undefined
var a = 'xxoo'
// 预解析后的代码(只有声明被提前赋值依旧没有被提前)
var a
console.log(a)
a = 'xxoo'
3.函数预解析
如果定义一个函数,函数也会被提升到当前作用域的最前面
xxxxxxxxxx
// 原代码
xxoo()
function xxoo () {
console.log('hello')
}
// 预解析后的代码
function xxoo () {
console.log('hello')
}
xxoo()
4.注意点
如果将函数赋值给一个var定义的变量, 那么函数不会被预解析, 只有变量会被预解析
xxxxxxxxxx
// 源代码
xxoo()
var xxoo = function () {
console.log('hello')
}
// 预解析后的代码
var xxoo
xxoo() // xxoo is not a function
xxoo = function () {
console.log('hello')
}
5.变量提升
变量提升是将变量的声明提升到函数顶部的位置,而变量的赋值并不会被提升(仅限用于var关键字)
- 变量未定义var关键字
xxxxxxxxxx
(function () {
console.log(xxoo)
xxoo = '我是隔壁老王'
})()
// 输出结果:xxoo is not defined
未使用var关键字的变量是全局变量,不会产生变量提升,直接进行输出,会抛出变量xxoo未定义异常
6.函数提升
使用函数声明方式定义的函数也会出现提升
xxxxxxxxxx
xxoo();// 我是xxoo
function xxoo(){
console.log('我是xxoo');
}
- xxoo()函数的声明在调用之后,能调用成功,因为xxoo()函数被提升至作用域顶部,相当于下面的代码
xxxxxxxxxx
function xxoo(){
console.log('我是xxoo');
}
xxoo();// 我是xxoo
函数提升会将整个函数体一起进行提升,包括里面的执行逻辑。
- 函数表达式不会函数提升
xxxxxxxxxx
xxoo();// 报错,xxoo is not a function
var xxoo = function(){
console.log('我是xxoo');
}
7.变量提升与函数提升的应用
加深理解
- 1.关于函数提升
xxxxxxxxxx
function xxoo1(){
function xxoo2(){
return 3;
}
return xxoo2();
function xxoo2(){
return 8;
}
}
console.log(xxoo1());// 8
// 代码解析
function xxoo1(){
// 由于变量提升的存在,两段代码都会被提升至foo()函数的顶部
function xxoo2(){
return 3;
}
function xxoo2(){
return 8;
}
// 后一个函数会覆盖前一个bar()函数
return xxoo2();
}
// 最后输出值为“8”
console.log(xxoo1());// 8
- 2.变量提升和函数提升同时使用
xxxxxxxxxx
var a = true;
xxoo();
function xxoo(){
if(a){
var a = 10;
}
console.log(a);// undefined
}
// 代码解析:
//全局作用域中定义一个变量a
var a;
// 值为true
var a = true;
// 定义xxoo()函数
function xxoo(){
// a会提升至xxoo()函数的顶部,此时a的值为undefined
var a;
// 过if语句进行判断时,返回“false”,并未执行a = 10的
if(a){
var a = 10;
}
// 最后输出“undefined”
console.log(a);
}
// 调用xxoo()函数
xxoo();
- 3.变量提升和函数提升优先级
xxxxxxxxxx
function xxoo () {
console.log(typeof a)
var a = '隔壁老王'
function a () {
return '我是正经人'
}
console.log(typeof a)
}
xxoo()
// function
// string
// 代码解析
function xxoo () {
// 变量提升至函数顶部
var a;s
// 函数提升优先级低,出现在变量声明后面,则a是一个函数
function a () {
return '我是正经人'
}
console.log(typeof a);// function
// 变量赋值
var a = '隔壁老王';
console.log(typeof a);// string
}
xxoo()
- 4.变量提升和函数提升整体应用
xxxxxxxxxx
function xxoo(){
var a = 1;
function b(){
a = 10;
return;
function a(){}
}
b();
console.log(a);//1
}
xxoo();
// 代码解析
// 代码执行过程
function xxoo(){
// 变量a的提升
var a;
// 函数声明b的提升
function b(){
// 内部的函数声明a的提升
function a(){}
// 变量a是一个全局环境的变量。会进行提升
a = 10;
return;
}
var a = 1;
b();
console.log(a);//1
}
xxoo();
注意:
无论变量还是函数,都做到先声明后使用
- ES5语法
xxxxxxxxxx
// 定义变量
var name = '隔壁老王'
// 先定义函数
var xxooAbc = function (a) {
console.log(name, ',我是', a)
}
// 预先定义将要使用到的变量
var i
var a
var b = ['波多野结衣', '大桥未久', '上原亚衣']
// 遍历数组
for (i = 0; i < b.length; i++) {
// 使用变量
a = b[i]
// 使用预先定义的xxooAbc函数
xxooAbc(a)
}
- ES6语法
xxxxxxxxxx
// 定义变量
const name = '隔壁老王'
// 先定义函数
let xxooAbc = function (a) {
console.log(name, ',我是', a)
}
// 预先定义将要使用到的变量
let b = ['波多野结衣', '大桥未久', '上原亚衣']
// 遍历数组
for (let i = 0; i < b.length; i++) {
// 使用变量
let a = b[i]
// 使用预先定义的xxooAbc函数
xxooAbc(a)
}
2.var面试题
x
// 案例1
{
var num = 5;
}
console.log(num);// 5
//案例2
var num = 5;
if (num > 3) {
var sum = 7;
}
console.log(sum);// 7
//案例3
for (var i = 0; i < 10; i++) {
}
console.log(i);// 10
//案例4 全局变量
var name = "zs";
function f() {
name = "ww";
}
f();
console.log(name);// ww
//案例5
function f() {
var name1 = "zs";
}
f();
console.log(name1);// 报错name1 is not defined
//案例6 作用域链
var color = "red";
function getColor() {
var anotherColor = "blue";
function swapColor() {
var tmpColor = color;
color = anotherColor;
anotherColor = tmpColor;
}
swapColor();
}
getColor();
console.log(color); // blue
Comments | NOTHING