变量和函数提升
js引擎会在正式执行代码之前进行一次“预编译”,预编译简单理解就是在内存中开辟一些空间,存放一些变量和函数。 函数的优先级最高
提升过程分析
var a = 1;
function foo() { a = 10; console.log(a); return; function a() {}; }
foo();
console.log(a);
// ------------------------------
var a = 1; // 定义一个全局变量 a
function foo() {
// 首先提升函数声明function a () {}到函数作用域顶端
// 然后function a () {}等同于 var a = function() {};最终形式如下
var a = function () {}; // 定义局部变量 a 并赋值。
a = 10; // 修改局部变量 a 的值,并不会影响全局变量 a
console.log(a); // 打印局部变量 a 的值:10
return;
}
foo();
console.log(a); // 打印全局变量 a 的值:1
- 当存在同名的函数和变量时,函数优先。
var foo = 666;function foo(){ console.log(1) };console.log(foo) // 666
// 函数提升 等价于以下
var foo = function(){};foo = 666;console.log(foo) // 666
// 由于foo在预编译时已经定义为函数,因此再遇到变量时不会再提升并负值为undefined。如下错误代码
var foo = function(){};var foo = undefined;foo = 666;console.log(foo)
- 存在同名的函数时,后面的会覆盖前面的
console.log(test); // 我是函数表达式
function test() { console.log('我是函数'); }
console.log(test); // 我是函数表达式
function test() { console.log('我是函数表达式'); }
console.log(test); // 我是函数表达式
test();
全局和局部变量
- 局部变量:在JavaScript函数内部声明的变量(使用 var)。只能在函数内部访问它。
函数运行完毕,本地变量就会被删除 - 全局变量:在函数外声明的变量或未使用var定义的变量。网页上的所有脚本和函数都能访问它。全局变量会在
页面关闭后被删除
注:值得注意的是:函数外块语句(大括号'{}”中间的语句),如 if 和 switch 条件语句或 for 和 while 循环语句内定义的变量还是全局变量
var c = 666;
function test(){
a = 30;
var b = 20;
var c = 10;
console.log("c=" + c);
}
test() // c=10 函数内改变的只是该函数内定义的局部变量,不影响函数外的同名全局变量的值
console.log("c="+c); // c=666
console.log("a="+a); // a=30 这里的a为全局变量,输出a=30
console.log("b="+b); // undefined
----------------------------------------------------------------
if (true) {
// 'if' 条件语句块不会创建一个新的作用域
var name = 'Hammad'; // name 依然在全局作用域中
}
console.log(name); // logs 'Hammad'
var和let、const区别
- var定义的全局变量会挂载在window下,let const声明的变量则不会
- const 声明之后必须马上赋值,否则会报错
- const 简单类型一旦声明就不能再更改,复杂类型(数组、对象等)指针指向的地址不能更改,内部数据可以更改。
- let、const不存在变量提升、不允许在相同作用域内,重复声明同一个变量
全局、函数、块级作用域
- ES5 只有全局作用域和函数作用域
- ES6 有块级作用域、全局作用域、函数作用域
块级作用域在如下情况被创建。1、在一个函数内部 2、在一个代码块(由一对花括号包裹)内部
块级作用域可通过新增命令let和const声明,所声明的变量在指定块的作用域外无法被访问
function getValue(condition) {
if (condition) {
let value = "blue";
return value;
} else {
// value 在此处不可用
return null;
}
// value 在此处不可用
}
------------------------------------------------------
for (let i = 0; i < 10; i++) {}
console.log(i);
// ReferenceError: i is not defined
// 计数器i只在for循环体内有效,在循环体外引用就会报错。
自由变量的取值
要到创建这个函数的那个域中取值,这里强调的是“创建”
var x = 10
function fn() {
console.log(x)
}
function show(f) {
var x = 20
(function() {
f() // 10,而不是20
})()
}
show(fn)
----------------------------------------------------------
// fn()返回的是bar函数,赋值给x。执行x(),即执行bar函数代码。
// 取b的值时,直接在fn作用域取出。
// 取a的值时,试图在fn作用域取,但是取不到,只能转向创建fn的那个作用域中去查找
// 结果找到了,所以最后的结果是30
var a = 10
function fn() {
var b = 20
function bar() {
console.log(a + b) //30
}
return bar
}
var x = fn(), b = 200
x() // bar()
