# JavaScript 学习
# HTML 中的 JavaScript
# <script> 元素
在 <script>
元素中的代码或外部 JavaScript 文件被解释完之前,页面的其余内容不会被加载,也不会被显示;
如果同时存在 <script>
元素中的代码和外部 JavaScript 文件时,浏览器只会下载并执行脚本文件,忽略行内代码;
现代 Web 应用程序一般将 JavaScript 的引用放在 <body>
元素中的页面内容后面;
# 延迟脚本
defer
属性:表明脚本在执行时不会影响页面的构造,即脚本会被延迟到整个页面都解析完毕后再运行;
# 输入输出
# 输出
<script> | |
prompt('这是一个输入框'); | |
alert('这是一个警示框'); | |
console.log('这是控制台打印输出的') | |
</script> |
# 输入
var age = promopt('请输入你的年龄'); |
# 语言基础
# 数据类型
# typeof 操作符
# Number 型
数字型进制:
数值型范围:
数值型的三个特殊值:
isNaN()函数:
NaN:
浮点数:
永远不要测试某个特定的浮点数值;
字符串数组转数字数组
let strArr=['1','2','3'] | |
let newArr=strArr.map(Number) |
# String 型
单引号或者双引号,如果嵌套就外双内单或内双外单;
字符串转义符:
字符串长度:
var txt ='abcdefg'; | |
console.log(txt.length); |
字符串拼接:
toString():
数值、布尔值、对象和字符串值(没错,每个字符串也都有一个 toString () 方法,该方法返回字符串的一个副本)都有 toString () 方法。但 null 和 undefined 值没有这个方法;
# Boolean 型
true 和 false 是区分大小写的,故必须小写;
# undefined 与 null
如果一个变量声明未赋值,就是 undefined(未定义数据类型);
一个声明变量给 null 值,里面存的值为空;逻辑上讲,null 值表示一个空对象指针;
let car =null; | |
console.log(typeof car); //"object" |
# Symbol 型
symbol 的值是通过 Symbol () 函数生成,每一个 symbol 的值都是唯一的,并且 symbol 类型的值可以作为对象的属性标识符使用,这也是 symbol 类型设计的目的。
所以现在对象属性名可以为两种类型:一种就是原本的字符串类型,一种即为新增的 symbol 类型。凡是使用 symbol 命名的属性都是独一无二的,保证不与其他属性名产生冲突。
# Object 型
对象(Object)其实就是一组数据和功能的集合。对象可以通过执行 new 操作符后跟要创建 的对象类型的名称来创建。而创建 Object 类型的实例并为其添加属性和(或)方法,就可以创建自定义对象;
# 数值转换
常见的类型转换有:
- 强制转换(显示转换)
- 自动转换(隐式转换)
显示转换:
Number():
Number(324) // 324 | |
// 字符串:如果可以被解析为数值,则转换为相应的数值 | |
Number('324') // 324 | |
// 字符串:如果不可以被解析为数值,返回 NaN | |
Number('324abc') // NaN | |
// 空字符串转为 0 | |
Number('') // 0 | |
// 布尔值:true 转成 1,false 转成 0 | |
Number(true) // 1 | |
Number(false) // 0 | |
//undefined:转成 NaN | |
Number(undefined) // NaN | |
//null:转成 0 | |
Number(null) // 0 | |
// 对象:通常转换成 NaN (除了只包含单个数值的数组) | |
Number({a: 1}) // NaN | |
Number([1, 2, 3]) // NaN | |
Number([5]) // 5 |
Number
转换的时候是很严格的,只要有一个字符无法转成数值,整个字符串就会被转为NaN
parseInt()
parseInt
相比 Number
,就没那么严格了, parseInt
函数逐个解析字符,遇到不能转换的字符就停下来;
parseInt('32a3') //32 |
不能转换出小数;
parseFloat():
String()
// 数值:转为相应的字符串 | |
String(1) // "1" | |
// 字符串:转换后还是原来的值 | |
String("a") // "a" | |
// 布尔值:true 转为字符串 "true",false 转为字符串 "false" | |
String(true) // "true" | |
//undefined:转为字符串 "undefined" | |
String(undefined) // "undefined" | |
//null:转为字符串 "null" | |
String(null) // "null" | |
// 对象 | |
String({a: 1}) // "[object Object]" | |
String([1, 2, 3]) // "1,2,3" |
Boolean()
可以将任意类型的值转为布尔值,转换规则如下:
Boolean(undefined) // false | |
Boolean(null) // false | |
Boolean(0) // false | |
Boolean(NaN) // false | |
Boolean('') // false | |
Boolean({}) // true | |
Boolean([]) // true | |
Boolean(new Boolean(false)) // true |
隐式转换:
我们这里可以归纳为两种情况发生隐式转换的场景:
- 比较运算(
==
、!=
、>
、<
)、if
、while
需要布尔值地方 - 算术运算(
+
、-
、*
、/
、%
)
# 字符串操作方法
提取字符串:
slice()
substr()
substring()
查看字符串位置:
indexOf
lastIndexOf()
trim():
这个方法会创建字符串的一个副本,删除前、后所有空格符,再返回结果;另外,trimLeft () 和 trimRight () 方法分别用于从字符串开始和末尾清理空格符。
repeat():
这个方法接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果。
padStart () 与 padEnd ():
大小写转换:
toLowerCase
toUpperCase
将字符串全部转换为小写(大写);
字符串替换:
replace()
localeCompare():
# Math
Math 的基本属性:
求最大最小值:
min()
max()
舍入方法:
round()
fround()
ceil()
floor()
round(): 执行四舍五入;
fround (): 返回数值最接近的单精度(32 位)浮点值;
ceil (): 向上舍入最接近的整数;
floor(): 向下舍入最接近的整数;
随机数:
random()
该方法生成一个在 [0,1) 范围内的随机数;
通常使用方法:
function selectFrom(lowerValue,upperValue){ | |
let choices = upperValue-lowerValue+1; | |
return Math.floor(Math.random()*choices+lowerValue); | |
} |
其它数学方法:
# Array
from()
Array.from () 的第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个 length 属性和可索引元素的结构;
Array.from () 还接收第二个可选的映射函数参数,这个函数可以直接增强新数组的值;
fill()
copyWithin()
toString()
push()
该方法接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。
pop()
该方法则用于删除数组的最后一项,同时减少数组的 length 值,返回被删除的项。
shift()
该方法它会删除数组的第一项并返回它,然后数组长度减 1。
unshift()
该方法会在数组开头添加任意多个值,然后返回新的数组长度。
reverse()
该方法将数组元素反向排序;
sort()
一般使用该方法时接收一个比较函数;
slice()
如果参数有负数,则改为数组长度加上负值。
splice()
定型数组:
# Map
写法 | 关键字 | 描述 |
---|---|---|
new Map() | 创建 | 创建 map |
map.set(key, value) | 设置 | 根据键存储值 |
map.get(key) | 获取 | 根据键来返回值,如果 map 中不存在对应的 key ,则返回 undefined |
map.has(key) | 是否存在 | 如果 key 存在则返回 true ,否则返回 false |
map.delete(key) | 删除 | 删除指定键的值 |
map.clear() | 清空 | 清空 map |
map.size | 大小 | 返回当前元素个数 |
Objects
和 Maps
类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。
对比:
意外的键
- Map:不包含任何键(
Map默认情况不包含任何键。只包含显式插入的键。
) - Object:有一个原型(
一个 Object有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
)
键的类型
- Map:任意值(
一个 Map的键可以是任意值,包括函数、对象或任意基本类型。
) - Object:必须是 String 或 Symbol(
一个Object 的键必须是一个 String 或是Symbol。
)
键的顺序
- Map:有序(
Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。
) - Object:无序(
一个 Object 的键是无序的
)
Size
- Map:可直接获取长度(
Map 的键值对个数可以轻易地通过size 属性获取
) - Object:不能直接获取长度(
Object 的键值对个数只能手动计算
)
性能
- Map:在频繁增删键值对的场景下表现更好。
- Object:在频繁添加和删除键值对的场景下未作出优化。
# Set
Set 与数组类似, Set 集合中的元素不重复。
- 查找元素: 在数组中使用 indexOf () 或 includes () 检查元素是否存在比较慢;
- 删除元素: 在 Set 中,可以通过值删除元素。即在数组中,基于索引的 splice () 功能;
- 插入元素: 在 Set 中添加元素比在数组中通过 push ()、 unshift () 或其他同类操作要快;
- 去重: Set 对象仅能存储不同的值;
Set 常用操作方法:
方法 / 属性 | 功能介绍 |
---|---|
size | 获取当前 Set 对象的长度 |
add(value) | 向当前 Set 对象中添加一个值,返回的是 Set 对象,所以支持链式写法 |
delete(value) | 删除当前 Set 对象中的一个值,返回一个布尔值,表示是否删除成功 |
has(value) | 检测这个 value 是否是当前 Set 对象的一个元素,通过返回的布尔值表示 |
clear() | 清除当前 Set 对象所有元素,没有返回值 |
Set 遍历方法:
方法 / 属性 | 功能介绍 |
---|---|
keys() | 返回该 Set 对象键名的遍历器,等同 values () |
values() | 返回该 Set 对象键值的遍历器,等同 keys () |
entries() | 返回该 Set 对象键值对的遍历器 (目前感觉没什么用) |
forEach() | 使用回调函数遍历该 Set 对象的每个元素 |
# 字符串数组方法
# 数组
改变原数组的方法:
# push
push () 方法可向数组的末尾添加一个或多个元素,并返回新的长度;
let ary=[10,20,30,40] | |
let res=ary.push(50) | |
//ary=[10,20,30,40,50] | |
//res=5 |
# unshift
unshift () 方法可向数组的开头添加一个或更多元素,并返回新的长度;
let ary=[10,20,30,40] | |
let res=ary.unshift(50) | |
//ary=[50,10,20,30,40] | |
//res=5 |
# pop
pop () 用于删除并返回最后一个元素,尾部删除,返回被删除的元素,改变原数组;
var a = [1,2,3] | |
var b = a.pop() | |
console.log(a) // [1,2] | |
console.log(b) // 3 |
# shift
shift () 用于删除并返回首个元素,删除首部元素,返回被删元素,改变原数组;
var a = [1,2,3] | |
var b = a.shift() | |
console.log(a) // [2,3] | |
console.log(b) // 1 |
# sort
按 ascii 码排序,改变原数组,返回排序后的数组;也可以接收一个比较函数;
var a = ['a','b','d','c'] | |
console.log(a.sort()) // ['a','b','c','d'] | |
console.log(a) // ['a','b','c','d'] |
# splice
splice () 方法用于添加或删除数组中的元素;
var n =array.splice(index,howmany,item1,.....,itemX) | |
// 如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组,如果只增加了元素,则返回空数组 |
参数 | 描述 |
---|---|
index | 必需。规定从何处添加 / 删除元素。 该参数是开始插入和(或)删除的数组元素的下标,必须是数字。 |
howmany | 可选。规定应该删除多少元素。必须是数字,但可以是 "0"。 如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。 |
item1, ..., itemX | 可选。要添加到数组的新元素 |
# reverse
reverse () 方法用于颠倒数组中元素的顺序,返回的是颠倒后的数组,会改变原数组。
var a = [1,3,2,7,6] | |
console.log(a.reverse()) // [6,7,2,3,1] | |
console.log(a) // [6,7,2,3,1] |
# fill
fill () 方法用于将一个固定值替换数组的元素,返回改变后的原数组;
array.fill('value', start, end) | |
//start 与 end 为可选参数 |
不改变原数组的方法:
# forEach
遍历整个数组,中途不能中断,没有返回值,不能改变原数组;
var arr = ['a','b','c'] | |
var copy = [] | |
arr.forEach(function(item){ | |
copy.push(item) | |
}) | |
console.log(copy) |
# slice
slice (startIndex,endIndex) 返回从 startIndex 开始 (包括),到 endIndex (不包括) 之间的原属组成的数组,返回新数组,不改变原数组;
var a = [1,2,3] | |
var b = a.slice(0,1) | |
// 不填参数则表示剪切整个数组 | |
var c = a.slice() | |
console.log(a) // [1,2,3] | |
console.log(b) // [1] | |
console.log(c) // [1,2,3] | |
console.log(a===c) //false// 注意 a !== c | |
// 负数表示从后往前数 | |
var d = a.slice(-1,-2) | |
console.log(d) // [] 从左向右截取,所以说为 [] | |
var e = a.slice(-1) | |
console.log(e) // [3] |
# join
join () 方法用来将数组转换为字符串,不改变原数组,返回转换后的字符串;
var a = [1,2,3,4,5] | |
console.log(a.join(',')) // 1,2,3,4,5 | |
console.log(a) // [1,2,3,4,5] |
# filter
filter () 方法返回数组中满足条件的元素组成的新数组,原数组不变,参数为一个方法, filter()
把传入的函数依次作用于每个元素,然后根据返回值是 true
还是 false
决定保留还是丢弃该元素;
var a = [1,2,3,4,11] | |
// 第一个参数为一个方法,有三个参数,current: 当前值 index: 当前值下标 array: 这个数组对象 | |
var b = a.filter(function(current,index,array){ | |
return current < 10 | |
}) | |
console.log(b) // [1,2,3,4] | |
console.log(a) // [1,2,3,4,11] |
# map
map () 方法来根据需求格式化原数组,返回格式化后的数组。原数组不变;
var a = [1,2,3,4,5] | |
// 参数同 filter 方法 | |
var b = a.map(function(current,index,array){ | |
return current + 1 | |
}) | |
console.log(b) // [2,3,4,5,6] | |
console.log(a) // [1,2,3,4,5] |
# indexOf 和 lastIndexOf
indexOf (某元素,startIndex) 从 startIndex 开始,查找某元素在数组中的位置,若存在,则返回第一个位置的下标,否则返回 - 1
lastIndexOf (某元素,startIndex) 和 indexOf () 相同,区别在于从尾部向首部查询
不会改变原数组,返回找到的 index, 否则返回 - 1
若不使用下标,则一般通过 includes () 方法代替 indexOf ()
var a = [1,2,4,3,4,5] | |
console.log(a.indexOf(4)) // 2 | |
console.log(a.indexOf(4,3)) // 4 |
# includes
includes () 方法,返回一个布尔值。 参数是一个 value, 一般用于简单数组。
对于复杂数组,则可以使用 some () 方法替代 includes () 方法;
var a = [1,2,3] | |
console.log(a.includes(1)) // true |
# concat
首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组;
let colors = ["red", "green", "blue"]; | |
let colors2 = colors.concat("yellow", ["black", "brown"]); | |
console.log(colors); // ["red", "green","blue"] | |
console.log(colors2); // ["red", "green", "blue", "yellow", "black", "brown"] |
# every
对数组的每一项都运行给定的函数,若每一项都返回 ture, 则返回 true;
var a = [1,2,3,4,5] | |
var b = a.every(function(current,index,array){ | |
return current < 6 | |
}) | |
var c = a.every(function(current,index,array){ | |
return current < 3 | |
}) | |
console.log(b) // true | |
console.log(c) // false |
# some
对数组的每一项都运行给定的函数,若存在一项或多项返回 ture, 则返回 true;
var a = [1,2,3,4,5] | |
var b = a.some(function(current,index,array){ | |
return current > 4 | |
}) | |
var c = a.some(function(current,index,array){ | |
return current > 5 | |
}) | |
console.log(b) // true | |
console.log(c) // false |
# find
找到数组中第一次满足条件的元素,并返回改元素,若找不到则返回 undefined。不改变原数组。
和 filter () 方法的区别在于:filter 返回值是所有满足条件的元素组成的数组,
一般在需要使用找到的元素时,用 find () 方法
var a = [1,2,3,4] | |
//b 在下面需要使用,则一般用 find | |
var b = a.find(function(ele,index,array){ | |
return ele == 1 | |
}) | |
var c = 3 | |
var d = b + c | |
console.log(a) // [1,2,3,4] | |
console.log(b) // 1 | |
console.log(d) // 4 | |
// 若只需判断元素是否存在 | |
// 若果是简单数组 (非对象数组),则一般使用 Array.includes (value) 方法 | |
// 如果为对象数组,则可以使用 Array.some () 方法 | |
var a = [1,2,3] | |
console.log(a.includes(1)) // true | |
var a = [{"name": "xiaoming" },{"name": "xiaohong"}] | |
console.log(a.some(function(ele){ | |
return ele.name == 'xiaoming' | |
})) // true |
# findIndex
findIndex () 的作用同 indexOf (),返回第一个满足条件的下标,并停止寻找。
区别是 findIndex () 的参数为一个回调函数,且一般用于对象数组
var a = [1,2,3,4] | |
var b = a.findIndex(function(ele,index,array){ | |
return ele === 2 | |
}) | |
var c = a.indexOf(2) | |
console.log(a) // [1,2,3,4] | |
console.log(b) // 1 | |
console.log(c) // 1 |
# Array.from
该 Array.from () 方法将从具有 length 属性或可迭代对象的任何 JavaScript 对象中返回一个数组对象。
// 可用来创建多维数组 | |
let ary= Array.from(Array(m),()=>Array(n).fill(0)) | |
// 创建 m*n 的全 0 数组 |
# isArray
用来判断一个元素是否为数组;
Array.isArray([]) // true | |
Array.isArray({}) // false |
# 字符串
# concat
concat () 方法用于连接两个或多个字符串或。
该方法没有改变原有字符串,但是会返回连接两个或多个字符串的新字符串。
var str1="Hello "; | |
var str2="world!"; | |
var str3=" Have a nice day!"; | |
var n = str1.concat(str2,str3); | |
// n='Hello world! Have a nice day!' |
# slice、substr、substring
不改变原字符串,返回新字符串
# trim
trim()移除字符串前后的空格,经常在对 input 和 textarea 的值做判断时用到,不改变原字符串,返回新字符串;同理:trimLeft () trimRight ()
# toLowerCase
把字符串转换成小写的;
# toUpperCase
把字符串转换成大写的;
# repeat
接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果;
let stringValue = "na "; | |
let copyResult = stringValue.repeat(2) // na na |
# charAt
返回指定索引的字符;
var str = "abbcalgldkjgldgehlgjldf" | |
str.charAt(1) // 结果是 b |
# includes
从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值;
let message = "foobarbaz"; | |
console.log(message.includes("bar")); // true | |
console.log(message.includes("qux")); // false |
# indexOf
同上
# split
把字符串分割为子字符串数组,并返回新数组;
var ary=string.split(separator,limit) | |
// 第一个参数为用于分割的字符串,一般为 '' 或 ' ' | |
// 第二个参数为返回的字符串的最大长度 |
var str="How are you doing today?"; | |
var n=str.split(""); | |
//['H', 'o', 'w', ' ', 'a', 'r', 'e', ' ', 'y', 'o', 'u', ' ', 'd', 'o', 'i', 'n', 'g', ' ', 't', 'o', 'd', 'a', 'y', '?'] |
# match
match () 方法可在字符串内检索指定的值,找到一个或多个正则表达式的匹配,并返回一个新数组;
let text = "cat, bat, sat, fat"; | |
let pattern = /.at/; | |
let matches = text.match(pattern); | |
console.log(matches[0]); // "cat" | |
// 参数 regexp 规定要匹配的模式的 RegExp 对象。如果该参数不是 RegExp 对象,则需要首先把它传递给 RegExp 构造函数,将其转换为 RegExp 对象 |
# replace
replace () 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串;
let stringNew=stringOld.replace(regexp/substr,replacement) | |
let text = "cat, bat, sat, fat"; | |
let pos = text.search(/at/); | |
console.log(pos); // 1 |
# search
search () 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。找到则返回匹配索引,否则返回 -1;
stringObject.search(regexp) | |
//stringObject 中第一个与 regexp 相匹配的子串的起始位置。 | |
let text = "cat, bat, sat, fat"; | |
let pos = text.search(/at/); | |
console.log(pos); // 1 |
# 正则表达式
模式
- g:全局模式,常用于执行一个全局搜索匹配,即(不仅仅返回第一个匹配的,而是返回全部);
- i:不区分大小写;
- m:执行一个多行匹配
普通字符
\w
:匹配一个字母、数字、下划线;\W
:匹配一个非字母、数字、下划线;\d
:匹配一个数字\D
:匹配一个非数字\n
:查找一个换行符\r
:查找一个回车符\s
:可以匹配一个空格(也包括 Tab 等空白符);[A-Z]
:[A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母;[A-z]
:查找从大写 A 到小写 z 范围内的字符,即所有大小写的字母;[0-9]
:查找从 0 至 9 范围内的数字,即查找数字;[a-zA-Z0-9]
:查找所有的英文字符和数字;
特殊字符
[^]
:查找不在方括号内任意一个字符(如[^ABC]
);.
:可以匹配任意字符,但不包括换行符,故'py.'
可以匹配'pyc'
、'pyo'
、'py!'
等等;?
:n?
匹配任何包含零个或一个 n 的字符串;*
:n*
匹配任何包含零个或多个 n 的字符串;+
:n+
匹配任何包含一个及以上 n 的字符串;{}
:n{x}
匹配包含 x 个 n 的序列的字符串,n{x,y}
匹配包含最少 x 个、最多 y 个 n 的序列的字符串,n{x,}
匹配包含至少 x 个 n 的序列的字符串;|
:表示在两个子模式的匹配结果中任选一个,如/a {dog|cat}/
;()
:表示括号内的字符必须全部包含;[]
:表示方括号内的字符为指定字符的范围;^
:匹配开头,在多行检测中,会匹配(限制)一行的开头,如/^\w+/
会匹配第一个单词;$
:匹配结尾,在多行检测中,会匹配一行的结尾,如/\w+$/
会匹配最后一个单词;\
:转义字符,用于匹配一些保留的字符[ ] ( ) { } . * + ? ^ $ \ |
;\num
:反向引用,所谓的 \1 引用了第一个 () 匹配到的内容,比如 (x)(y)\2 该正则是想匹配到第一个字符是 x, 第二个字符是 y,第三个字符也是 y 的内容,即 xyy 能够被匹配到,但是 xya、xyb 就不能被匹配到;
# test()
test () 方法用于检测一个字符串是否匹配某个模式,如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false。
RegExpObject.test(string) |
代码实例:
let data = ['#123456', '247146086@qq.com', '15281091015', '123.0.5.255', | |
'https://www.bilibili.com/video/BV1QK4y1K72U?spm_id_from=333.999.0.0', | |
'247146086', '0.0.0.0', '#ABC', '2021-10-01', '18215576625', '825662107', '15281091015', | |
'https://www.https://nc3021.github.io/', '255.255.255.255', '1257730824', | |
'#9bf', '1984-02-30'] | |
function regexp(ary, reg) { | |
let result = [] | |
ary.forEach(element => { | |
if (element.match(reg)) | |
result.push(element.match(reg)[0]) | |
}) | |
return result | |
} | |
//phoneNumber | |
let regPhone = /^1[3-9][0-9]{9}$/g | |
let aryPhone = regexp(data, regPhone) | |
console.log('phoneNumber:', aryPhone) | |
//QQNumber | |
let regQQ = /^[1-9][0-9]{4,9}$/ | |
let aryQQ = regexp(data, regQQ) | |
console.log('QQNumber:', aryQQ) | |
//color | |
let regColor = /^#([0-9a-fA-F]{6}$|[0-9a-fA-F]{3}$)/g | |
let aryColor = regexp(data, regColor) | |
console.log('Color:', aryColor) | |
//email | |
let regEmail = /^([\w\.\-]+)@([\w\.\-]+)\.([a-zA-Z]{2,6})$/g | |
let aryEmail = regexp(data, regEmail) | |
console.log('Email:', aryEmail) | |
//url | |
let regUrl = /^((https?|ftp|file):\/\/)?([\da-z\.\-]+)\.([a-z\.]{2,6})((.*\/)*)?(.*)?$/g | |
let aryUrl = regexp(data, regUrl) | |
console.log('Url:', aryUrl) | |
//Ipv4 | |
let regIpv4 = /^(([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/g | |
let aryIpv4 = regexp(data, regIpv4) | |
console.log('Ipv4:', aryIpv4) | |
// 或 | 之间不用加(),原因不清 | |
//date | |
let regDate = /^\d{4}-(0\d|1[012])-(0\d|[12]\d|3[01])/g | |
let aryDate = regexp(data, regDate) | |
console.log('Date:', aryDate) | |
var pattern1 = /\[bc\]at/; | |
// 等价于 var pattern1 = new RegExp ("\\[bc\\] at", "i"); |
# 操作符
# 一元操作符
递增递减操作符(++/--):
前缀递增或递减时,变量的值都是在语句被求值以前改变的;后缀递增或递减时,变量的值都是在语句求值之后才改变的;
正负操作符(+/-):
# 位操作符
# 布尔操作符
逻辑非!:
通过使用(!!n)将一个值转换位其对应的布尔值;
逻辑与 &&:
逻辑或 ||:
一些特殊用法:
防止初始值为 null(importent)
# 乘性操作符
乘法:
除法:
取模:
# 指数操作符(**)
# 加性操作符
加法:
减法:
# 关系运算符(><)
# 相等操作符
由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,一般推荐使用全等和不全等操作符;
# 迭代器
# 对象与类
# 对象
# 对象属性
数据属性:
将属性显式添加到对象之后,[[Configurable]]、[[Enumerable]] 和 [[Writable]] 都会被设置为 true,而 [[Value]] 特性会被设置为指定的值;
属性修改
Object.defineProperty () 方法:
在调用 Object.defineProperty () 时,configurable、enumerable 和 writable 的值如果不指定,则都默认为 false;
访问器属性:
属性定义
Object.defineProperty () 方法:
定义多个属性
Objext.define-Properties () 方法:
读取属性的特性:
Object.getOwnPropertyDescriptor () 方法:
合并对象:~P210
对象标识及相等判定:
对象结构:~P216
# 创建对象
工厂模式(非构造函数):
构造函数模式:
两者区别:
没有显式地创建对象
属性和方法直接赋值给了 this
没有 return
按照惯例,构造函数名称的首字母都是要大写的, 非构造函数则以小写字母开头;
构造函数与普通函数唯一的区别就是调用方式不同。除此之外,构造函数也是函数。并没有把某个函数定义为构造函数的特殊语法。任何函数只要使用 new 操作符调用就是构造函数,而不使用 new 操作符调用的函数就是普通函数;
但通过构造函数创建出的每个实例的函数虽然同名但不相等,故因此一般将函数定义转移到构造函数外部;
原型模式:
Object.getProtorypeOf () 方法:
返回参数的内部特性 Prototype
的值;
Object.create () 方法:
创建一个新对象,同时为其指定原型;
Object.hasOwnProperty () 方法:
确定某个属性是在实例上还是原型对象上;参数为属性名,返回 ture 则说明来自实例,返回 false 则说明来自原型;
in 操作符:
确定某个属性是否在该对象的实例或原型对象上;
Object.keys () 方法:
这个方法接收一个对象作为参数,返回包含该对象所有可枚举属性名称的字符串数组;
对象迭代:
Object.entries () 方法:
接收一个对象,返回它们内容(键值对)的数组;
Object.values () 方法:
接收一个对象,返回它们对象值的数组;
例:[[' 键 ',' 值 '],[' 键 ',' 值 '],[' 键 ',' 值 ']]
注意:非字符串属性会被转换为字符串输出,符号属性会被忽略;
# this
1:this 永远指向一个对象;
2:this 的指向完全取决于函数调用的位置
# 继承
原型链:
instanceof 操作符:
如果一个实例的原型链中出现过相应的构造函数,则返回 true;
console.log(instance instanceof Object);//ture |
isProtorypeOf () 方法:
如果原型链中包含这个原型,则返回 true;
console.log(Object.prototype.isPrototypeOf(instance));//true |
# 组合继承
综合了原型链和盗用构造函数,通过盗用构造函数继承构造函数的属性,通过原型链继承原型上的方法;
从而避免了原型中所包含的引用值会在所有的实例间共享的问题(原型链的弊端);以及盗用构造函数中重新定义方法的问题;
# 原型式继承
Object.create () 方法:
接收两个参数:第一个作为新对象原型的对象,第二个为给新对象定义额外属性的对象(可选)。在只有一个参数时, Object.create () 与这里的 object () 方法效果相同;
# 寄生式组合继承
寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。基本思路是不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。说到底就是使用寄生式继承来继承父类原型,然后将返回的新对象赋值给子类原型;
相比于组合继承,少调用了一次父构造函数(只在最后构造实例时调用了父构造函数),从而效率更高,是引用类型继承的最佳模式;
# 类
与函数类型相似,定义类也有两种主要方式:类声明和类表达式。这两种方式都使用 class 关键字加大括号:
class Person {}// 类声明 | |
const Animal = class {};// 类表达式 |
与函数表达式式类似,类表达式在它们被求值前也不能引用。不过,与函数定义不同的是,虽然函数声明可以提升,但类定义不能;
类构造函数
constructor () 用于在类定义块内部创建类的构造函数。方法名 constructor 会告诉解释器在使用 new 操作符创建类的新实例时,应该调用这个函数。构造函数的定义不是必需的,不定义构造函数相当于将构造函数定义为空函数;
实例、原型、类成员:~P254
继承:~P258
# 代理和反射
# 函数
函数声明可以提升,但函数表达式不可以;
# 函数参数
函数的参数在函数内部表现为一个数组,存放在一个类数组对象 arguments
中;
可以通过 arguments [0] 获得第一个参数;也可以通过 arguments 的 length 属性检查传入的参数个数,即
但如果采用箭头函数则没有 arguments 对象。
arguments 还有一个属性 callee
, 是一个指向 arguments 对象所在函数的指针,可以让函数逻辑与函数名解耦;
function jiecheng(num){ | |
if (num<=1){ | |
return 1; | |
}else{ | |
return num*jiecheng(num-1); | |
} | |
} |
# 期约与异步函数
Promise 详解与实现(Promise/A + 规范) - 简书 (jianshu.com)
async
函数执行返回一个 promise
对象,且 async
函数内部的返回值会当作这个 promise 对象 resolve 状态的值;
await
是一个表达式,如果后面不是一个 promise 对象,就直接返回对应的值,如果跟一个 promise 对象,await 将等待这个 promise 对象的 resolve 状态的值,且将这个值返回给前面的变量;
# 期约
~P325
# 异步函数
~P348
# 执行上下文
[深入理解 JavaScript 执行上下文和执行栈 - Fundebug - 博客园 (cnblogs.com)](https://www.cnblogs.com/fundebug/p/understand-javascript-context-and-stack.html#:~:text = 一、执行上下文(Execution Context). 1. 什么是执行上下文。简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念,,JavaScript 中运行任何的代码都是在执行上下文中运行. 2. 执行上下文的类型。执行上下文总共有三种类型:. 全局执行上下文: 这是默认的、最基础的执行上下文。. 不在任何函数中的代码都位于全局执行上下文中。.)
# AJAX
AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。而传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。
创建 XMLHttpRequest 对象
var xmlhttp;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
向服务器发送请求
xmlhttp.open("GET","ajax_info.txt",true);
xmlhttp.send();
服务器相应
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
onreadystatechange 事件
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
# BOM
浏览器对象模型(Browser Object Model)
# window
# Global 作用域
- 通过 var 声明的所有全局变量和函数都会变成 window 对象的属性和方法;但通过 let 或 const 声明的则不会把变量添加给全局对象。
- 直接访问未声明的变量会抛出异常,但通过 window 对象进行访问,可以判断未声明的变量是否存在。
alert(window.a) //undefined | |
alert(a) // 抛出异常 |
# 打开和关闭窗口
window 对象提供了 window.open () 方法和 window.close () 方法分别用于打开窗口和关闭窗口,使用 window.open () 方法即可打开一个新的窗口,并可以设置新窗口的 URL 、标题以及大小属性,window.open () 的基本语法为:
window.open (URL , 窗口名字,特征,是否替换);
第一个参数为新打开窗口的 URl 地址,如果为空,则打开页面为白板;
第二个参数为打开窗口的名字(如果参数指定一个已经存在的窗口,那么该方法不再创建一个新窗口,而是对该指定窗口的引用;
第三个参数为新窗口显示标准浏览器的特征,详情如下表
第四个参数代表着指定的 URL 是否取代浏览器记录中的当前加载页面,true 为替换浏览器记录中的当前加载页面,false 为创建浏览器历史记录中的创建新的页面;
属性值 | 描述 |
---|---|
height | 窗口的高度,单位为像素,最小值为 100 |
left | 该窗口的左侧位置,单位为像素 |
location | 是否显示浏览器的地址栏。默认值为 yes |
memubar | 是否显示浏览器的菜单栏。默认值为 yes |
resizable | 是否可以改变浏览器窗口的大小。默认值为 yes |
scrollbars | 是否显示浏览器的滚动条。默认值为 yes |
status | 是否显示浏览器的状态栏。默认值为 yes |
titlebar | 是否显示浏览器的标题栏。默认值为 yes |
top | 窗口顶部的位置,单位为像素 |
width | 窗口的宽度,单位为像素,最小值为 100 |
<h1>父窗口</h1> | |
<button onclick=" | |
subWin = window.open('subWindow.html','子窗口','width=500','height=500','top=100','left=100'); | |
">打开子窗口</button> | |
<button onclick=" | |
if (subWin!=null && !subWin.closed) {//存在且不是关闭状态 | |
subWin.close(); | |
} | |
">关闭子窗口</button> | |
<script> | |
var subWin = null;// 定义子窗口 | |
</script> |
# 窗口位置与窗口大小
window.screenLeft
: 窗口相对于屏幕左侧的距离(单位:CSS 像素)
window.screenTop
: 窗口相对于屏幕顶部的距离(单位:CSS 像素)
所有现代浏览器都支持 4 个属性: innerWidth
、 innerHeight
、 outerWidth
和 outerHeight
。
outerWidth
和 outerHeight
返回浏览器窗口自身的大小(不管是在最外层 window 上使用,还是在窗格中使用;
innerWidth
和 innerHeight
返回浏览器窗口中页面视口的大小(不包含浏览器边框和工具栏)。
# 定时器
setTimeout()
该方法通常接收两个参数:要执行的代码和在执行回调函数前等待的时间(毫秒)。第一个参数可以是包含 JavaScript 代码的字符串(类似于传给 eval () 的字符串)或者一个函数,第二个参数是要等待的毫秒数,并会返回一个唯一标识符,可用于取消该任务,只要是在指定时间到达之前调用 clearTimeout (),就可以取消超时任务。
let timeoutId =setTimeout(()=>alert('hello'),1000); | |
clearTimeout(timeoutId);// 取消超时任务 |
因为 setTimeout()
只能执行一次,所以如果要反复执行该方法中包含的代码,则应该在该方法中包含对自身的调用:
var t = 0; | |
var i = 1; | |
function f() { | |
var out = setTimeout( | |
function () { | |
t = i++; | |
f(); | |
}, 1000 | |
); | |
if (i > 3) { | |
clearTimeout(out); | |
alert('10s done') | |
} | |
} | |
f(); |
setInterval()
与 setTimeout () 的使用方法类似,只不过指定的任务会每隔指定时间就执行一次,直到取消循环定时或者页面卸载。setInterval () 同样可以接收两个参数:要执行的代码(字符串或函数),以及把下一次执行定时代码的任务添加到队列要等待的时间。其也会返回一个标识符,通过 clearInterval () 来取消任务。
# 系统对话框
可以让浏览器调用系统对话框向用户显示消息。这 些对话框与浏览器中显示的网页无关,而且也不包含 HTML。它们的外观由操作系统或者浏览器决定,无法使用 CSS 设置。此外,这些对话框都是同步的模态对话框,即在它们显示的时候,代码会停止执行, 在它们消失以后,代码才会恢复执行.
alert()
: 只接收一个参数
confirm()
:只接收一个参数,并返回布尔值
prompt()
:接收两个参数,第一个是要显示给用户的文本,第二个是文本框的默认值(可以是空字符串),最后返回文本框中的值
<script> | |
prompt('这是一个输入框'); | |
alert('这是一个警示框'); | |
console.log('这是控制台打印输出的') | |
var age = promopt('请输入你的年龄'); | |
</script> |
# location
location 是最有用的 BOM 对象之一,提供了当前窗口中加载文档的信息,以及通常的导航功能(URL)。 这个对象独特的地方在于,它既是 window 的属性,也是 document 的属性。也就是说, window.location 和 document.location 指向同一个对象。
location
对象的属性都是可读可写的,如果改变了相关属性值,浏览器就会载入新的页面。
# navigator
navigator
对象包含了浏览器的基本信息,如名称、版本和系统等。
# screen
screen
对象存储客户端屏幕的信息。
# history
history
对象存储浏览器窗口的浏览历史。
go()
方法可以在用户历史记录中沿任何方向导航,可以前进也可以后退。这个方法只接收一个参数, 这个参数可以是一个整数,表示前进或后退多少步。
history.go(-1);// 后退一页 | |
history.go(2);// 前进两页 |
history.length
用来表示历史记录的数量。
对于窗口或标签页中加载的第一个页面,history.length 等于 1。 通过以下方法测试这个值,可以确定用户浏览器的起点是不是你的页面。
# DOM
文档对象模型(Document Object Model)
HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。
换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。
# DOM 属性
innerHTML
用于获取 HTML 元素的内容
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
</head> | |
<body> | |
<p id="intro">Hello World!</p> | |
<script> | |
var txt=document.getElementById("intro").innerHTML; | |
document.write(txt); | |
</script> | |
</body> | |
</html> |
# 节点属性
nodeName
用于读取节点名称
- nodeName 是只读的
- 元素节点的 nodeName 与标签名相同
- 属性节点的 nodeName 与属性名相同
- 文本节点的 nodeName 始终是 #text
- 文档节点的 nodeName 始终是 #document
注意: nodeName 始终包含 HTML 元素的大写字母标签名。
nodeValue
用于规定节点的值
- 元素节点的 nodeValue 是 undefined 或 null
- 文本节点的 nodeValue 是文本本身
- 属性节点的 nodeValue 是属性值
nodeType
返回节点的类型(只读)
ownerDocument
返回当前节点的根元素(即 document 对象)
parentNode
返回当前节点的父节点(所有节点都仅有一个父节点)
childNodes
返回当前节点的所有子节点的节点列表( nodeList
类数组对象)
nodeList 对象实际上基于 DOM 结构动态执行查询的结果,DOM 结构的变化能够自动反映在 nodeList 对象中。可以通过方括号访问内部的值,但不能直接调用数组的方法。
firstChild
返回当前节点的首个子节点
lastChild
返回当前节点的最后一个子节点
nextSibling
返回当前节点之后相邻的同级节点
previousSibling
返回当前节点之前相邻的同级节点
# DOM 方法
getElementsByld()
返回带有指定 ID 的元素引用
node.getElementById("id"); |
getElementsByTagName()
返回带有指定标签名的所有元素
node.getElementsByTagName("tagname"); |
getElementsByClassName()
返回包含带有指定类名的所有元素的节点列表
document.getElementsByClassName("intro"); |
# 事件处理
# 事件委托
delegate
把目标节点的事件绑定到上层节点上
原因:事件传播过程中,逐层冒泡总是能被上层节点捕获;优化代码,提升运行性能,真正将 HTML 与 JavaScript 分离;也能防止动态添加或删除节点时将注册的事件丢失。
# Ajax
Ajax (Asynchronous JavaScript and XML):利用 JS 脚本和 XML 数据实现客户端与服务器端之间快捷通信的一种技巧。
# 待补充
- filter () 方法
- 箭头函数