1- 作用域
作用域指变量和函数可以被读写的范围,通常由函数来进行划分, 也叫作函数作用域。
1.1 作用域的分类
全局作用域 :
- script标签下的就是全局
- var声明的变量叫做全局变量
- function声明的函数叫做全局函数
- 全局变量和全局函数可以在整个作用域的任何位置被读取和写入
局部作用域:
- 函数中{}的区域就是局部作用域
- var声明的变量叫做局部变量
- function声明的函数叫做局部函数
- 局部变量和局部函数只能作用于当前的局部作用域中, 但凡出了{}就会被销毁
var a = 20; // 全局变量
function sum(){ // 全局函数
// 局部作用域
console.log(a); // 全局的a
}
sum(); // 全局的sum
function s(){
// 局部作用域
var num = 30;
console.log(num); // 局部变量的num
function m(){
console.log(1);
}
m();
}
s();
// console.log(num); // num is not defined num未定义 报错
// m(); // 报错: m is not defined m未定义
2- 作用域链
作用域链是js中的一种查找方式, 决定了变量和函数向上查找的方式。
先在自身作用域范围中查找变量和函数, 如果找到就直接返回, 如果找不到就往上一级作用域查找, 如果一直找到全局作用域都没有, 就会报错。
var a = 20;
function sum(){
console.log(a); // 20
// console.log(c);
}
sum();
var b = 30;
function s(){
var b = 21;
console.log(b); // 21
}
s();
3- 变量提升(预解析)
js的解析器在执行js代码的时候,会按照一定的顺序来执行
1.找 var function, 将var声明的变量,声明提前, 但是不赋值; 将function声明的函数整个存储在内存中;
2.逐行解析(从上到下)
在第一步中,找var的过程中,只声明,遇到 = += -= *= 赋值运算符的时候才会赋值且function只存函数。
3.1 例子1
console.log(a);
var a = 3;
console.log(typeof a);
function a() {
alert('1');
}
a();
var a = 4;
console.log(a);
a();
function a() {
alert(5);
};
a();
console.log(a);
执行过程:
var a;
var a;
function a() {
alert('1');
}
function a() {
alert(5);
};
console.log(a); // alert(5)的函数a
a = 3;
console.log(a); // number
a();// 报错
a = 4;
console.log(a); //4
a(); // 报错
a(); // 报错
console.log(a); // 4
3.2 例子2
console.log(a);
console.log(d);
var a = 3;
var d = function a() {
alert('1');
};
console.log(a);
console.log(d);
a();
执行过程:
var a;
var d;
console.log(a); // undefined
console.log(d); // undefined
a = 3;
d = function(a){
alert('1');
}
console.log(a); // 3
console.log(d); // function(a){ alert('1'); }
a(); // 报错, a是3, 不能被调用
函数调用时候, 执行函数内部的代码,代码执行的作用域是局部用域, 执行环境改变的时候,会重新执行预解析并且执行代码。
实参的赋值在声明完形参之后 var
3.3 例子3
function fn(a) { // 形参 a === var a
console.log(a);
var a = 3;
console.log(a);
}
fn();
执行过程:
var a; //形参声明的时候, var a就执行了
console.log(a); // undefined
a = 3;
console.log(a); // 3
3.4 例子4
function fn(a) { // 形参 a === var a
console.log(a);
var a = 3;
console.log(a);
}
fn(2);
执行过程:
var a; // 形参声明的时候 var a就执行了
a = 2; // 实参赋值给形参
console.log(a); // 2
a = 3;
console.log(a); // 3
3.5 例子5
var a = 4;
function fn(b) {
console.log(a);
var a = 3;
console.log(a);
};
fn();
console.log(a);
执行过程:
var a;
function fn(b) {
console.log(a);
var a = 3;
console.log(a);
};
a = 4;
fn()
/*
var b;
var a;
console.log(a); undefined
a = 3;
console.log(a); 3
*/
console.log(a); // 全局变量 4
3.6 例子6
var a = 4;
function fn(b) {
console.log(a);
a = 3;
console.log(a);
};
fn();
console.log(a);
执行过程:
var a;
function fn(b) {
console.log(a);
a = 3;
console.log(a);
};
a = 4;
f(n);
/*
console.log(a); 全局变量 4
a = 3;
console.log(a); 全局变量 3
*/
console.log(a); // 全局变量3
3.7 例子7
var a = 4;
function fn(a) {
console.log(a);
a = 5;
};
fn(a);
console.log(a);
执行过程:
var a;
function fn(a) {
console.log(a);
a = 5;
};
a = 4;
fn(a)
/*
var a;
a = 4;
console.log(a); // 4
a = 5;
*/
console.log(a); // 4
3.8 例子8
function fn(a) {
var s = a;
s.name = 'United';
};
var json = {
name: '小u'
};
fn(json);
console.log(json);
解析过程:
var json;
function fn(a) {
var s = a;
s.name = 'United';
};
json = {
'name': '小u'
};
fn(json); // 小u
/*
var a;
var s;
a = {小u};
s = a; {小u}
s.name = 'United'
*/
console.log(json); // United