学习《JavaScript 数据结构与算法》读书笔记和勘误?
第1章 JavaScript简介
1.3 JavaScript基础
1.3.1 变量
变量作用域1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var myVariable = 'global';
myOtherVariable = 'global';
function myFunction() {
var myVariable = 'local';
return myVariable;
}
function myOtherFunction() {
myOtherVariable = 'local';
return myOtherVariable;
}
console.log(myVariable); /* 'global' */
console.log(myFunction()); /* 'local' */
console.log(myVariable); /* 'global' */
console.log(myOtherVariable); /* 'global' */
console.log(myOtherFunction()); /* 'local' */
console.log(myOtherVariable); /* 'local' */
1.3.2 操作符
1 | console.log('5 & 1 : ', (5 & 1)); /* 5 & 1 : 1 */ |
位操作符 | 描述 | |
---|---|---|
& | 与 | |
` | ` | 或 |
~ | 非 | |
^ | 异或 | |
<< | 左移 | |
>> | 右移 |
1.3.4 相等运算符
不同类型的值用相等操作符比较后的结果
类型(x) | 类型(y) | 结果 |
---|---|---|
null | undefined | true |
undefined | null | true |
数字 | 字符串 | x == toNumber(y) |
字符串 | 数字 | toNumber(x) == y |
布尔值 | 任何类型 | toNumber(x) == y |
任何类型 | 布尔值 | x == toNumber(y) |
字符串或数字 | 对象 | x == toPrimitive(y) |
对象 | 字符串或数字 | toPrimitive(x) == y |
如果 x 和 y 是相同类型,JavaScript 会比较它们的值或对象值。其他没有列在这个表格中的情况都会返回false。
toNumber 和 toPrimitive 方法是内部的,并根据以下表格对其进行估值
toNumber 方法对不同类型返回的结果如下:
值类型 | 结果 |
---|---|
undefined | NaN |
null | +0 |
布尔值 | 如果是 true ,返回1;如果是 false ,返回+0 |
数字 | 数字对应的值 |
字符串 | 将字符串解析成数字。如果字符串中包含字母,返回NaN;如果是由数字字符组成的,转换为数字 |
对象 |
toPrimitive方法对不同类型返回的结果如下:
值对象 | 结果 |
---|---|
对象 | 如果对象的valueOf方法的结果是原始值,返回原始值。如果对象的toString方法返回原始值,就返回这个值;其他情况都返回一个错误 |
1.6 JavaScript 面向对象编程
在面向对象编程(OOP)中,对象是类的实例。一个类定义了对象的特征。我们会创建很多类来表示算法和数据结构。例如我们声明了一个类来表示书:
1 | function Book(title, pages, isbn) { |
用下面的代码实例化这个类
1 | var book = new Book('title', 'pag', 'isbn') |
然后,我们可以访问和修改对象的属性:
1 | console.log(book.title); |
类可以包含函数。可以声明和使用函数,如下所示:
1 | Book.prototype.printTitle = function() { |
也可以直接在类的定义里声明函数
1 | function Book(title, pages, isbn) { |
在原型的例子里,printTitle 函数只会创建一次,在所有实例中共享。如果在类的定义里声明,就像前面的例子一样,则每个实例都会创建自己的函数副本。使用原型对下方法可以节约内存和降低实例化开销。不过原型方法只能声明公共函数和属性,而类定义可以声明只在类的内部访问的私有函数和属性。
1.9 ECMAScript 6 的功能
1.9.6 声明展开和剩余参数
在 ES5 中,我们可以用 apply()
函数把数组转化为参数。为此, ES6 有了展开操作符 ...
。举例来说,考虑我们上一节声明的 sum 函数。可以执行如下代码来传入参数 x, y, z 。
1 | function sum(x = 1, y = 2, z = 3) { |
1 | var params = [3, 4, 5]; |
以上代码和下面的 ES5 代码的效果是相同的:
1 | var params = [3, 4, 5]; |
在函数中,展开操作符也可以代替 arguments
,当作剩余参数使用。考虑如下例子:
1 | function restParamaterFunction(x, y, ...a) { |
以上代码和下面代码的效果是相同的:
1 | function restParamaterFunction(x, y) { |
增强的对象属性
ES6引入了数组解构的概念,可以用来一次初始化多个变量
1 | var [x, y] = ['a', 'b']; |
以上代码和下面代码的效果是相同的:
1 | var x = 'a'; |
数组解构也可以用来进行值的互换,而不需要创建临时变量,如下:
1 | [x, y] = [y, x]; |
以上代码和下面代码的效果是相同的:
1 | var temp = x; |
还有一个属性简写的功能,它是对象结构的另一种方式
1 | var [x, y] = ['a', 'b']; |
以上代码和下面代码的效果是相同的:
1 | var x = 'a'; |
本节我们要讨论的最后一个功能是方法属性。这使得开发着可以在对象中声明看起来像是属性的函数。下面是一个例子:
1 | var hello = { |
以上代码也可以写成下面这样:
1 | var hello = { |
1.9.6 使用类进行面向对象编程
ES6还引入了一种更简洁的声明类的方式
之前:
1 | function Book(title, pages, isbn) { |
可用ES6简化为
1 | class Book { |
两段代码具有相同的效果和输出
1 | let book = new Book('title', 'pages', 'isbn'); |
继承
除了新的声明类的方式,类的继承也有了简化的语法。
1 | class ITBook extends Book { |
我们可以用 extends
关键字扩展一个类并继承它的行为。在构造函数中,我们也可以通过 super
关键字引用父类的构造函数。
使用属性存取器
使用新的类语法也可以为属性创建存取器函数。虽然不像其他面向对象语言(封装概念),类的属性不是私有的,但最好还是遵循一种命名模式。
下面的例子是一个声明了 get
和 set
函数的类:
1 | class Person { |
要声明 get
和 set
函数,只需要在我们要暴露和函数名前面加上 get
和 set
关键字。我们可以用相同的名字声明类属性,或者在属性名前面加下划线,让这个属性看起来像是私有的。
然后,只要像普通属性一样,引用它们的名字,就可以执行 get
和 set
函数。
其他功能
列表迭代器、类型数组、 Set
、 Map
、 WeakSet
、 WeakMap
、模块、尾调用、 Symbol
等等
查看ES6全部功能和规范