作用

储存数据的状态

==============

定义变量

image.png

var 正常声明(不再推荐)

  1. var a=1,b=2,c=3;

全局变量

var声明的都是window对象的变量,而let、const声明的不是。

  1. var name = 'Matt';
  2. console.log(window.name); // 'Matt'

let 块级作用域内声明(次之)

不允许let、var重复声明同一个变量。不会被变量提升

  1. var x = 2;
  2. {
  3. let x = 1; //块级作用域里面有效
  4. {
  5. console.log(x); //1,作用域链里面有效
  6. }
  7. }
  8. function abc() {
  9. console.log(x);
  10. }
  11. abc(); //2

const 当前作用域的常量声明(优先)

声明一个当前作用域的只读常量,不能被改变。

不许重复声明同一个变量。
image.png

对于引用类型的变量(对象、数组),改变内部是没问题的。

  1. const obj = { // 内存里面创建了一个内存地址,obj指向这个内存地址
  2. foo:123
  3. }
  4. obj.foo = 321 // 这里只是修改内存地址里面的变量,没问题
  5. obj = {} // 报错,修改了obj的指向

总结

const > let > var

image.png

===============

特性

变量类型

变量是松散类型的,意思是变量可以用于保存任何类型的数据,并且随时可以改变。

  1. var message = "hi";
  2. message = 100; // 合法,但不推荐

命名规则

1.变量必须使用字母、下划线(_)或者美元符($)开始。

2.然后可以使用任意多个英文字母、数字、下划线(_)或者美元符($)组成。

3.不能使用JavaScript关键词与JavaScript保留字。

4.重复声明变量,值可能不会丢失,如:

  1. var a="abc";
  2. var a; //"abc"

5.全局的变量,一般会加_开头

命名规范

image.png
image.png
image.png
image.png

变量提升

var

  1. console.log(a); //undefined 变量提升,相当于先把赋值语句var a = undefined提升到最前面执行,后执行其他语句。
  2. var a = 123;
  3. console.log(b); //ReferenceError报错
  4. let b = 123;
  5. console.log(c); //ReferenceError报错
  6. const c = 123;

let 和 const
image.png
实际上ECMA的描述,访问foo的时候,是会先创建出来,但是不能提前访问,因此会报错

暂时性死区

image.png

=============

ES6 解构赋值

如果中途出错,会完成出错前的那部分赋值

1、数组

image.png
image.png

2、对象

image.png
image.png image.png

image.png(不像数组,可以不要求顺序,会找对应属性名)

image.png(找到属性名为name后,赋值给新变量名newName)

image.png (找到属性名为name后,赋值给新变量名newName,如果找不到,就用默认值”广州市”)

使用场景

image.png

================

原始值与引用值

解释

原始值(primitive value)就是最简单的数据(基本数据类型:Undefined、Null、Boolean、Number、String 和 Symbol)
引用值(reference value)则是由多个值构成的对象(数组和对象)

内存储存

保存原始值的变量是按值(by value)访问的,因为我们操作的就是存储在变量中的实际值。
引用值是保存在内存中的对象,记录的是内存的地址,但JavaScript 不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。

复制

原始值复制,是开辟新的空间,然后把数值复制过去

  1. let num1 = 5;
  2. let num2 = num1;

image.png image.png

引用值赋值,赋的是内存地址,因此两个变量实际上指向同一个内存地址。
image.png

=================

上下文对象(作用域)

image.png
image.png

块级作用域

image.png
image.png

image.png(let声明的只在if的块级作用域内使用,let定义的外面无法访问)

image.png(switch的也是块级作用域,let定义的外面无法访问)

image.png(for也是块级作用域,let定义的外面无法访问)

块级作用域应用

页面上创建4个按钮,给每个按钮一个点击事件,点击时打印
image.png(结果发现点什么都是第4个按钮被点击)
原因是点击时,去查找i这个变量,这个变量是全局的,给所有按钮添加完后,i=4了,因此不管怎么点击都是4

以前的解决方法,是用一个立即执行函数包围,形成自己的作用域
image.png

现在的解决方法,直接用let就可以了
image.png

=================

垃圾回收

过自动内存管理,实现内存分配 和 闲置资源回收。

在浏览器的发展史上,用到过两种主要的标记策略:标记清理和引用计数

标记清理:标记处于函数中的变量,执行完后一段时间就清理

引用计数:被引用就+1,引用的被覆盖就-1,到0就回收。问题比较多,很少用。

如果数据不再必要,那么把它设置为 null,从而释放其引用。这也可以叫作解除引用

1. 通过 const 和 let 声明提升性能

2. 隐藏类和删除操作

3. 内存泄漏

意外声明全局变量是最常见但也最容易修复的内存泄漏问题。
定时器setInterval( )也可能会悄悄地导致内存泄漏。
闭包很容易在不知不觉间造成内存泄漏。

4. 静态分配与对象池

  1. // vectorPool 是已有的对象池
  2. let v1 = vectorPool.allocate();
  3. let v2 = vectorPool.allocate();
  4. let v3 = vectorPool.allocate();
  5. v1.x = 10;
  6. v1.y = 5;
  7. v2.x = -3;
  8. v2.y = -6;
  9. addVector(v1, v2, v3);
  10. console.log([v3.x, v3.y]); // [7, -1]
  11. vectorPool.free(v1);
  12. vectorPool.free(v2);
  13. vectorPool.free(v3);
  14. // 如果对象有属性引用了其他对象
  15. // 则这里也需要把这些属性设置为 null
  16. v1 = null;
  17. v2 = null;
  18. v3 = null;

如果你的应用程序被垃圾回收严重地拖了后腿,可以利用它提升性能。但这种情况并不多见。大多数情况下,这都属于过早优化,因此不用考虑。