作用域: 变量生效的限定环境
全局/顶层作用域 存在于script标签以及js文件
全局作用域内声明的变量称之为全局变量,全局变量,可以在整个作用域内使用.
所有的全局的环境都是互通的
函数作用域
1.函数作用域内声明的变量,只能在当前函数作用域内使用,在别的作用域内访问不到.
2.每个函数,都会生成一个独立的函数作用域
3.函数作用域内的函数作用域,属于包含关系,不存在交集的函数作用域,则互不干扰
4.函数使用全局变量,会改变全局变量的值
!!!作用域链 多个作用域相互嵌套
! 当我们处于某一个作用域里面使用变量时,先从自身作用域里面找该变量,如果找不到,就往父级作用域里面查找,直到script作用域,,还是没有就报错
! 当我们处于某一个作用域里面,修改某个变量的值时,先修改自己的,如果没有,就修改父级,直到script作用域都找不到,默认设置全局变量
! 无论什么环境下,没有声明就直接赋值的变量都会泄露成为window的属性,类似全局变量,window下面的属性 比全局还要高 var 和 function声明的全局变量,也会挂载到window的属性 let const不会
挂载上去的属性 可以delete删除 声明的全局变量不行
a = 1; delete a;
if for内的 var 声明 如果 if 在 全局作用域内 那么在if内用var 声明的变量则为全局变量.
//认{}为域
if(true){ var a = 1 let b = 2 }
console.log(a)// 1
console.log(b)// not defined
for循环内let 声明的块作用域 let具备块作用域 因此for一共有10个块作用域,每个作用域内的i值不一样 每次触发使用的是 块作用域内存的 i 值
for(var i = 0 ; i < 10 ; i++){
box[i].onclick = function (){
console.log(i) //点击只输出 10 }
}
for(let i = 0 ; i < 10 ; i++){
box[i].onclick = function (){
console.log(i) //输出当前点击的i值 }
}
JavaScript是具有自动垃圾收集机制的。通常情况下,程序在执行的过程中,会存储各种变量以及环境(作用域)。如果不对不需要的内容定时清理,就会使得页面的内存占用越来越多,使得浏览器越来越卡影响用户体验,所以,需要对不需要的变量或者没有使用的作用域进行定期清理。定时删除不需要无影响的内容。
这种清理是自动的,无需手动管理,这是依赖优秀的垃圾回收机制。
在我们全局里面的就是全局变量,浏览器关闭之后才会自动回收,当我们浏览器打开,会自动开辟一个空间来放它的值,所以我们要减少全局变量的使用.在局部里面声明的变量就是局部变量,局部变量里面的变量没有使用的时候,自动就会回收
var obj = document.getElementById("box");
obj.style.color = "blue";
obj = null;//清空指向
临时作用域 函数()形参内 在函数运行瞬间执行
案例 1
let x = 1
function fn (y = x) {
let x = 2
console.log(y) }
fn() //1 编译 x fn 执行fn() 瞬间 编译 :无 瞬间 执行:y = 1 内部编译 : x 执行 x = 2 con y => 1
案例二
let x = 1
function fn(x = 2,y = function(){x = 2}){ console.log(x) x = 3 y() console.log(x) }
fn() /* 编译阶段 x fn 执行 fn() => 瞬间 编译 y x = 2 y = fun 函数内部编译:无 内部执行: con x => 2 x = 3 y() x = 2 重新赋值 con x =>2 */
1.浏览器中配备 js解释器,用于执行js代码
2.js是解释性语言,js需要工具翻译成对应的机器底层码,可以被识别
3.js解释器并没有一个统一的规范 (造成存在的兼容的问题)
4.v8引擎放到服务器,js就可以在服务器环境执行
var function 声明存在提升的问题,因此 es5 js的执行有两个阶段 一个是编译 一个是执行
js执行流程: 面试常客
编译:找变量 找函数 对代码进行静态分析 检查语法是否符合规范 无关启动函数与否 (编译阶段发现语法错误,直接报错不执行)
执行:运行js代码 赋值等操作
//编译时期 抛出错误 演示 无关执行与否 在编译期就直接终止
function fn(){ var a + b = 2 }
alert(a)
var a = 1
function a(){
console.log(a)
}
alert(a)
//编译阶段 : 找声明 var a function a(){} 由于function权重大 所以 可以覆盖var a
//执行阶段: alert(a) => function a a = 1 alert(a) => 1
//练习1
function f(){ var g = 1; alert(g) }
function f() { var g = 2 alert(g) }
alert(f)
f()
var f = 5
f()
编译阶段: function f 第一个 =>pass function f 第二个 =>ok var f =>pass 执行阶段: alert(f) =>function f 2 f() => funtion 第二个 => 编译 :var g 执行 :g = 2 alert(g) => 2 f = 5 f() => 报错 5 不是函数 ```
//练习2
fn()
alert(s)
var s = 0;
alert(s)
function fn() { var a = 1 }
编译阶段: var s fn function 执行阶段 : fn() => 编译:var a 执行 a = 1 alert(s) =>undefined s = 0 alert(s) => 0 ```
由于垃圾回收机制的存在,所以一个作用域内声明的变量是不被存储的,因此不能再前一次的基础上使用.只能重头再来,
function fn(){ let a = 2; a++ console.log(a) }
fn() // 3
fn() // 3
//不能在前一次的基础上,进行运算,因为函数执行完毕,变量没有用处之后,会被回收
//函数可以保留自己的作用域并可以访问它的作用域就产生了闭包
// 闭包的条件 : 一个函数里面嵌套一个函数 ,内部函数引用外部函数的变量或者参数 // 闭包的作用 : 使局部变量不会被销毁,得以存储
function fn(){
var a = 1
return function fn1(){
a++ return a
}
}
let b = fn()
//保留了函数fn1 函数fn1可以访问fn的作用域里面的a 并且对它进行改变,这意味着 a的作用域在fn执行完成之后保留了下来,保留在函数fn1中
b()//2
b()//3
作用 小案例
// 1
function money(){
var ATM = { "money": 100 }
console.log("你的钱是:"+ ATM.money)
return {
"add":function(){
//存钱
ATM.money += 10;
//每次存十元
console.log("你的钱是:"+ ATM.money); },
"lost":function()
{
//消费
ATM.money-=5;
//每次消费5元
console.log("你的钱是:"+ ATM.money); },
"get":function(){
return ATM.money; } } }
var xx = money();
//"你的钱是:100" 初始钱
xx.add();//"你的钱是:110"
xx.lost();//"你的钱是:105"
//2
function fn(){
var ss = 123
function A(){ console.log(ss) }
window.$ = A;
//将foo作用域里面的A存储到全局window下的$中也是形成闭包。
}
fn();
window.$()
闭包坏处:: 闭包使用的父级函数的变量或者参数,会被永久保存,直到窗口关闭,使用过多会导致ie内存泄漏(可分配的内存的资源减少) 占内存 非常杂乱 找东西慢 效率低 生命周期和全局变量一样