[TOC]
## 变量提升
在**当前**作用域当中,把所有带var和function关键字的提前声明或则定义
### 声明和定义
> 在`当前作用域`中,js代码自上而下执行之前,浏览器首先会把所有带`var/function`关键字的进行提前的`声明或则定义`
es6中的`let/const`并不会
>声明(declare): var num;在当前作用域中吼一嗓子 我有num这个名了
> 定义(defined):num=12;把声明的名字赋一个值(先有个值,再把这个值和声明的名字建立链接)
### var和function
>[warning]带var关键字的只是提前的声明一下;带function关键字的在变量提升阶段把声明和定义都完成了
```
console.log(num);
console.log(fn);
var numb = 13;
function fn(){
console.log(a);
var a =10;
console.log(a);
}
fn();
console.log(numb)
```
![](https://box.kancloud.cn/136bf7faf8fae03bc3f278ba98323d72_1732x724.png)
> **注意:** 除了全局作用域执行时,函数执行时也会执行自己的变量提升
### 带var和不带var的区别
在项目中,如果目的是创建变量,最好不要省略var
#### 带var是声明变量(顺道在全局下定义一个属性)
在当前作用域中声明一个变量,如果当前是全局作用域,也相当于给全局作用域设置了一个属性叫做a。
```
//=>变量提升:var a; <=> window.a=undefined;
console.log(a); //->undefined
var a = 12; //定义了一个变量a并且将12这个值赋给了它,另外顺道在 window.a=12
console.log(a); //->12
console.log(window.a); //->window['a'] 在”全局作用域“中,我们声明一个变量相当于给全局对象window增加了一个属性名
```
#### 不带var是全局属性
在全局作用域中,如果不带var,仅仅只是给全局对象设置了一个新的属性名(相当于window.a=xx)
```
console.log(a); //=>Uncaught ReferenceError:a is not defined
//先看是不是变量,如果没有,在window下看有没有这个属性,如果都没有,就会报错(浏览器会认为你在忽悠它)
//如果输出的window.a,不会报错,只会输出undefined
a = 12; //<=>window.a = 12
console.log(a); //=>12
console.log(window.a); //=>12
```
### 只对等号左边的进行变量提升
~~~
等号=
左边是变量
右边都应该是值
~~~
匿名函数:函数表达式(把函数当做一个值赋值给变量或则其它内容)
```
oDiv.onclick = function(){
}
//<=>
oDiv.onclick = aaafff000
```
变量提升只会提升等号左边的,右边是值不会提前声明。
```
console.log(fn);//undefined
var fn = function(){
}
console.log(fn);//->函数本体
//谷歌浏览器中用小f 表示一个function
```
```
sum(); //报错 Uncaught TypeError:sum is not a function
var sum = function(){}
```
真实项目中,应用这个原理,我们创建函数的时候可以使用函数表达式的方式。
为了在项目中使代码更加严谨,我们一般都通过函数表达式的方式来定义一个函数(先定义后执行)
因为:
1. 只能对等号左边的进行提升,所以变量提升完成后,当前函数只是声明了,没有定义,想要执行函数只能放在赋值的代码之后(放在前面执行相当于让undefined执行,会报错的)
2. 这样让我们的代码逻辑更加严谨,以后想要知道一个执行的函数做了什么功能,只需要向上查找定义的部分即可(不会存在定义的代码在执行下面的情况)
```
var fn = function sum(){
console.log(sum);//->函数本身
console.log(1);
console.log(arguments.callee);//->函数本身
}
sum(); //Uncaught TypeError:sum is not a function
fn();
```
### 不管条件是否成立,都要进行变量提升
不管条件是否成立,**判断体**当中出现的`var`或则`function`都会进行变量提升,但是在最新版本的浏览器当中,function声明的变量只能提前声明不能定义了。(前提:函数是在判断体中)
老版本将浏览器的function是声明加定义,新版本只会声明(说的是放置在判断体中时的情况)
```
console.log(num); //->undefined
console.log(fn); //->undefined
if(1 !== 1){ //不会走
console.log(num);
console.log(fn);
var num = 12;
function fn(){}
console.log(num);
console.log(fn);
}
console.log(fn); //=>undefined
```
```
console.log(num); //->undefined
console.log(fn); //->undefined
if(1 === 1){
console.log(num); //->undefined
console.log(fn); //->函数体本身
var num = 12;
function fn(){}
console.log(num); //->12
console.log(fn); //=>函数体本身
}
console.log(fn); //=>函数体本身
```
```
console.log(fn); //undefined
for(var i=0;i<9;++i){
function fn(){}
}
```
> 代码执行到条件判断的地方
>[条件不成立]
>进入不到判断体中,此时之前声明的变量或则函数依然是undefined
>
>[条件成立]
>进入条件判断体中的第一件事情不是代码执行,而是把之前变量提升没有定义的函数首先定义了(进入到判断体中函数就定义了,为了迎合ES6中的块级作用域)
```
f = function(){
return true;
}
g = function(){
return false;
}
~function(){
//=>[私有作用域]
//变量提升:g
//虽然g提升了但在新版本中,因为这货在判断体里,只提升不会定义
//故g()报错
if(g()&&[]==![]){
f=function(){
return false;
};
function g(){
return true;
}
}
}();
console.log(f()); //
console.log(g()); //false
```
### 重命处理
```
fn(); //4
function fn(){
console.log(1);
}
fn(); //4
function fn(){
console.log(2);
}
fn(); //4
var fn = 13;
fn(); //报错
function fn(){
console.log(3);
}
fn();
function fn(){
console.log(4);
}
fn();
```
在变量提升阶段,如果名字重复了,不会重新的进行声明,但是会重新进行定义(后面赋的值会把前面赋的值替换掉)
## 作用域链
```
function fn(){
a = 123; // <=>window.a = 123;
console.log(a); //=>123
}
fn();
console.log(a); //=>123
```
>函数执行形成一个私有的作用域(保护私有变量),进入到私有作用域中,首先变量提升(声明过的变量是私有的),接下来代码执行
>1. 执行的时候遇到一个变量,如果这个变量是私有的,变量不受外界干扰
>2. 如果当前这个变量不是私有的,我们需要向它的上级作用域进行查找,上级也没有,则继续向上查找,直到找到window全局作用域为止,我们把这种查找机制叫做**作用域链**
>1)如果上级作用域有,我们当前操作的都是上级作用域中的变量(假如我们在当前作用域把值改了,相当于把上级作用域中的这个值给改了)
>2)如果上级作用域中没有这个变量(找到window也没有)
>变量 = 值:相当于给window设置了一个属性,以后再操作window下就有了
>alert(变量):想要输出这个变量,但此时是没有的,所以会报错
```
console.log(x,y);//undefined undefined
var x = 10,
y = 20;
//var x=10;var y=20;
function fn(){
console.log(x,y); //undefined 20
var x = y = 100;
//var x = 100;y=100;
console.log(x,y);// 100 100
}
fn();
console.log(x,y);//10,100
```
作用域(开辟)->变量提升->逐行运行
- 空白目录
- window
- location
- history
- DOM
- 什么是DOM
- JS盒子模型
- 13个核心属性
- DOM优化
- 回流与重绘
- 未整理
- 文档碎片
- DOM映射机制
- DOM库封装
- 事件
- 功能组件
- table
- 图片延迟加载
- 跑马灯
- 回到顶部
- 选项卡
- 鼠标跟随
- 放大镜
- 搜索
- 多级菜单
- 拖拽
- 瀑布流
- 数据类型的核心操作原理
- 变量提升
- 闭包(scope)
- this
- 练习题
- 各种数据类型下的常用方法
- JSON
- 数组
- object
- oop
- 单例模式
- 高级单例模式
- JS中常用的内置类
- 基于面向对象创建数据值
- 原型和原型链
- 可枚举和不可枚举
- Object.create
- 继承的六种方式
- ES6下一代js标准
- babel
- 箭头函数
- 对象
- es6勉强笔记
- 流程控制
- switch
- Ajax
- eval和()括号表达式
- 异常信息捕获
- 逻辑与和或以及前后自增
- JS中的异步编程思想
- 上云
- 优化技巧
- 跨域与JSONP
- 其它跨域相关问题
- console
- HTML、XHTML、XML
- jQuery
- zepto
- 方法重写和方法重载
- 移动端
- 响应式布局开发基础
- 项目一:创意简历