webveuje/js/kejian/zuoyongyu.md

193 lines
4.5 KiB
Markdown
Raw Normal View History

2021-03-23 10:58:10 +08:00
# 作用域
### 练习
```
var color = "blue";
function changeColor() {
let anotherColor = "red";
function swapColors() {
let tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问color、anotherColor和tempColor
}
// 这里可以访问color和anotherColor但访问不到tempColor
swapColors();
}
// 这里只能访问color
changeColor();
```
分析上面的作用域链:
<details>
<summary>展开查看</summary>
* window
* color
* changecolor()
* anothercolor
* swapcolors()
* tempcolor
</details>
### 垃圾回收机制
优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。如果数据不再必要那么把它设置为null ,从而释放其引用。这也可以叫作解除引用 。这个建议最适合全局变量和全局对象的属性。
局部变量在超出作用域后会被自动解除引用
即 全局变量(GO) 不会被销毁,但是局部变量(AO)函数执行完后会被销毁
也可以手动销毁变量即赋值为null
如下面的例子所示:
```
function createPerson(name){
let localPerson = new Object();
localPerson.name = name;
return localPerson;
}
let globalPerson = createPerson("Nicholas");
// 解除globalPerson对值的引用
//globalPerson = null;
```
解析:
<details>
<summary>展开查看</summary>
在上面的代码中变量globalPerson 保存着createPerson() 函数调用返回的值。在createPerson() 内部localPerson 创建了一个对象并给它添加了一个name 属性。然后localPerson 作为函数值被返回并被赋值给globalPerson 。localPerson 在createPerson() 执行完成超出上下文后会自动被解除引用不需要显式处理。但globalPerson 是一个全局变量,应该在不再需要时手动解除其引用,最后一行就是这么做的。
不过要注意,解除对一个值的引用并不会自动导致相关内存被回收。解除引用的关键在于确保相关的值已经不在上下文里了,因此它在下次垃圾回收时会被回收。
</details>
### 闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
```
function a() {
var x = 0;
return function(y) {
x = x + y;
// return x;
console.log(x);
}
}
var b = a();
b(1); //1
b(1); //2
```
练习1
```
function fn() {
var max = 10;
return function bar(x) {
if (x > max) {
console.log(x);
}
};
}
var f1 = fn();
f1(15);
```
练习2
```
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();
```
<details>
init() 创建了一个局部变量 name 和一个名为 displayName() 的函数。displayName() 是定义在 init() 里的内部函数,并且仅在 init() 函数体内可用。请注意displayName() 没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 displayName() 可以使用父函数 init() 中声明的变量 name 。
</details>
hrefs:
https://blog.csdn.net/weixin_43586120/article/details/89456183
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
```
(function() {
var m = 0;
function getM() { return m; }
function seta(val) { m = val; }
window.g = getM;
window.f = seta;
})();
f(100);
console.info(g());
```
<hr/>
```
function fn(){
var arr = [];
for(var i = 0;i < 5;i ++){
arr[i] = (function(i){
return function (){
return i;
};
})(i);
}
return arr;
}
// 立即执行函数 每调用一次完成后就自动销毁
var list = fn();
for(var i = 0,len = list.length;i < len ; i ++){
console.log(list[i]());
} //0 1 2 3 4
```
```
function fn(){
var arr = [];
for(var i = 0;i < 5;i ++){
arr[i] = function(){
return i;
}
}
return arr;
}
var list = fn();
for(var i = 0,len = list.length;i < len ; i ++){
console.log(list[i]());
} //5 5 5 5 5
```
```
var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick = function(){
console.log(i);
};
})(i); //事件处理函数中闭包的写法
}
```
```
var li = document.getElementsByTagName( "li" );
   for ( var i = 0; i < li.length; i++) {
li[i].addEventListener( "click" , function () {
console.log(i);
})
}
```