首页 > 代码库 > ECMAScript学习笔记
ECMAScript学习笔记
let和const命令
- let声明的作用域为代码块,不存在变量提升。
- let不允许在相同的作用域内,重复声明同一个变量。
- const用法与let类似,区别是const声明的变量是常量。
为什么需要块级作用域?
- 内层变量可能会覆盖外层变量
- 用来计数的循环变量泄漏为全局变量
对象的解构赋值
默认值生效的条件是,对象的属性值严格等于undefined。
以下三种解构赋值不得使用圆括号
- 变量声明语句中,不能带有圆括号
- 函数参数中,模式不能带有圆括号
- 赋值语句中,不能将整个模式,或嵌套模式中的一层,放在圆括号中
可以使用圆括号的情况
- 赋值语句的非模式部分,可以使用圆括号
变量解构赋值的用途:
- 交换变量的值
- 从函数返回多个值
- 函数参数的定义
- 提取JSON数据
- 函数参数的默认值
- 遍历Map结构
- 输入模块的指定方法
字符串的扩展
函数的扩展
什么是尾递归(Tail Call):就是指某个函数最后一步调用另一个函数。函数调用会在内存形成一个“调用记录”,又称“调用帧”,保存调用位置和内部变量等信息。尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息已经不会再用到了,只要直接用内层函数取代外层函数的调用帧就可以了。
fibonacci数列的例子说明如下:
function Fibonacci(n) {
if (n <= 1) {
return 1;
};
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
console.log(Fibonacci(10));
function FibonacciTailCall(n) {
var ac1 = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1];
var ac2 = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];
if (n <= 1) {
return ac2;
}
return FibonacciTailCall(n - 1, ac2, ac1 + ac2);
}
console.log(FibonacciTailCall(1000));
对象的扩展
ES6允许在对象中只写属性名,不写属性值,此时属性值等于属性名所代表的变量。
描述对象的 enumerable
属性,成为“可枚举性”,如果该属性为 false
,就表示某些操作会忽略当前属性。 ES5 有三个操作会忽略 enmerbale
为 false 的属性。
for...in
循环:只遍历对象自身和继承的可枚举属性Object.keys()
:返回对象自身的所有可枚举属性的键名JSON.stringify()
:只串化对象自身的可枚举的属性
ES6 新增了一个操作Object.assign()
,会忽略enumerable
为false
的属性,只拷贝对象自身的可枚举属性。
Symbol
ES5 的对象属性名都是字符串,容易造成属性名的冲突。如果有一种机制保证每个属性的名字都是独一无二,这样就从根本上防止了属性名的冲突,这就是ES6引入Symbol的原因。
Proxy和Reflect
Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程(meta programming)”,即对编程语言进行编程。
二进制数组
由于WebGL是指浏览器与显卡之间的通信接口,需要满足大量的、实时的数据交换,所以它们之间的通信必须是二进制的。
二进制数组由三类对象组成:
- ArrayBuffer对象:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。
- TypeArray视图:共包括9种类型的视图,比如Uint8Array数组视图、Int16Array数组视图、Float32Array数组视图
- DataView视图:可以自定义符合格式的视图,比如第一个字节是Uint8、第二三个字节是Int16、第四个字节是Float32Array数组视图等。
简单来说,ArrayBuffer对象代表原始的二进制数据,TypeArray视图用来读写简单类型的二进制数据,DataView视图用来读写复杂的二进制数据。ArrayBuffer对象代表存储在二进制数据的一段内存,它不能直接读写,只能通过视图读写,视图的作用是以指定格式解读二进制数据。
TypedArrary数组的构造函数,可以接受另一个TypedArray实例作为参数。此时生成的新数组,只是复制了参数数组的值,对应的底层内存是不一样的。新数组会开辟一段新的内存存储数据,不会在原数组的内存之上建立视图。
如果想在遍历操作中,同步改变原来的Set结构,目前并没有直接的方法,但有两种变通反复。一种是利用原Set结构映射出一个新的结构,然后赋值给原来的Set结构;另一种是利用 Array.from
方法
Tips: Map中,只有对同一对象的引用,Map结构才将其视为同一个键。
Class
ES5的继承,实质是先创造了子类的实例对象 this ,然后再将父类的方法添加到 this 上面( Parent.apply(this) )。ES6的继承机制安全不同,实质是先创造父类的实例对象 this (所以必须先调用 super 方法),然后再用子类的构造函数修改 this 。
Class作为构造函数的语法糖,同时有prototype属性和proto属性,因此存在两条继承链。
- 子类的proto属性,表示构造函数的继承,总是指向父类。
- 子类 prototype 属性的 proto 属性,表示方法的继承,总是指向父类的 prototype 属性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
ECMAScript学习笔记