什么是作用域,通俗讲,作用域内部的变量无法被外部获取。用来产生一个封闭的空间,防止外部的变量污染内部的变量。作用域中的变量名允许和外部或者其他作用域中的变量重名,不会受到任何影响。
比如,一个班级有两个叫张三的,是会影响到提问问题的。但是两个张三如果分散在不同的组里,就不会影响了。
全局作用域
在script中有一个作用域叫全局作用域。
<script> // 这里就是全局作用域 </script>
全局作用域中声明的变量函数等有一个特定,所有的其他作用域都能访问。
let a = 1 function fn() { console.log(a) // 1 函数中可以获取到全局中的变量 } fn()
函数作用域
每个函数内部都有独立的作用域,函数中的变量只能被函数内部的作用域获取
let a = 2 function fn () { let a = 1 console.log(a) // 1 }
在函数内部,函数作用域中的变量优先被访问,只有没有这个变量的时才会向作用域外访问。直到都没有就报错。(函数中变量优先级高于全局作用域)
let a = 2 function fn () { let a = 1 console.log(a) // 1 function fn2() { let b = 2 console.log(a) // 1 } fn() console.log(b) // 报错 }
参数也是变量,叫参数变量,属于函数内部。参数变量的优先级低于函数内部变量
function fn (x, y) { x = 10 console.log(x) // 10 } fn(20, 1)
参数变量在使用时就是一个声明变量的过程,所能不能重复声明(针对let和const),非必要,尽量避免参数变量和函数内部变量名冲突。
外部变量能不能和参数变量冲突呢???函数内部的变量的可以和全局变量相同名称,内部优先,因为参数变量页属于函数,所以可以冲突,优先获取参数变量。
let year = new Date().getFulleYear() function isLeapYear (year) { // year用的是参数变量year,而不是全局year } isLeapYear(year) // 这个year是全局中的year
函数作用域的应用
// function () {} // 匿名函数 function () {}()
块级作用域
js最初没有所谓的块级作用域,就是在代码块中的作用域
if (条件) { // 这个就是代码块 var a = 1 } console.log(a) // 1
ES6中提出了let
和const
这两个声明变量的方式赋予了js块级作用域
if (条件) { let a = 1 } console.log(a) // 报错
那么如果我们确实要在代码块内部对变量赋值,又想在外部获取
let a if (条件) { a = 1 } console.log(a) // 1
当我们使用for循环时,let和var声明的i最终表现不同
for (var i = 0; i < 5; i++) {} console.log(i) // 5
for (let i = 0; i < 5; i++) { // 可以正确的获取到i的值 } console.log(i) // 报错
一个应用
let btn = document.querySelectorAll('button') for (var i = 0; i < btn.length; i++) { btn[i].onclick = function () { console.log(i) // 如果使用let声明,则点击不同的按钮,出现不同的下标,如果使用var,则都是btn.length } }
var存在的问题
不存在块级作用域
var没有块级作用域,所以在代码块中声明的变量,外部可以直接获取
var变量提升
console.log(a) // undefined var a = 1
上面代码相当于
var a console.log(a) a = 1
let const都不会有这个情况。
函数中声明变量的话,如果不屑声明的关键字,则会变成全局变量
function fn () { x = 10 } fn() console.log(x) // 10