《JavaScript 语言精粹 (修订版)》阅读笔记详解,一篇文章解决你的疑惑,很适合初学者阅读!

目录

前言:

核心部分:

①语法

(1)空白与注释

(2)标识符 - 保留字

(3)数字

(4)字符串

(5)语句

(6)表达式

(7)字面量(对象 )

(8)函数

②对象

③🌟函数 

④继承 

⑤数组

⑥方法

其他

①正则表达式

②代码风格

③优美的特性

附录

 ①毒瘤

②糟粕

总结:

①优点: 

②缺点:


这篇文章为观看这个博主笔记,详情请点击链接查看!支持原作者!

一小时读完《JavaScript 语言精粹(修订版)》_哔哩哔哩_bilibili《JavaScript 语言精粹(修订版)》作为 JavaScript 经典书籍,你是否已经将它彻底融会贯通了?本视频通过一个小时帮助你阅读 《JavaScript 语言精粹(修订版)》~~文档版访问地址:https://juejin.cn/post/7193625406636261413/ github 仓库地址:https://github.com/lgd8981289/book_read_q, 视频播放量 16805、弹幕量 29、点赞数 586、投硬币枚数 368、收藏人数 1941、转发人数 73, 视频作者 LGD_Sunday, 作者简介 以每周一本的速度,产出《程序员专业技术书籍》讲解视频。前端专业技术知识、发展方向、面试等内容(不定期更新)。@黑马程序员-济南校区,相关视频:【前端进阶】2023涨薪必备:Element-UI源码深入解析系列课程!年前看完,年后涨薪!,为初学者准备的:JavaScript 速成,JavaScript从入门到精通(美女老师版),一小时读完《Vue.js 设计与实现》,JavaScript核心基础_讲师(李立超)_JS教程,【Udemy排名第一的JavaScript课程】2023最新完整JavaScript课程 从入门到精通 -- 通过项目、挑战和理论掌握JS(中英文字幕)上,一小时读完《JavaScript权威指南(第7版)》上,一小时读完《你不知道的JavaScript(上卷)》,Shell脚本少走99%的弯路,整整100全程干货无废话,小白也可以听得懂!,尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版https://www.bilibili.com/video/BV1JY4y1R7vq/?spm_id_from=333.1007.top_right_bar_window_history.content.click

前言:

①为什么要使用JavaScript?   因为你没得选!

②分析JavaScript
优秀的想法:

  • 函数
  • 弱类型
  • 动态对象
  • 对象字面量

糟糕的想法:
基于全局变量的编程模型;
即JavaScript 是一个反差鲜明的语言和精华一样显眼。


核心部分:

①语法

(1)空白与注释

  • 单行注释  // 单行注释内容
  • 多行注释  /* 多行注释内容 */

另外一种多行注释值得推荐:/ ** 多行注释内容 /

(2)标识符 - 保留字

abstract
boolean break bytecase tatch char class const continuedebugger default delete do double else enum export extends false final finally float for function goto
if implements import in instanceof int interface long native new null
package private protected public return
short static super switch synchronized this throw throws transient true try typeofvar volatile void while with

在 JavaScript 中,有一些保留字(Reserved Words)是已经被语言本身所预留的,因此不能用作标识符(如变量名、函数名等)。这些保留字无法被重新定义或赋值,因为它们是语言的关键部分,用于控制数据和程序的流程。

(3)数字

只有一种数字类型:number

在 JavaScript 中,number 数据类型是用来表示数字的。它可以包含整数和小数,以及正数、负数和零。JavaScript 中的 number 类型采用的是 IEEE 754 标准中的双精度浮点数表示法,即64位二进制表示方式,其中52位用于有效数字,11位为指数部分,1位为符号部分。

JavaScript 中只有 number 数据类型,而没有独立的整数数据类型和浮点数数据类型,这是由语言本身特性决定的。在 JavaScript 中,所有的数字都被视为 number 类型,并且在使用时会自动进行类型转换。这种类型转换的特性使得 JavaScript 中的数字计算更加灵活,但也为开发者带来了一些注意事项,例如在比较数字时要注意类型转换可能带来的误差

为什么 JavaScript 只有 number 类型呢?这与 JavaScript 的设计初衷和历史有关。JavaScript 最初是一种用于处理网页上简单交互的脚本语言,因此其设计目标是简单、易学易用。当时并没有考虑到需要独立的整数和浮点数类型,而是将所有数字作为 number 类型处理。JavaScript 作为一门动态弱类型语言,这种设计反而使得其更加灵活和易于使用,同时也避免了类型转换可能带来的性能损失。

总之,JavaScript 中的 number 数据类型用于表示数字,它采用双精度浮点数表示法,并且是 JavaScript 中唯一的数字类型。这种设计使得 JavaScript 更加灵活和易于使用,同时也需要开发者在使用时注意类型转换可能带来的误差。

(4)字符串

1️⃣字面量

  • 单引号
  • 双引号

在 JavaScript 中,表示字符串值的文本可以使用单引号(')或双引号(")来括起来,例如 'Hello World!' 或 "Hello World!"。不同的引号风格在语言上是等价的,使用哪一种都可以达到相同的效果。

然而,通常情况下,JavaScript 开发人员更倾向于使用单引号而非双引号来表示字符串字面量。这是因为 JavaScript 的语言规范中没有明确规定使用哪种引号风格,但是在开源社区和热爱 JavaScript 编程的人群中,有一种共识认为,尽可能地使用单引号更加符合 JavaScript 编码规范和风格。

这种偏好主要基于以下几个方面的考虑:

1.与 HTML 中的双引号形成对称。在编写 JavaScript 代码时,通常需要将 JavaScript 代码和 HTML 代码混合在一起。而 HTML 中经常使用双引号来定义属性值,因此使用单引号可以避免产生视觉上的混乱。

2.更易于书写。在键盘中输入单引号比输入双引号要快,因此如果大量使用字符串字面量,则使用单引号更加方便。

3.可读性更强。单引号风格会使字符串字面量的分隔符与字符内容保持一致,可以使代码更加易读,也有利于代码静态分析。

需要注意的是,在 JavaScript 中,单引号和双引号的作用是等价的,因此选择哪种风格并不是绝对的规则。编码时应该考虑到项目的具体情况和团队的编码风格,以便在整体上保持统一性和可读性。

2️⃣特性

  • 可拼接
  • 可length
  • 有方法

(5)语句

1.概念

  • 编译单元   <script> 标签
  • 代码块  一对花括号中的一组语句

2.声明语句

  • 陈日的: var
  • 变量:let
  • 常量: const

这是es6 之后的,书中仅提到 var



3.条件语句

if
switch

任何表达式可作为判断条件

假:

  • false
  • null
  • undefined
  • 空字符串
  • 数字 0
  • NaN

真:

其他所有


4.循环语句

for

  • 普通的: for(初始化从句;条件从句;增量从句)
  • forln: for (key in object)

while 

do  结合while使用



5.强制跳转语句

  • break  退出循环 || switch
  • continue 终止当前循环 (书中并未提到,因为作者认为这是一个糟粕)
  • return 中断函数,返回值(注: 函数默认 return undefined)
  • throw  抛出异常
  • try...catch... 捕获异常

(6)表达式

:组代码的集合,返回一个值

  • 算数  例如3.1415926
  • 字符串  例如“张三”
  • 逻辑值  逻辑运算符得到一个 boolean 型的值
  • 左值表达式
    • const o = new Object()
    • const arr = [, 2, 3]
  • 基本表达式:基本的关键字和一般表达式

(7)字面量(对象 )

按照指定规格创建新对象的表示法

  • const arr = [l, 2, 3]
  • const o = { ... }

(8)函数


②对象

1.定义:

1️⃣简单数据类型

  • number
  • string
  • boolean
  • null
  • undefined
  • symbol
  • bigint

在 JavaScript 中,Number 类型可以表示的最大整数为 2^53-1,超过这个范围的整数会失去精度。为了解决这个问题,ES6 引入了一种新的数据类型 BigInt,用于表示任意精度的整数

BigInt 是一种全新的数据类型,用于表示任意大小的整数,可以安全、可靠地进行数学计算。与 Number 类型不同,BigInt 没有固定的最大值,在理论上可以无限制地扩展。在语法上,BigInt 是以 n 结尾的整数字面量,例如 10n 或 12345678901234567890n。

BigInt 不支持与其他类型的混合运算,它只能与同为 BigInt 的值进行运算。在使用 BigInt 进行计算时,需要使用 BigInt 对象上提供的方法,例如 BigInt.prototype.add()、BigInt.prototype.multiply() 等,同时也支持 ES6 中新增的运算符 +n、-n、*n、/n 等。

需要注意的是,在 BigInt 和 Number 之间进行转换时会丢失精度,因此需要特别小心。可以使用 BigInt() 将 Number 类型转换为 BigInt 类型,但是转换时可能会丢失小数部分。而将一个 BigInt 转换为 Number 类型时,如果超出了 Number 的最大值,其结果会变成 Infinity。

总之,ES6 中的 BigInt 是一种新的数据类型,用于表示任意精度的整数。它提供了可靠、安全的数学计算,可以无限制地扩展。在使用时需要注意与其他类型和精度转换的问题。

在 ES6 中,引入了一种新的 “原始值” 数据类型 Symbol,用于表示独一无二的值。Symbol 值通过 Symbol( ) 函数生成,每个 Symbol 值都是唯一的,即使参数相同,也不相等。

通常情况下,Symbol 值可用于构建对象的属性名,可以避免属性名冲突和被意外覆写的风险。比如,你可以使用一个 Symbol 值作为对象的属性名,这样其他程序就无法轻易地访问这个属性:

let prop = Symbol('my_property');
let obj = {};
obj[prop] = 'foo';
console.log(obj[prop]); // 输出 'foo'
console.log(obj); // 输出 { [Symbol(my_property)]: 'foo' }

Symbol 值还可以与类似 Map、Set 等新的集合类型结合使用,越来越多的 JavaScript 库和框架也开始使用 Symbol 来实现特定的功能,例如库的全局唯一标识、ES6 迭代器协议等。

此外,ES6 标准还提供了一些 Symbol 内置属性,其中包括:Symbol.toPrimitive、Symbol.toStringTag 等。这些内置属性都是以 Symbol 值为键的属性,用于控制对象的行为或自定义对象的字符串输出方式。

需要注意的是,Symbol 类型的使用也有一些限制,例如无法使用 typeof 运算符检测 Symbol 类型、无法用于 JSON 序列化等。

在实际开发中,Symbol 值的应用场景很多,可以用来创建私有属性、创建需求唯一性的键值、创建迭代器等。虽然它并不是一种全新的数据类型,但它的引入大大丰富了 JavaScript 的语法和特性。

2️⃣复杂数据类型(对象)

  • 数组(Array)
  • 函数(Function)
  • 正则表达式(RegExp)
  • 对象(Object)
  • 日期(Date)

这些复杂数据类型与简单数据类型(Number、String、Boolean、Null 和 Undefined)相对应,它们可以包含更多的信息和更复杂的结构。


2.字面量

3.检索(获取值)与更新(修改值)

.语法以及[ ]语法

在 JavaScript 中,方括号语法 [ ] 用于访问对象的属性和数组的元素。其语法形式为 object[property] 或 array[index],其中 object 是一个对象,property 是一个字符串类型的属性名,array 是一个数组,index 是一个整数类型的索引值。

使用方括号语法可以访问对象的动态属性,也可以访问数组的动态索引。比如:

const obj = {name: '张三'};
console.log(obj['name']); // 输出 '张三'

const arr = ['a', 'b', 'c'];
console.log(arr[0]); // 输出 'a'

需要注意的是,在使用方括号语法访问对象属性时,如果属性名中包含特殊字符(如点号  '.' ),则必须使用方括号语法;而使用点号语法 . 只能访问常规的属性名。比如:

const obj = {'my-name': '张三'};
console.log(obj['my-name']); // 输出 '张三'
console.log(obj.my-name); // 报错:SyntaxError: Unexpected identifier

此外,方括号语法还可以用于访问 ES6 中新加入的数据类型 Map、Set 中的成员。对于 Map 类型,方括号语法可以使用该 Map 的键作为属性名来访问其值;对于 Set 类型,则可以直接通过索引值来访问其成员。比如:

const map = new Map();
map.set('name', '张三');
console.log(map['name']); // undefined
console.log(map.get('name')); // 输出 '张三'

const set = new Set([1, 2, 3]);
console.log(set[0]); // undefined
console.log([...set][0]); // 输出 1

总之,方括号语法 [ ] 是 JavaScript 中一种常用的语法形式,可以访问对象属性、数组元素以及新的数据类型 Map、Set 中的成员。需要注意使用时的区别和注意事项。


4.反射

1️⃣typeof

  • undefined
  • boolean
  • number
  • bigint
  • string
  • symbol
  • function
  • object

2️⃣hasOwnProperty

true || false

在 JavaScript 中,反射(reflection)是一种运行时操作,允许程序员在运行时获取和修改对象的属性和方法

具体来说,JavaScript 反射提供了一些方法和属性,可以用于实现以下功能:

  • 检查对象是否具有指定的属性或方法:hasOwnProperty、in、instanceof、typeof
  • 获取对象的所有属性名或方法名:Object.keys、Object.getOwnPropertyNames、Object.getOwnPropertySymbols、Reflect.ownKeys
  • 获取或设置对象的属性值或方法:obj[prop]、obj[prop] = value、Object.defineProperty、Reflect.get、Reflect.set
  • 增加或删除对象的属性或方法:Object.create、Object.assign、delete、Object.freeze、Object.seal、Reflect.construct、Reflect.deleteProperty、Reflect.defineProperty

除了以上的方法和属性外,JavaScript 还支持一种比较特殊的反射方法 eval(),它可以动态执行字符串形式的代码。不过,在实际开发中,应该尽可能避免使用 eval(),因为它会带来安全性、可读性和性能等方面的问题。

总之,反射是 JavaScript 中一种非常强大和灵活的特性,它可以帮助程序员在运行时动态地获取和修改对象的属性和方法,从而实现更加动态和灵活的编程方式。当需要实现类似拦截器、代理等高级功能时,反射也是一种非常有用的技术。

5.枚举

forIn 利用反射的hasOwnProperty 来判断当前的属性是否是对象自身的属性

6.删除

delete:delete obj.key


③🌟函数 

精华:所谓编程,就是将一组需求分解成一组函数与数据结构的技能

1.函数对象
函数就是对象
函数拥有 “调用” 属性,可被 调用

1️⃣函数
函数(Function)是 JavaScript 中的基本组件之一,可以看作是一段可重复使用的代码块,可以接受输入参数,执行特定的操作,然后返回结果。在 JavaScript 中,函数本身也是一个对象,它可以赋值给一个变量,作为其他对象的属性或方法,或者作为参数传递给另一个函数。

2️⃣对象
对象(Object)是 JavaScript 中的另一个基本组件,可以看作是属性(property)的集合,每个属性都由一个键值对(key-value pair)组成。在 JavaScript 中,几乎所有的东西都可以被看作是对象,包括数字、字符串、数组等等。对象可以通过字面量、构造函数或 Object.create() 方法来创建,可以动态地添加、修改、删除属性和方法,还可以与其他对象进行交互和传递。

3️⃣函数对象
函数对象指的是由函数创建的对象,它们具有函数的所有特性,同时也是对象,可以拥有自己的属性和方法。在 JavaScript 中,所有的函数都是函数对象,即使是匿名函数、箭头函数等。函数对象可以使用 new 操作符来创建实例,也可以像普通对象一样添加、修改、删除属性和方法。

函数可以看作是一种可重复使用的代码块,对象可以看作是属性的集合,函数对象则是由函数创建的具有函数和对象的双重特性的对象。需要根据实际情况选择合适的类型来进行编程。

2.函数字面量

  • 保留字: function
  • 函数名:name(可省略)
  • 参数:(p1,p2....)
  • 语句:[代码块]

在 JavaScript 中,函数字面量(Function literal)是一种以函数形式来表示的常量值。它通常由 function 关键字、可选参数列表、代码块组成,例如:

function add(x, y) {
  return x + y;
}

上述代码中,add 就是一个函数字面量。它以 function 关键字开始,后面跟着函数名 add 和参数列表 (x, y),再用大括号 { } 表示函数体,用 return 语句返回计算结果。

函数字面量可以赋值给变量或对象属性,也可以作为参数传递给其他函数。例如:

var sum = function(x, y) {
  return x + y;
};

var person = {
  name: "Alice",
  greet: function() {
    console.log("Hello, my name is " + this.name);
  }
};

function doSomething(fn) {
  console.log("The result is " + fn(1, 2));
}

doSomething(sum); // 输出 The result is 3
person.greet();   // 输出 Hello, my name is Alice

上述代码中,sum 和 person.greet 都是函数字面量,分别被赋值给变量和对象属性。doSomething 函数接受一个函数类型的参数 fn,并在内部调用该函数。通过这些例子可以看出,函数字面量在 JavaScript 中有着广泛的应用和重要的地位。

因此函数字面量是 JavaScript 中一种常见的以函数形式来表示的常量值,它具有可重复使用、可以作为参数传递、可以赋值给变量或属性等特性,是实现动态编程和高级功能的基础。

实例
命名函数 - function f(a, b){ ...}
匿名函数 - const f= function (a, b) { ...}

命名函数具有可读性好、可重复使用、调试方便等优点,适用于需要多次调用的情况;

匿名函数则适用于只需要一次使用、或者作为其他函数的参数传递等场景,具有更加灵活和动态的特性。


3.调用

(1)函数可以调用函数:暂停当前函数执行,传递控制权和参数给新函数

(2)附加参数  调用方Il 指定值

1️⃣this:值取决于调用的模式

  • 方法调用模式
  • 函数调用模式
  • 构造器调用模式
  • apply调用模式
    • apply
    • call
    • bind

2️⃣arguments:得到所有实际参数

在 JavaScript 中,arguments 是一个内置的数组对象,它表示函数调用时传递给函数的所有参数,包括命名参数和未命名参数(即使用了 arguments 关键字定义的参数)。arguments 对象可以在函数内部通过名称引用,也可以像数组一样通过下标访问。

arguments 对象具有以下常用属性和方法:

  1. arguments.length:返回传递给函数的参数数量。
  2. arguments[index]:通过下标访问传递给函数的第 index+1 个参数。
  3. arguments.callee:指向当前正在执行的函数本身,可用于递归调用函数或匿名函数的自我执行。
  4. arguments.caller:指向调用当前函数的函数,如没有调用者则为 null,该属性已被弃用,请尽量避免使用。

另外,由于 arguments 对象是类数组对象(Array-like object),因此它还具有一些数组的特性,比如 Array.prototype.slice.call(arguments) 可以将 arguments 对象转换为真正的数组,从而可以使用数组的各种方法。

例如,下面的代码定义了一个函数 sum,它可以计算任意数量的数字的总和:

function sum() {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

console.log(sum(1, 2, 3)); // 输出 6
console.log(sum(4, 5));    // 输出 9
console.log(sum(6));       // 输出 6
console.log(sum());        // 输出 0

上述代码中,sum 函数没有定义任何参数,但是内部可以通过 arguments 对象访问到传递给函数的所有参数,并使用循环计算它们的总和。由于 arguments 对象是类数组对象,所以可以通过 arguments.length 属性获取传递给函数的参数数量,然后使用下标访问 arguments 对象的元素获取各个参数的值。

因此arguments 是 JavaScript 中一个内置的数组对象,代表函数调用时传递给函数的所有参数。通过 arguments 对象可以访问传入基于函数的参数,也可以像数组一样使用类似 length 的属性或 slice 等方法进行处理。

在 JavaScript 中,slice() 是数组对象的一个方法,用于从数组中提取一部分元素创建一个新数组,并返回这个新数组。slice() 方法接受两个参数,起始索引(包括)和终止索引(不包括),如果省略第二个参数,则提取从起始索引到数组末尾的所有元素。

slice() 方法不会修改原始数组,而是返回一个新数组,因此可以链式调用多个数组方法。slice() 方法提取的元素包括起始索引对应的元素,但不包括终止索引对应的元素。如果起始索引或终止索引为负数,表示从末尾开始计算的偏移量,例如 -1 表示倒数第一个元素。

下面是 slice() 方法的语法和示例代码:

Syntax: array.slice(startIndex, endIndex)

Example:
var fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
var citrus = fruits.slice(1, 3);  // 提取 'banana' 和 'cherry'
var berries = fruits.slice(3);    // 提取 'date' 和 'elderberry'
var firstTwo = fruits.slice(0, 2) // 提取 'apple' 和 'banana'
var lastTwo = fruits.slice(-2);   // 提取 'date' 和 'elderberry'

上面的代码中,fruits 是一个有 5 个元素的数组。使用 slice() 方法,可以根据起始和终止索引提取不同的元素组成新数组。例如,citrus 数组包含了原数组 fruits 中从索引 1('banana')开始,到索引 3(不包括)结束的所有元素,即 'banana' 和 'cherry';而 berries 数组则包含了从索引 3('date')开始到末尾的所有元素 'date' 和 'elderberry'。

⭕注意:slice() 方法虽然不会修改原始数组,但它返回的新数组和原始数组共享同样的元素对象。如果对原始数组进行了修改,那么对应的元素在新数组中也会发生变化


4.构造器调用模式

  1. JavaScript是一门基于原型继承的语言  这意味着: 对象可以直接从其他对象中继承属性
  2. 构造器本质是一个<函数>
  3. 通过 new 调用(不通过小括号的形式直接调用)
  4. 约定 首字母应该大写

5.apply调用模式:改变 this 指向

在 JavaScript 中,可以使用 apply() 方法来调用一个函数,并指定一个特定的上下文和一组参数。这种调用方式被称为 "apply 调用"。

apply() 方法接受两个参数,第一个参数是要绑定到函数上下文的对象(通常是 this 关键字),第二个参数是一个数组或者类数组对象,用于指定函数的参数。被调用的函数会使用这些参数来执行自己的逻辑。

使用 apply() 方法可以灵活地改变函数执行时的上下文。例如,当需要在一个对象的上下文中调用一个函数时,可以使用 apply() 方法将该对象绑定到函数的上下文中,从而访问该对象的属性和方法。此外,还可以通过 apply() 方法来实现参数的扩展和收缩,以及将类数组对象转换为真正的数组。

6.参数:arguments 伪数组(得到所有实际参数)

7.返回

  1. 总会返回一个值,默认 undefined
  2. return 请句可以是函数提前返回,并终止执行
  3. 配合new 使用,则返回 this(构造器调用模式)

8.异常:throw 语句会中断函数的执行

在 JavaScript 中,异常(Exception)是指程序运行时发生的错误,例如语法错误、类型错误等。当程序运行到发生异常的代码时,JavaScript 引擎会将控制权交给异常处理器,如果没有正确地处理异常,程序就会停止执行并报错。

为了捕获异常并正确地处理它们,JavaScript 提供了一些异常处理机制,其中抛出异常(throw)是其中之一。抛出异常表示在程序中手动创建一个异常对象,并将其传递给异常处理器进行处理。异常对象通常包含了异常的信息,例如异常类型、异常描述、调用栈信息等。

在 JavaScript 中,可以使用 throw 语句来抛出一个异常,语法如下:

throw expression;

其中,expression 表示需要抛出的异常对象或者异常表达式。抛出异常的过程会立即终止当前代码块的执行,并将控制权交给上级代码块的异常处理器进行处理。如果没有合适的异常处理器来处理该异常,程序就会停止执行并报错。

下面是一个抛出异常的示例代码:

function divide(a, b) {
  if (b === 0) {
    throw new Error("除数不能为零");
  }
  return a / b;
}

try {
  var result = divide(10, 0);
  console.log(result);
} catch (e) {
  console.error(e);
}

上述代码中,我们定义了一个 divide() 函数,用于计算两个数相除的结果。在函数中,我们判断了除数是否为零,如果是,则抛出一个异常对象,其中包含异常信息 "除数不能为零"。在 try...catch 语句块中,我们调用 divide() 函数,由于除数为零,会抛出一个异常,然后被 catch 语句块捕获并处理,输出异常信息到控制台。

抛出异常通常用于告知上级代码块当前代码无法继续执行,并提供异常信息以便上级代码块进行处理。合理使用异常处理机制可以帮助我们编写更加健壮和可靠的 JavaScript 代码。

9.扩充类型的功能:基于原型继承 Function.prototype.xxx

10.递归:

  • 定义:直接或间接调用自身的函数
  • 场景:递归把一个复杂问题分解为一组相似的子问题每一个都用一个寻常解去解决  例:汉诺塔游戏

11.作用域

  • 不支持块级作用域   ⭕注意: 文中所说为 ES6 之前
  • 函数作用域

12.闭包

内部函数可以访问定义他们的外部函数的参数和变量(可以访问其它函数作用域中变量的函数)

function a(){
    const name ='张三'

    // 闭包函数
    return function b() {
        return name
    }
}

console.log(a()()); // 张三

13.回调:函数可以作为参数进行回调使用

在 JavaScript 中,回调(Callback)指的是将一个函数作为参数传递给另一个函数,并在特定事件发生或者异步操作完成后,由该函数来调用传入的函数。回调机制往往用于处理异步操作的结果,例如网络请求、文件读写、定时器等。

使用回调函数可以使代码更加灵活和可扩展,避免了阻塞式调用的问题。通过将回调函数传递给异步操作,我们可以在异步操作结束后立即获取到结果并进行其他操作,而不必等待异步操作执行完毕。

14.模块:

  • 产生:使用函数和闭包来构造模块
  • 定义:模块是一个提供接口却隐藏状态与实现的函数或对象
  • 优点:通过使用函数产生模块,几乎可以完全摒弃全局变量的使用,从而缓解这个JavaScript 的最为糟糕的特性之一所带来的的影响
    • Let name ='张三' // 时 name 为全局变量,可以被任意修改
      function a (){
          // 此时 name 为函数作用域变量
          // 通过 const b = a() 得到 b 函数,然后进行调用
          // name 不可以被外界修改
          Let name ='张三'
          return function b () {
      
              return name
          }
      }

15.级联:链式调用

JavaScript 中的级联(Cascading)指的是在某个元素上设置样式规则时,如果该元素内部还有子元素,则该规则会自动应用到子元素上。这种规则的传递方式就像水滴从上方落下,沿着层层递进的路径慢慢扩散开来,因此也被称为“级联”。

在 CSS 中,级联是通过选择器优先级和继承机制实现的。在 JavaScript 中,则可以使用 DOM API 操作元素样式来实现级联。

⭕注意:在编写 JavaScript 代码时,应当尽量减少样式规则的使用,避免出现过多的层叠和嵌套,以提高代码的可读性和可维护性。同时,也应当避免在 JavaScript 中频繁操作元素样式,以减少页面重绘和重排,提高页面性能。

16.柯里化

把函数与传递给它的参数相结合,产生一个新的函数

这与我们的普遍记忆不同,我们的普遍记忆为: 柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a,b,c)转换为可调用的 f(a)(b)(c) 。


记忆:函数可以将先前操作的结果记录在某个对象里从而避免无调的重复运算。


④继承 

精华:JavaScript 是弱类型的语言,提供了多种继承的模式,而非传统的类继承

注意: ES6之后提供了类继承 class 的<语法糖>模式

ES6 中引入了 class 语法,用于声明一个类和创建对象。相对于传统的基于原型的对象创建方式,class 语法更加直观和易于理解,也更符合面向对象编程(OOP)的思想。

使用 class 语法,我们可以定义一个类,并在其中定义构造函数、实例方法、静态方法等等属性和方法。下面是一个简单的 class 示例:

class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  say() {
    console.log(`I'm ${this.name}, ${this.age} years old`);
  }
  
  static info() {
    console.log('This is an animal class');
  }
}

var dog = new Animal('dog', 5);
dog.say(); // I'm dog, 5 years old

Animal.info(); // This is an animal class

上述代码中,我们定义了一个 Animal 类,其中包含构造函数、实例方法 say() 和静态方法 info()。在构造函数中,我们初始化了 name 和 age 两个成员变量;在 say() 方法中,我们使用模板字符串输出了对象的属性;在 info() 方法中,我们输出了一个静态信息。

接着,我们使用 new 关键字创建了一个 Animal 对象,并调用了 say() 方法,输出了打招呼的信息;同时,我们也直接调用了 info() 静态方法,输出了静态信息。

⭕注意:在 class 语法中,使用 constructor 关键字定义构造函数,而不需要手动创建对象原型并设置构造函数;同时,在实例方法和静态方法中,我们可以使用 this 和 static 关键字来访问对象和类本身。

因此ES6 中的 class 语法为 JavaScript 提供了一种更加直观、易于理解的面向对象编程方式,使得代码更加组织化和可维护。通过定义类、构造函数和各种方法,我们可以更加方便地创建对象并处理数据,从而实现复杂的业务逻辑。

而在 ES6 之前,JavaScript 中创建对象通常通过手动创建对象原型和设置构造函数来实现。具体的操作步骤如下:

1.使用 Object.create() 方法手动创建一个对象原型,例如:

var animalPrototype = {
  say: function() {
    console.log('I am an animal');
  }
};

使用 Object.create() 方法创建了一个 animalPrototype 对象,其中定义了一个 say() 方法,用于输出一段文本信息。

2.定义一个构造函数,并将其原型对象设置为上一步创建的对象原型,例如:

function Animal(name, age) {
  this.name = name;
  this.age = age;
}

Animal.prototype = animalPrototype;

3.使用 new 关键字调用构造函数,创建 Animal 对象,并调用其方法,例如:

var dog = new Animal('dog', 5);
dog.say(); // I am an animal

在手动创建对象原型和设置构造函数的过程中,我们需要手动进行原型链的管理和维护,包括原型对象的创建和继承关系的设置等等。相比于 ES6 中的 class 语法,这种方式更加繁琐和复杂,也不够直观和易于理解。

1.伪类(构造函数)
JavaScript 不存在类的概念,而是以伪类 (首字母大写的普通函数)的形式进行呈现

2.对象说明符
当一个函数接收多个参数时,记住参数的顺序非常困难

利用对象的特性,将多个参数合并为一个。

var myObject = maker(f, l, m, c, s);
//所以,于其这样写
var myObject= maker({
    first: f,
    middle: m,
    last: 1,
    state: s,
    city: c
});
//不如,这样写

3.原型

JavaScript 中基于原型进行继承: 一个新对象可以继承一个旧对象的属性

差异化继承

const person = {
    name:'张三'
    age: 18
}
const newPerson = Object.create(person)
newPerson.name ='李四'

在 JavaScript 中,每个对象都有一个原型(prototype)属性,它指向另一个对象,这个对象即为当前对象的原型。原型是 JavaScript 实现继承的基础,它实现了对象之间的共享和继承。

当访问一个对象的某个属性或方法时,如果该对象本身不存在这个属性或方法,JavaScript 引擎会沿着原型链往上查找,直到找到该属性或方法为止。这意味着通过原型,我们可以将一个对象的属性和方法共享给所有它的子对象。

JavaScript 中的原型实现方式非常简单,每个函数都有一个 prototype 属性,它指向一个普通对象,这个对象就是该函数的原型。例如:

function Animal(name, age) {
  this.name = name;
  this.age = age;
}

Animal.prototype.say = function() {
  console.log(`I'm ${this.name}, ${this.age} years old`);
};

var animal = new Animal('dog', 3);
animal.say(); // I'm dog, 3 years old

其中,Animal.prototype 是一个普通对象,它包含一个名为 say 的方法。当使用 new 关键字创建 Animal 对象时,JavaScript 引擎会将名称为 Animal.prototype 的对象作为新对象的原型,从而使得新创建的 animal 对象可以通过原型链继承来自 Animal.prototype 对象的方法(比如 say() 方法)和属性(比如 toString() 方法、valueOf() 方法等)。

JavaScript 中的原型机制使得对象之间可以通过共享来实现继承和多态,从而提高代码的可维护性、扩展性和重用性。

差异化继承

const person = {
    name:'张三',
    age: 18
}
const newPerson = Object.create(person)
newPerson.name ='李四'

4.函数化

JavaScript 中继承的模式会导致没有私有变量  比如:在上面的例子中,person 无法具备私有变量

应用模块模式

//这里是一个函数化构造器的伪代码模板(加粗的文本表示强调):
var constructor = function (spec, my) {
    var that,其他的私有实例变量;
    my = my || {};
    把共享的变量和画数添加到 my 中
    that = 一个新对象
    添加给 that 的特权方法
    return that;
};

5.部件  对象的属性或方法

const eventuality = function (that) {
    const reigstry = {}
    //部件1
    that.fire = function (){
        console.log('fire');
        return this
    }

    // 部件2
    that.onk= function () {
        console. log('on');
        return this
    }
    return that
}

const person = {
    name:'张三'
}

eventuality(person)


⑤数组

(1)定义

  • 传统数组:数组是一段线性分配的内存,它通过整数计算偏移并访问其中的元素
  • JS数组:
    • JavaScript中并不存在数组一样的数据结构
    • JavaScript提供了类数组特性的对象  所以:在JavaScript 中数组本质是对象

(2)数组字面量  const arr =[, 2, 3]
(3)长度  length 属性
(4)删除

1️⃣数组本质是对象,所以可以通过 delete 删除  但是这样会留下<空洞>

2️⃣利用 splice 删除

(5)枚举

1️⃣for...in...  无法保证顺序

2️⃣常规 for 循环

(6)易混淆的地方

1️⃣对象与数组的定义混淆

当属性名是小而连续的整数时,应该定义数组。否则,都定义对象

2️⃣区别数组与对象

typeof 不可以用

var is_arnay = function (value){
    return Object.prototype.toString.apply(value) === '[object Array]';
}

我们需要知道,除了书中的这两种之外,还有另外一种形式来进行区分: instanceof

(7)方法:JavaScript 提供了一套数组可用的方法,这些方法都被存放到了Array.prototype 中

(8)指定初始值:

JavaScript 的数组通常不会预设值,如果通过[ ]得到一个新数组,它将是空的。

var matrix = [
    [0,1,2],
    [3,4,5],
    [6,7,8]
];

matrix[2][1]//7

JavaScript 没有多维数组,但是它支持<元素为数组的数组>



⑥方法

(1)定义:当一个函数被保存为对象的一个属性时

(2)四大类:

  • Array
  • Function
  • Object
  • String

1️⃣Array 类
Array 类是用于创建数组对象的类,它提供了很多内置的方法,可以对数组进行增、删、改、查等操作。常用的方法包括 push()、pop()、shift()、unshift()、slice()、splice()、concat()、join()、map()、filter() 等。

2️⃣Function 类
Function 类是用于创建函数对象的类,它提供了很多方法和属性,可以对函数进行各种操作。比如可以通过 bind() 方法来改变函数的 this 指向;可以使用 call() 和 apply() 方法来调用函数并传入参数;还可以使用 toString() 方法来获取函数的源代码等。

3️⃣Object 类
Object 类是 JavaScript 中所有对象的基类,它提供了一些通用的方法和属性,可以对对象进行访问和操作。比如可以通过 hasOwnProperty() 方法来判断一个对象是否具有某个属性;可以使用 Object.keys() 方法来获取对象的所有属性键名;还可以使用 Object.create() 方法和继承来创建新的对象等。

4️⃣String 类
String 类是用于创建字符串对象的类,它也提供了很多内置的方法,可以对字符串进行各种操作。比如可以使用 concat() 方法来连接两个字符串;可以使用 indexOf() 和 lastIndexOf() 方法来查找字符串中特定的字符或子串;还可以使用 slice() 和 substr() 方法来截取子串等。


其他

①正则表达式

并非JavaScript 特性,而是一门语言的语法规范
MDN 文档

正则表达式(Regular Expression,简称 RegEx)是一种用于匹配字符串的模式。它由一个或多个字符、元字符和限定符组成,用来描述文本中的一种或多种匹配模式。

在 JavaScript 中,可以使用内置的正则表达式对象 RegExp 或使用字面量语法定义正则表达式。比如:

var pattern1 = /hello/;
var pattern2 = new RegExp('world');

正则表达式中的元字符包括:

  1. 字符类:用于匹配单个字符,比如 . 表示任意字符,[abc] 表示字符 a、b 或 c。
  2. 重复类:用于指定字符或子表达式的出现次数,比如 * 表示零次或多次,+ 表示一次或多次,? 表示零次或一次。
  3. 定位类:用于指定匹配的位置,比如 ^ 表示匹配字符串开头,$ 表示匹配字符串结尾。
  4. 分组类:用于分组并捕获匹配结果,以便后续处理或替换。

在 JavaScript 中,可以使用正则表达式进行字符串的查找、替换、验证等操作。常用的方法包括 test()、exec()、match()、replace() 等。

②代码风格

作者对JavaScript 语法规范的理解,但并不完全适合于国内环境

③优美的特性

我们喜欢简单,追求简洁易用,但是当产品缺乏这种特性时,就需要自己去创造它。


附录

 ①毒瘤

全局变量:中大型项目中,全局变量可以被任意修改,会使得程序的行为变得极度复杂

作用域:无块级作用域  注意: ES6之前

自动插入分号:不合时宜的自动插入

unicode:unicode 把一对字符视为一个单一的字符,而JavaScript认为一对字符是两个不同的字符

typeof:typeof的返回总是很“奇怪”

typeof 操作符的返回结果可能包括以下几种:

  • "undefined":表示未定义的值,通常是指变量已声明但未赋值或属性未定义。
  • "string":表示字符串类型的值。
  • "number":表示数字类型的值,包括整数、浮点数、无穷大和 NaN 等。
  • "boolean":表示布尔类型的值,即 true 和 false。
  • "object":表示对象类型的值,包括普通对象、数组、函数和 null 等。
  • "function":表示函数类型的值。

其中,需要特别注意的是:

  • typeof null 的返回值是 "object",这是由于历史原因造成的错误,实际上 null 是一个空对象指针,应该返回 "null" 才更为合理。
  • 对于数组、函数和正则表达式等引用类型的值,typeof 操作符的返回值都是 "object",这并不能明确表达它们的类型,需要使用其他方式进行判断。

综上所述,虽然 typeof 操作符是 JavaScript 中很常用的一个操作符,但是其返回值的语义不够清晰,容易引起混淆。因此,在实际开发中,建议使用更为准确和直观的方式来获取值的类型信息,比如 instanceof、Object.prototype.toString.call() 等。

parselnt:parseInt("16")与 parseInt("16 tons")产生相同的结果。遇到非数字时会停止解析,而不是抛出一个错误。

+ :+ 既可以让数字相加,也可以链接字符串

浮点数:
因此0.1+0.2不等于0.3
进制的浮点数不能正确的处理十进制的小数

NaN:NaN 表示不是一个数字,同时它的一些运算也会让人感到奇怪

typeof NaN === 'number' // true
NaN === NaN  //false
NaN !==NaN  //true

伪数组:JavaScript中没有真正的数组,却又存在伪数组的概念

假值:逻辑运算中被判断为 false 的值

类型
Number
NaN(非数字)Number
' '(空字符串)
String
falseBoolean
nullObject
undefinedUndefined

hasOwnProperty
another stooge.hasOwnProperty = nul1;
hasOwnProperty 是一个方法而不是运算符,所
以在任何对象中,他可以被替换掉

对象:JavaScript 中的对象永远不会是真的空对象,因为它们可以从原型链中取得成员属性
 

JSLint  已被 ESLint 替代,所以这里不再表述
语法图
JSON


②糟粕

  1. == 不判断类型,所以尽量不要使用它;
  2. with   改变一段语句的作用域链;
  3. eval:传递字符串给JavaScript 编译器,会使得代码更加难以阅读;
  4. continue:作者发现:移除 continue 之后,性能会得到改;
  5. switch 穿越:必须明确中断 case,否则会穿越到下一个;
  6. 缺少块的语句: ES6 之后已经可以提供块作用域了;
  7. ++--:这两个运算符鼓励了一种不够谨慎的编程风格;
  8. 位运算符:JavaScript 执行环境一般不接触硬件,所以执行非常慢;
  9. function 语句对比 function 表达式(国内一般叫做:命名函数和匿名函数):多种定义方式让人困惑
  10. 类型的包装对象:应该从来没有使用过new Boolean(false)。所以作者认为:这是完全没有必要,并且令人困惑的语法。

总结:

①优点: 

  • 体量小
  • 初、中级工程师可以通过它快速理清JavaScript 语言精粹 

②缺点:

  • 内容偏老,针对 ES6之前的语法
  • 直译
  • 书中包含大量的作者主观表述,可能并不一定那么精准,大家需要客观看待。

比如: 一些糟粕并不一定是完全绝对的,善加利用可能会带来意料之外的效果

比如: vue 中就大量的使用到了“糟粕”。

即该书着重介绍了 JavaScript 的核心概念和精华部分,让读者能够深入理解 JavaScript 的设计原理和语言特性。书中讲解了函数、对象、原型、作用域、闭包、正则表达式等诸多关键概念,并带给读者很多实用的编码技巧和最佳实践。但由于该书的篇幅较短,部分内容可能不太详细。此外,随着 JavaScript 语言的不断演进和发展,书中的部分内容已经有些过时,需要及时更新。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值