前言:
《JavaScript 权威指南》(JavaScript:The Definitive Guide)是一本由David Flanagan所著的JavaScript领域的经典书籍,它是学习和开发JavaScript应用不可或缺的参考书之一。该书分为两个部分,第一部分讲解了JavaScript语言的核心概念、基础语法、数据类型、函数、对象、数组等内容。第二部分则介绍了JavaScript在Web浏览器中的应用,包括DOM操作、事件处理、表单验证、Ajax等内容。《JavaScript 权威指南》凝结了Flanagan多年在JavaScript领域的经验和教学经历,内容深入浅出地讲解了JavaScript的各种特性和用法,既适合初学者入门,也适合进阶开发者深入学习。书中还提供了大量的示例代码、练习题和答案,有助于读者更好地理解和掌握JavaScript的知识点,同时也方便读者自行实践和深入探索。
此外,该书也会不断更新,跟随JavaScript的最新发展并加入新特性,使得它始终保持着权威性和实用性,成为了JavaScript领域的经典之作。
1️⃣内容:
- JS 基础API
- 浏览器 API
- Node.js API
2️⃣特点(全面)
- JavaScript 简介
- 前端工程化 (ESLint、Prettier)
3️⃣适用人群:
- JavaScript 初学者
- 有一定经验的开发者
第一章: JavaScript 简介
1.JavaScript 与 ECMAScript 的关系
ECMAScript 是JavaScript 的语言标准。
- ES5 对应 ECMAScript 第五版
- ES6 对应 ES2015
- ES7 对应 ES2016
2.JavaScript的宿主环境都有什么
- 游览器:最常见的 JavaScript 宿主环境,支持通过 HTML、CSS 和 JavaScript 创建和运行 Web 应用程序,如 Chrome、Firefox、Safari、Edge 等。
- node:一个基于 Chrome V8 引擎的 JavaScript 运行环境,主要用于构建高性能、可伸缩性的网络应用程序,如服务器端应用程序、命令行工具等。
3.在哪里书写 JavaScript
①浏览器控制台
②编辑器
第二章: 词法结构
1.注释的三种方式
①单行注释 //注释
②多行注释
/*
多行注释
*/
/**
* 注释内容
*/
第二种注释方式标记在方法上时,在调用方法时会有相对应的提示。
2.省略分号的潜在问题
1️⃣ ; 分号不是必须的
const name ='张三'
console.log(name)
2️⃣防御性分号
let x = 0;
[x, x + 1, x + 2].forEach()
//初始代码
let x = (0)[(x,x + 1,x + 2)].forEach()
//编译时
//Uncaught ReferenceError: x is not defined at <anonymous>:1:14
第三章: 类型、值和变量
类型 -> 表达式 -> 语句 -> 对象/数组 -> 函数 -> 类 -> 模块
1.基本数据类型
(1)数值:
1️⃣分类:
- 整数
- 浮点数 (小数)
2️⃣问题:
- 大数字问题通过 BigInt 处理
- 精度问题三种处理方案
(2)null、undefined
- null: 空值
- undefined: 没有值
(3)Symbol
console.log(Symbol('hello') == Symbol('hello')); // false
2.原始值与引用类型
1️⃣原始值 -> 基本数据类型
2️⃣引用类型 -> 复杂数据类型
引用类型(也叫对象类型)包括对象、数组、函数等。
引用类型的值是由多个值组成的对象,可以拥有属性和方法,其值在内存中以引用存储。这意味着当一个变量被赋予引用类型的值时,实际上是把该值在内存中的地址赋值给变量,而不是在变量中直接存储该值的副本。
(1) 对象(Object):表示一组无序的属性的集合,每个属性包含一个名称和一个值
(2)数组(Array):表示一组有序的值的集合,可以通过索引访问每个值
(3)函数(Function):表示一段可执行的代码,可以重复利用
(4)还有日期(Date)、正则表达式(RegExp)等引用类型。这些引用类型都可以使用“new”关键字来创建一个新的实例
3.类型转换
1️⃣隐式转换
// 利用加号 (+),进行字符串隐式转换
console.log('a 的值为: '+ 1); // 数字 1 转化为字符串
// booLean 隐式转换
console.log(0 == false); // true (不判断类型)
console.log(0 === false); // false (判断类型)
// 数字的隐式转换
console.log('1'-0 ); // 1 (数值)
console.Log('1'- 0 +1); // 2 (数值)
2️⃣显示转换
console.log(parseInt('18'));// 显示转化为整数
console.log(parseFloat('3.1415')); // 显示转化为小数
第四章: 表达式与操作符
1.表达式
//主表达式
3.1415926
//函数表达式
fn()
//属性访问表达式
user.name
JS中任何一行代码都是一个表达式
2.复杂操作符
1️⃣ in :判断某个属性是否为指定对象的属性名
const user = {
name:'张三'
}
// 属性 in 对象
console.log('name' in user); // true
console.log('age' in user); // false
2️⃣ instanceof : 判断某个对象是否为另一个类的实例
const d = new Date()
// 实例对象 instanceof 类
console.log(d instanceof Date); // true
console.log(d instanceof Object); //true
console.log(d instanceof Array); //false
3️⃣ typeof : 返回一个任意值的结果
(1)固定的九类结果:
x | typeof x |
undefined | "undefined" |
null | "object" |
true 或 false | "boolean" |
任意数值或NaN | "number" |
任意BigInt | "bigint" |
任意字符串 | "symbol" |
任意函数 | "function" |
任意非函数对象 | "object" |
(2) 语法:
// typeof 任意值
console.log(typeof ' ');//string
console.log(typeof 3.14); // number
console.Log(typeof {}); // object
console.log(typeof []);// object
📜对比
(1)in 和 instanceof
- 相同点:都会返回 boolean 的值
- 不同点:in 属性是否属于对象;instanceof 对象是否属于类
(2)typeof :返回 string 类型的结果 ⭕注意: 针对和返回的结果都是 object
4️⃣ ? 条件式访问
(1)存在的问题:
const user = null
console.log(user.name); / TypeError
处理方法:
const user = null
if (user){
console.log(user.name);
} else {
console.log(undefined);
}
(2)作用:
const user = null
console.log(user?.name); // undefined
如果 ? 前的表达式为空值 (null ll undefined) 则会返回 undefined
5️⃣ ??先定义
(1)知识储备:
①假值
- undefined
- null
- 0
- “
- false
- NaN
②逻辑或
// || 逻辑或: 假值 都会被认为假
console.log(0 || 1); // 1
所有的假值都会被判定为 假 (但0可能因为有意义的值)
(2)??先定义操作符:
// ?? 先定义操作符: 只有 undefined 和 null 会被认为假
console.log(0 ? 1); // 0
console.log(undefined ?? 1); // 1
console.log(null ?? 1): // 1
只有 undefined 和 null 会被认定为 假
6️⃣ eval()
本质是一个函数,可以接收一个参数。(实际上是用来执行动态拼接的方法)
// 得到结果
console.log(eval(2 + 3)); // 5
// 声明了函数 fn
console.log(eval(" function fn () [ console.log('我是 fn') }"));
fn() // 我是 fn
7️⃣ delete
删除指定的对象属性或数组元素
const user = {
name: '张三'
}
// 从对象中删除 name 属性
delete user.name
console.log('name' in user); // false
const arr = [张三','李四',"王五']
// 从数组中删除 0 下标元素
delete arr[0]
console.log(arr[0]); // undefined
第五章: 语句
1.条件语句
- if 语句
- switch 语句
2.循环语句
- while 循环
- do/while 循环
- for 循环
- for/of 循环
- for/in 循环
const arr =['张三' ,'李四','王五']
const user = {
name:'张三'
}
// 正常循环,拿到 下标
for (const index in arr) {
console.log(index);
}
// 正常循环,拿到 vaLue 元素
for (const value of arr) {
console.log(value);
}
// 正常循环,拿到 key
for (const key in user) {
console.Log(key);
}
// TypeError: user is not iterable
for (const key of user) {
console.log(key);
}
'for/in’ 可以循环任意可枚举对象,而 'for/of' 只能循环可迭代对象
3.跳转语句
- break
- continue
- return
- yield
- throw : 抛出异常
function fn(n) { if (n <0){ throw new Error('n的值不能小于 0') } } fn(-1)
- try / catch / finally
function fn() { try { // try 中的代码出现异常会被捕获 JSON.parse('张三') } catch (err) { // 捕获异常之后,执行 catch console.log(err); // SyntaxError: Unexpected token '张',"张三" is not valid JSON } finally { // 无论是否捕获了异常,finally 总会执行 console.log('finally'); } } fn()
4.其他语句
- with 混淆指定代码块的作用域指向
const user = { name:'张三' } with (user) { // 使用 user 混淆作用域,这里的 name 会被理解为 user.nameconsole.Log(name); }
- debugger
- use strict
第六章:对象
1.测试属性
测试某一个名字是否是指定对象的一个属性名
- in 操作符 : 自有属性和继承属性
const user = name: '张三' } // 属性 in 对象 console.log('name' in user); // true console.log('age' in user); //false console.log('toString' in user); // true
- hasOwnProperty : 自由属性
const user = name:'张三' } // 0bject.prototype.hasOwnProperty() console.log(user.hasOwnProperty('name')); // true console.log(user.hasOwnProperty('toString')); // false
- propertylsEnumerable : 自有属性 并且 enumerable (可枚举)特性为 true
const user = name :"张三" age: 18 } // 利用 Object.defineProperty 修改 age 的可枚举特性 Object.defineProperty(user,'age',{ enumerable: false }) // 0bject.prototype.propertyIsEnumerable() console.log(user.propertyIsEnumerable('name')); // true console.log(user.propertyIsEnumerable('age')); // false console.log(user.propertyIsEnumerable('toString')); // false
2.枚举属性
1️⃣可枚举性
- 默认创建的属性都是可枚举的
- 通过 Object.defineProperty 可以修改指定属性的可枚举性
- 通过 propertylsEnumerable 方法,可以判断属性是否可枚举
2️⃣枚举对于循环的影响
const user{
name:'张三'
age: 18
}
// 利用 Object.defineProperty 修改 age 的可枚举特性
Object.defineProperty(user,'age',{
enumerable: false
})
for (const key in,user) {
console.Log(key); // 只打印 name
}
当一个属性不可枚举时,"for/in" 循环会忽略掉该属性
3️⃣其他方法
Object.keys():指定对象的可枚举属性
Object.getOwnPropertyNames():指定对象的所有自有属性(无论是否可枚举)
const user = {
name :'张三'
age: 18
}
// 利用 Object.defineProperty 修改 age 的可枚举特性
Object .defineProperty(user,'age',{
enumerable: false
}
console.log(Object.keys(user)); // ['name']
console.log(Object.getOwnPropertyNames(user)); // ['name','age']
3.扩展对象
1.作用:把一个对象的属性复制到另一个对象上
2.操作:
- Object.assign
- 扩展操作符
const user = {
name: '张三'
}
const info = {
token: 'xxx'
}
// 方式-: 0bject.assign 方法 (注意: Object.assign 返回的是第一个参数)
console.log(Object.assign(user, info)); //{name: '张三', token: 'xxx'}
console.log(user); // {name: 张三 ,token:xxx}
console.log(Object.assign(user,info) === user); // true
// 如果不想修改 user,可以使用这种方式合并
console.log(Object.assign({},user, info)); // {name:张三',token:'xxx'}
// 方式二: 扩展操作符 (推荐)
console.log(...user, ...info }); // {name :"张三", token: 'xxx'}
4.序列化对象
- JSON.stringify() 把对象变为 JSON 格式字符串
- JSON.parse() 把 JSON 格式字符串变为对象
// 对象 转化为 json
const user =
name:'张三'
}
console.log(JSON.stringify(user)); // {"name":"张三"}
// json 转化为 对象
const str ='{"name":"张三"}'
console.Log(JSON.parse(str)); // {name: '张三'}
第八章:函数
1.函数是JS中的一等公民
2.大纲:
如何定义函数 -> 如何调用函数 -> 函数的形参和实参 -> 命名空间 -> 闭包 -> 函数的属性、方法、构造函数 -> 函数式编程
3.闭包
(1)定义:JavaScript函数对象的内部状态不仅要包括函数代码,还要包括对函数定义所在作用域的引用。这种函数对象与作用域(即一组变量绑定)组合起来解析函数变量的机制,在计算机科学文献中被称作闭包 (closure)。
严格来讲,所有JavaScript函数都是闭包
(2)国内通俗解释:
可以访问其它函数作用域中变量的函数
(3)mdn:
闭包是一个函数以及其捆绑的周边环境状态的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在JavaScript 中,闭包会随着函数的创建而被同时创建
(4)最终解释:
- 所有JavaScript 函数都是闭包
- 闭包可以访问外部函数作用域中才有的变量
4.函数对象
(1)函数本质上是一个对象
- 方法 :apply、call、bind
- 属性 :prototype
(2)构造函数:
首字母大写的普通函数就是构造函数