js底层原理
js原理,js内存中只存在一种——关联数组。不涉及堆栈
举例:var a = 10; a应存放在栈内存中,但是window.a 是可以访问a的,window是对象,应该存放在堆内存中。这不就自相矛盾了。
所以一切内存关系,都是关联数组。证明:window.a / window[a] 都可访问 10;
作用域&作用域链
js中,作用域和作用域链都是对象结构。更准确来说是关联数组
作用域(scope)
浅显定义
作用域就是变量的可用范围
为什么要有作用域
目的是防止不同范围的变量之间互相影响
JS中包含2类作用域
作用域有两类:全局作用域和函数作用域
全局作用域
不属于任何函数的外部范围称为全局作用域。
其实是一个名为 window 的对象,所有的全局变量和全局函数都是window对象的成员
定义在全局的变量叫全局变量
全局变量的特点:
优点:可反复使用
缺点:全局污染——开发时,如果是变量,禁止使用
函数作用域
一个函数内的范围称为函数作用域
其实是JS引擎在调用函数时才临时创建的一个作用域对象。其中保存函数的局部变量。函数调用完,函数作用域对象就会释放
所以js中函数作用域对象,还有个别名——(活动的对象(Actived Object)),简称,AO。所以,局部变量不可重用
保存在函数的变量叫局部变量,除在函数内声明的变量,形参也属于局部变量
局部变量的特点:
优点:不造成污染
缺点:无法重复使用
不是所有的{}都能生成函数作用域,也不是所有的{}内的数据都是局部变量,只有函数function内的变量才是局部变量, 也只有函数{}会形成作用域. 例如
console.log(a);
if (false) {
var a = 10;
}
console.log(a);
局部变量:只有两种, 只要看不到var,也不是形参,就不是这个函数的局部变量。
- 函数内 var 出来的
- 函数的形参变量。
作用域链(scopes)
js规定,一个函数,既要用到自己作用域内的变量,又想用到外层乃至window的作用域变量,就通过像路线图一样的作用域链关联起来。
在定义函数时,就已经规划好自己由内向外的查找变量的路线,称为作用域链
一个函数可用的所有作用域串联起来,就形成函数的作用域链,而当执行某条语句时,js引擎就会自动按照由内向外延函数作用域链进行查找要用的变量。
查找不到时
会报错 “ x is not defined”
当给未声明的变量赋值时
不报错,而是自动在全局创建变量 x
闭包
浅显定义
即重用变量又保护变量不被污染的一种编程方法。
如何使用(三步)
- 用外层函数包裹 要保护的变量和使用变量的内层函数
- 在外部函数内返回内部函数对象
- 调用外层函数,用变量接住内层函数对象
// 第一步
function mother(){
var total=1000;
function pay (money) { // 第二步
total -= money;
console.log(花了${money}还剩${total}元) }
}
}
var pay=mother(); // 第三步
闭包是如何形成的
外层函数调用后,外层函数被返回的内层函数的作用域链引用着,无法释放,形成闭包对象
闭包缺点
由于闭包藏得很深,几乎找不到,所以,极容易内存泄漏
解决:将保存内层函数的对象的变量赋值为null