JavaScript 基础
JS 基础
JavaScript 包含很多内容,如类、期约、迭代器、代理、客户端检测、事件、动画、表单、错误处理以及JSON等。
1. JavaScript 概念
完整的 Javascript 包含3部分:
核心(ECMAScript)
文档对象模型(DOM)
浏览器对象模型(BOM)
script 标签属性:
- async 立即开始下载脚本【外部脚本】
- charset 字符集
- crossorigin CORS 跨域资源共享
- defer 脚本可以延迟到文档完全被解析和显示之后再执行(最好只包含一个这样的脚本)【外部脚本】
- src 重要!!
- type 脚本类型 type=”text/javascript”
noscript 标签:满足以下两个条件,都会被浏览器渲染。否则不会渲染 noscript 标签里内容
- 不支持 JavaScript
- 禁用 JavaScript
1 |
|
注意:对不推迟执行的脚本,浏览器必须解释完位于<script>
元素中的代码,然后才能继续渲染页面
2. 语法基础
2.1 变量
标识符组成:(变量名建议:驼峰命名)
- 第一个字符必须是一个字母、下划线(_)或美元符号($)
- 标识符由字母、下划线、$或数字组成
1 | // 有效名称 : 合法名称 |
开启严格模式:==”use strict”==。对于不安全的活动将抛出错误
1 | function doSomething() { |
在 JavaScript 中建议 ==加分号(;)==,压缩代码不容易出现语法错误,在某些情况下可能会提升性能,因为解析器会尝试在合适的位置补上分号以纠正语法错误。
关键字如下:
break | do | in | typeof |
---|---|---|---|
case | else | instanceof | var |
catch | export | new | void |
class | extends | return | while |
const | finally | super | with |
continue | for | switch | yield |
debugger | function | this | enum |
default | if | throw | 等等 |
delete | import | try |
var 声明提升:都拉到函数作用域的顶部【let 声明的变量不会被提升,即必须先声明再使用,即“暂时性死区”】
1 | function foo() { |
let 声明的范围是块作用域,而 var 声明的范围是函数作用域。
✨小技巧:
建议使用 let 声明变量,如果变量确定不会发生变化,建议使用 const 声明变量。
全局声明时,let 声明变量不会成为 window 对象属性
1 | var name = "张三" |
总结:const 优先,let 次之
2.2 数据类型(7种)
6中简单数据类型(原始类型):
- Undefined(”undefined”)只有1个值 undefined
- Null(””)
- Boolean(”boolean”)
- Number(”number”)
- String(”string”)
- Symbol(符合)
还有复杂数据类型:Object(”object” 或 null)(键值对的集合)
确定变量类型: typeof 【操作符】,区分函数和其他对象
1 | let message = "some string"; |
✨小技巧:
声明变量时,建议初始化,避免不必要的错误
== 的使用:这个操作符会为了比较而转换它的操作数
1 | console.log(null == undefined); // true |
一般来讲,不必显示声明为 undefined,要使用 void(0)
不同类型与布尔值之间转换规则:if 等流控制语句会自动执行其他类型值到布尔值的转换(经常用!!)
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 非空字符串 | “”(空字符串) |
Number | 非零数值(无穷) | 0、NaN |
Object | 任意对象 | null |
Undefined | N/A(不存在) | undefined |
Number最大:Number.MAX_VALUE
Number最小:Number.MIN_VALUE
超出范围:Infinity 无穷 【Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 也可以获取正、负 Infinity。】
确定一个值是不是无穷大:isFinite 函数
NaN (非数值):console.log(0/0); // NaN
判断是否为非数值:isNaN
isNaN()可以用于测试对象。此时,首先会调用对象的 valueOf()方法,然后再确定返回的值是否可以转换为数值。如果不能,再调用 toString()方法,并测试其返回值
1 | console.log(isNaN(NaN)); // true |
将非数值转换为数值:Number()、parseInt()和 parseFloat()
Number函数转换规则:
- 布尔值 true为1
- 数值,直接返回
- null 返回0
- undefined 返回NaN
- 字符串【isNaN 为 true】
- 对象,调用 valueOf 方法,如果结果为 NaN,调用 toString() 方法
1 | let num1 = Number("Hello world!"); // NaN |
字符串转数字有专门的函数处理:parseInt和parseFloat
String 类型
字符字面量:
字面量 | 含义 |
---|---|
\n | 换行 |
\t | 制表 |
\b | 退格 |
\r | 回车 |
\f | 换页 |
\ \ | 反斜杠 |
\‘ | 单引号 |
\“ | 双引号 |
\` | 反引号 |
\xnn | \x41 等于 “A” |
\unnnn | \u03a3 等于字符”Σ” |
转换为字符串:toString()
模板字面量:由反引号括起来(123
),允许支持字符串插值(${})
模板字面量会保持反引号内部的空格
模板字面量:标签函数
1 | function simpleTag(strings, aValExpression, bValExpression, sumExpression) {} |
获取原始字符:.raw
为什么要获取原始字符:不要转义后的 © ,要 \u00A9
示例代码:
1 | function printRaw(strings) { |
Symbol 类型【了解,该内容属于进阶知识,可跳过】
是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
1 | let sym = Symbol(); |
凡是可以使用字符串或数值作为属性的地方,都可以使用符号
Symbol.asyncIterator:由 for-await-of 使用,异步迭代器API
1 | class Emitter { |
Symbol.hasInstance 由 instanchof 使用。确定一个对象实例的原型链上是否有原型。
1 | function Foo() {} |
重新定义原型:
1 | class Bar {} |
Symbol.isConcatSpreadable 了解即可
Symbol.iterator 使用 for-of 遍历
Symbol.match 正则表达式需要
Symbol.replace 替换字符。 String.prototype.replace()方法使用
Symbol.search 匹配正则表达式索引
Symbol.species 该函数作为创建派生对象的构造函数
Symbol.split 拆分字符串
Symbol.toPrimitive 将对象转换为相应的原始值
Symbol.toStringTag 默认字符串
Symbol.unscopables 了解,不深入探究
Object 类型
创建对象
1 | let o = new Object() |
每个Object都有的方法:
- constructor
- hasOwnProperty(属性名)
- isPrototypeof(object)
- propertyIsEnumerable(propertyName)
- toLocaleString
- toString
- valueOf
Object 是所有对象的基类,所以任何对象都有这些属性和方法。
BOM 和 DOM 可能会出现例外情况
2.3 操作符
操作符通常会调用 valueOf()和/或 toString()方法来取得可以计算的值。
一元操作符:
递增/递减操作符 ++/–
一元加/减,如 s1 = +s1;
位操作符
- 按位非 ~
- 按位与 &
- 按位或 |
- 按位异或 ^
- 左移 <<
- 有符号右移 >>
- 无符号右移 >>>
布尔操作符
逻辑非 !【同时使用两个叹号(!!),相当于调用了转型函
数 Boolean()】
1
2
3
4
5
6console.log(!false); // true
console.log(!"blue"); // false
console.log(!0); // true
console.log(!NaN); // true
console.log(!""); // true
console.log(!12345); // false逻辑与 &&
逻辑或 ||
乘性操作符
- 乘法 *
- 除法 /
- 取模 %
指数操作符 ** Math.pow()
关系操作符(大于>,等等)
相等操作符
- 等于(==)或不等于(!=)
- 全等(===)或不全等(
!==
)
条件操作符 flag ? true : false
赋值操作符 =
逗号操作符
1
let num1 = 1,num2 = 0
2.4 语句
if 语句
do-while语句
while 语句
for 语句
for-in 语句
for-of 语句
标签语句 常用于内部循环跳出外部循环 break start;
1
2
3start: for (let i = 0; i < count; i++) {
console.log(i);
}break 和 continue
with 语句 【不建议使用,严格模式报错】
1
2
3
4
5
6
7
8
9let qs = location.search.substring(1);
let hostName = location.hostname;
let url = location.href;
// 使用 with 简化
with(location) {
let qs = search.substring(1);
let hostName = hostname;
let url = href;
}switch 语句
2.5 函数(Function)
它属于引用类型
基本语法:
1 | function functionName(arg0, arg1,...,argN) { |
3. 变量、作用域与内存
3.1 变量
变量可以包含两种不同类型的数据:原始值和引用值
原始值:简单数据类型。(typeof有效),保存在栈上
引用值:多个值构成的对象。(instanceof 判断类型),保存在堆上。(引用值对象实际是指向对象的指针)
3.2 作用域
作用域链:各级上下文中的代码在访问变量和函数时的顺序。(更多资料可百度)
上下文是函数,其活动对象用作变量对象加入作用域链中。
对于过滤链举个简单例子方便理解:
1 | let color = "blue"; |
在该函数 changeColor 的作用域链中包含两个对象:
- arguments 自身变量对象【具体可百度】
- 全局上下文变量对象
作用域链增强: catch 语句 和 with 语句
作用域链中查找指定标识符,找到搜索结束,全局上下文仍然没有找到相应标识符,则其说明未定义。
3.3 垃圾回收(进阶知识)
标记清理【任何上下文都无法访问,将会打上标记】
引用计数。声明变量时引用数为1,当被其他值覆盖,引用数减去1,当引用数为0,则可删除。(不建议,循环引用不适用)
性能问题(合适的时机删除变量)
内存管理,建议不用的变量,手动赋值 null,释放其引用
3.4 小结
- 执行上下文分全局上下文、函数上下文和块级上下文。
- 代码执行流每进入一个新上下文,都会创建一个作用域链,用于搜索变量和函数。
- 全局上下文只能访问全局上下文中的变量和函数,不能直接访问局部上下文中的任何数据。
- 离开作用域的值会被自动标记为可回收,然后在垃圾回收期间被删除。
- 主流的垃圾回收算法是标记清理,即先给当前不使用的值加上标记,再回来回收它们的内存。
4. 基本引用类型
❤ 小提示:前面内容没有太多有用信息。
4.1 Date
4.1.1 创建日期对象
- 创建一个 Date 的实例对象
1 | let now = new Date(); // 2023-06-05T06:02:04.276Z |
- 通过 Date.parse 创建对象
1 | let someDate = new Date(Date.parse("6/5/2023")); // 2023-06-05T16:00:00.000Z |
Date.parse 参数支持的格式:
- 月/日/年 如: 6/5/2023
- 月名 日, 年 如:June 5, 2023
- 周几 月名 日 年 时:分:秒 时区 如”Mon June 5 2032 00:00:00 GMT-0700”
- 【推荐】YYYY-MM-DDTHH:mm:ss.sssZ 如2019-05-23T00:00:00
- 通过 Date.UTC 创建对象 (月份应该要减去1)
1 | // 参数内容从左到右: 年月日时分秒 |
- 返回当前日期 Date.now()
1 | let start = Date.now(); |
4.1.2 日期格式化
- toDateString 显示周几、年月日
- toTimeString 显示时区、时分秒
- toLocaleDateString
- toLocaleTimeString
- toUTCString 显示完整的UTC日期
1 | let now = new Date() |
4.1.3 Date 类型具体方法
getTime() 返回日期的毫秒表示;与 valueOf()相同
setTime(milliseconds) 设置日期的毫秒表示,从而修改整个日期
更多方法,访问 MDN
4.2 RegExp 正则
基本格式:
1 | let expression = /pattern/flags; |
pattern 模式:包括字符类、限定符、分组、向前查找和反向引用
flags 标记:0 个或多个,一般有6种模式
- g 全局模式,查找字符串全部内容
- i 不区分大小写
- m 多行模式
- y 粘附模式,只查找从 lastIndex 开始以及之后字符串
- u Unicode 模式
- s dotAll 模式 表示元字符
.
匹配任何字符(包括\n 和 \r)】
1 | let patter = /123/g |
更多资料参考菜鸟教程,多使用正则。
4.3 原始值包含类型
基本使用:
1 | // 将字符串转成数字 |
4.4 内置对象
不用显示实例化内置对象,开箱即用
Global 对象
isNaN 函数
isFinite 函数
parseInt 函数
parseFloat 函数
encodeURI() 用于编码URI 【类似encodeURIComponent】
1
2let url = encodeURI("https://www.baidu.com/s?wd=菜鸟")
console.log(url); // https://www.baidu.com/s?wd=%E8%8F%9C%E9%B8%9FdecodeURI()和 decodeURIComponent()
1
2let d = decodeURI("https://www.baidu.com/s?wd=%E8%8F%9C%E9%B8%9F")
console.log(d); // https://www.baidu.com/s?wd=菜鸟[强大] eval 函数,执行 JS 语句 [==容易被 XSS 利用,谨慎!!==]
1
2
3
4
5
6const str = `
let a = 1;
let b = 2;
console.log(a + b);
`
eval(str); // 3Global 对象属性,请翻阅MDN
Window 属性
所有全局作用域中声明的变量和函数都变成了 window 的属性
当然: 仅限 var 声明变量 和 函数
1
2
3
4
5var color = "red";
function sayColor() {
console.log(window.color);
}
window.sayColor(); // "red"Math 对象: 数学公式
更多资料请翻阅 MDN
4.5 小结
当代码开始执行时,全局上下文中会存在两个内置对象:Global 和 Math。
5. 集合引用类型
内容:对象、数组、定型数组、Map、WeakMap、Set和WeekSet
5.1 Object
- 对象创建:
① new 操作符
1 | let p = new Object() // 也可以 let p = {} |
② 对象字面量
1 | let person = { |
- 获取属性
1 | person["name"] |
5.2 Array
- 数组创建
1 | let colors = new Array(); // Array(20) Array("1","2") |
- 数组拆分
1 | Array.from("Matt"); // [ 'M', 'a', 't', 't' ] |
- 将集合映射成新数组
1 | const m = new Map().set(1, 2) .set(3, 4); |
- 浅复制当前数组
1 | const a1 = [1, 2, 3, 4]; |
- 可以使用任何可迭代对象
1 | const iter = { |
- arguments 转为数组
1 | function getArgsArray() { |
- 换带有必要属性的自定义对象
1 | const arrayLikeObject = { |
- Array.of 函数
1 | Array.of(1,2,3,4); // [1,2,3,4] |
- 数组空位 let arr = [,,,] { % label 不建议 orange%}
- 数组索引从0开始,到 length - 1结束
- 判断是否为数组
- instanchof
- Array.isArray
- 迭代器方法:keys() values() 和 entries()
- 复制和填充方法 copyWithin 和 fill
- 栈方法 push 和 pop
- 队列方法
- shift 方法: 删除第一项并返回它,数组长度减去1
- push
- unshift 方法:数组开头添加,数组长度加1,返回新的数组长度
- pop
- 排序方法 reverse 和 sort,返回数组的引用
- 操作方法
- concat 函数 拼接数组
- slice 函数 相当于切片
- splice 函数,实现删除、插入、替换【常用】
- 搜索
- indexOf 、lastIndexOf 和 includes 【严格相等】
- find、findIndex 【断言函数】
- 迭代方法
- every 每项函数必须返回 true
- filter 每项函数返回 true 组成新数组
- forEach 遍历每一项
- map 返回由每项函数调用的结果组成的数组
- some 如果有一项返回 true
- 归并方法
- reduce
- reduceRight
注意 如果数组中某一项是 null 或 undefined,则在 join()、toLocaleString()、
toString()和 valueOf()返回的结果中会以空字符串表示。
5.3 定型数组
- ArrayBuffer:可用于在内存中分配特定数量的字节空间【类似C++ 的 malloc】【定型数组及视图引用的基本单位】
1 | // 在内存中分配 16 字节 |
slice 方法:复制全部或部分到新数组
注意:
- 分配内存失败,报错
- 分配内存不能超过 Number.MAX_SAFE_INTEGER
- 初始成功后,将所有二进制位初始化为0
- 可以被垃圾回收
要读取或写入 ArrayBuffer,就必须通过视图
- DataView 允许读写 ArrayBuffer 的视图