JavaScript 基础知识
字符串处理
substring()
用法:提取字符串中介于两个指定下标之间的字符
语法:string.substring(start, stop)
参数:
- start(必需):一个非负的整数,起始下标(包含)
- stop(可选):一个非负的整数,结束下标(不包含),默认到字符串末尾
返回值:截取的字符串
示例:
const str = "hello world"
str.substring(0, 5) // 'hello'
str.substring(6) // 'world'
substr()
用法:提取字符串中从开始下标到指定长度的字符
语法:string.substr(start, length)
参数:
- start(必需):起始下标(包含)
- length(可选):截取的长度,默认到字符串末尾
返回值:截取的字符串
示例:
const str = "hello world"
str.substr(0, 5) // 'hello'
str.substr(6) // 'world'
注意事项
1. 如果 length 为 0 或负数,将返回一个空字符串
2. 如果 start 或 length 为负数,那么它将被替换为 0
slice()
用法:提取字符串中介于两个指定下标之间的内容
语法:string.slice(start, stop)
参数:
- start(必需):起始下标(包含),如果是负数,那么它规定从字符串尾部开始算起的位置。也就是说,-1 指最后一个字符,-2 指倒数第二个字符,以此类推
- stop(可选):结束下标(不包含),默认到字符串末尾,如果这个参数是负数,那么它规定的是从字符串尾部开始算起的字符
返回值:截取的字符串
示例:
const str = "hello world"
str.slice(0, 5) // 'hello'
str.slice(6) // 'world'
str.slice(0, -1) // 'hello worl'
str.slice(-1) // 'd'
str.slice(-5, -2) // 'wor'
split()
用法:将字符串分割成数组
语法:string.split(separator, limit)
参数:
- separator(可选):分隔符,默认为空格
- limit(可选):数组返回长度,默认返回全部
返回值:分割后的数组
示例:
const str = "hello world"
str.split(" ") // ['hello', 'world']
str.split("") // ['h', 'e', 'l', 'l', 'o','', 'w', 'o', 'r', 'l', 'd']
str.split("o", 2) // ['hell', 'w']
replace()
用法:替换字符串中指定字符
语法:string.replace(searchValue, replaceValue)
参数:
- searchValue(必需):需要替换的字符或者 RegExp 对象
- replaceValue(必需):替换成的字符
返回值:替换后的字符串
示例:
const str = "hello world"
str.replace("world", "world!") // 'hello world!'
str.replace(/world/g, "world!") // 'hello world!'
match()
用法:在字符串中匹配指定字符
语法:string.match(regexp)
参数:
- regexp:正则表达式对象
返回值:匹配到的字符串数组,如果没有匹配到,返回null
示例:
const str = "hello world"
str.match(/world/g) // ['world']
padStart() / padEnd()
用法:在字符串的开头或结尾填充指定字符
语法:string.padStart(targetLength, padString)
/ string.padEnd(targetLength, padString)
参数:
- targetLength(必需):需要填充的长度,如果这个数值小于当前字符串的长度,则返回当前字符串本身
- padString(可选):填充的字符,默认为空格
示例:
const str = "hello"
str.padStart(10, "*") // '*****hello'
str.padEnd(10, "*") // 'hello*****'
trimStart() / trimEnd()
用法:在字符串的开头或结尾删除空白字符
语法:string.trimStart()
/ string.trimEnd()
参数:无
返回值:去除空白字符后的结果
示例:
const str = " hello "
str.trimStart() // 'hello '
str.trimEnd() // ' hello'
数组处理
slice()
用法:返回数组中介于两个指定下标之间的内容
语法:array.slice(start, stop)
参数:
- start(必需):起始下标(包含),如果是负数,那么它规定从字符串尾部开始算起的位置。也就是说,-1 指最后一个字符,-2 指倒数第二个字符,以此类推
- stop(可选):结束下标(不包含),默认到数组末尾,如果这个参数是负数,那么它规定的是从数组尾部开始算起的字符
返回值:截取后的新数组
示例:
const arr = [1, 2, 3, 4, 5]
arr.slice(0, 2) // [1, 2]
arr.slice(2) // [3, 4, 5]
arr.slice(0, -1) // [1, 2, 3, 4]
arr.slice(-1) // [5]
splice()
用法:在数组中删除元素或删除后追加新的元素
注意事项
会改变原数组
语法:array.splice(start, count,...items)
参数:
- start(必需):起始下标(包含),可以为负数,负数从末尾开始倒计数
- count(可选):删除的个数,默认删除到数组末尾,如果为 0 或者负数,则不会执行删除操作
- items(可选):追加的新元素
返回值:被删除的元素数组
示例:
const arr = ['1', '2', '3', '4', '5']
arr.splice(0, 2) // ['1', '2']
console.log(arr) // ['3', '4', '5']
arr.splice(0, 1, '33', '44') // ['3']
console.log(arr) // ['33', '44', '4', '5']
join()
用法:将数组中的元素连接成一个字符串
语法:array.join(separator)
参数:
- separator(可选):连接符,默认以逗号分割
返回值:连接后的字符串
示例:
const arr = ['1', '2', '3', '4', '5']
arr.join() // '1,2,3,4,5'
arr.join('-') // '1-2-3-4-5'
push()
用法:在数组中添加元素
注意事项
会改变原数组
语法:array.push(item1, item2, ...)
参数:
- item1:要添加的元素
返回值:无
示例:
const arr = ['1', '2', '3', '4', '5']
arr.push('6')
arr.push('7','8')
console.log(arr) // ['1', '2', '3', '4', '5', '6', '7', '8'])
pop()
用法:删除数组中最后一个元素并返回删除的元素
注意事项
会改变原数组
语法:array.pop()
参数:无
返回值:删除的元素
示例:
const arr = ['1', '2', '3', '4', '5']
arr.pop() // '5'
console.log(arr) // ['1', '2', '3', '4']
shift()
用法:删除数组中第一个元素并返回删除的元素
注意事项
会改变原数组
语法:array.shift()
参数:无
返回值:删除的元素
示例:
const arr = ['1', '2', '3', '4', '5']
arr.shift() // '1'
console.log(arr) // ['2', '3', '4', '5']
unshift()
用法:在数组的开头添加一个或多个元素,并返回数组新的长度
注意事项
会改变原数组
语法:array.unshift(item1, item2,...)
参数:
- item1:要添加的元素
返回值:新数组的长度
示例:
const arr = ['1', '2', '3', '4', '5']
arr.unshift('6', '7') // 7
console.log(arr) // ['6', '7', '1', '2', '3', '4', '5']
sort()
用法:对数组进行排序
注意事项
会改变原数组,原理可 参考这里
语法:array.sort(compareFunction)
参数:
- compareFunction(可选):比较函数,默认按照字符编码升序
返回值:数组本身
示例:
const arr = [1, 3, 5, 2, 4]
arr.sort((a,b)=>a-b) // [1, 2, 3, 4, 5] 升序
arr.sort((a,b)=>b-a) // [5, 4, 3, 2, 1] 降序
reverse()
用法:颠倒数组中的元素顺序
注意事项
会改变原数组
语法:array.reverse()
参数:无
返回值:数组本身
示例:
const arr = [1, 3, 5, 2, 4]
arr.reverse() // [4, 2, 5, 3, 1] 升序
concat()
用法:将多个数组合并成一个数组
语法:array.concat(array1, array2,...)
参数:
- array1(必需):要合并的数组
返回值:数组本身
示例:
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
arr1.concat(arr2, [7, 8], 9) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(arr1) // [1, 2, 3]
indexOf()
用法:在数组中查找指定元素的下标(从数组的开头开始查找,找到第一个就返回)
语法:array.indexOf(item)
参数:
- item:要查找的元素
返回值: 元素下标,如果没有找到,返回-1
示例:
const arr = ['1', '2', '3', '4', '5', '3']
arr.indexOf('3') // 2
注意
在比较过程中,使用全等操作符
lastIndexOf()
用法:在数组中查找指定元素的下标(从数组的末尾开始查找,找到第一个就返回)
语法:array.lastIndexOf(item)
参数:
- item(必须):要查找的元素
返回值: 元素下标,如果没有找到,返回-1
示例:
const arr = ['1', '2', '3', '4', '5', '3']
arr.lastIndexOf('3') // 5
注意
在比较过程中,使用全等操作符
forEach()
用法:遍历数组中的每一个元素(可以跳出当前的循环,想要终止循环必须要 throw 一个错误)
语法:array.forEach(callback)
参数:
- callback(必须):回调函数,接收三个参数,第一个是当前元素,第二个是当前元素的下标,第三个是数组本身
返回值: 无
示例:
const arr = ['1', '2', '3', '4', '5']
arr.forEach((item, index, a)=>{
console.log(item, index, a)
})
map()
用法:遍历数组中的每一个元素,并返回一个新数组(无法跳出循环)
注意:和 forEach 的区别
map 可以再每次循环中使用 return 返回新数组,更适合需要创建新数组的时候使用
语法:array.map(callback)
参数:
- callback(必需):回调函数,接收三个参数,第一个是当前元素,第二个是当前元素的下标
返回值: 新数组
示例:
const arr = ['1', '2', '3', '4', '5']
const arr2 = arr.map((item, index)=>{
return item + index
})
console.log(arr2) // ['10', '21', '32', '43', '54']
filter()
用法:过滤数组中的元素,并返回一个新数组
语法:array.filter(callback)
参数:
- callback(必需):回调函数,接收三个参数,第一个是当前元素,第二个是当前元素的下标
返回值: 数组本身
示例:
const arr = ['1', '2', '3', '4', '5']
const arr2 = arr.filter((item, index)=>{
return item > 2
})
console.log(arr2) // ['3', '4', '5']
fill()
用法:填充数组中指定位置的元素
注意事项
会改变原数组
语法:array.fill(value, start, end)
参数:
- value(必需):填充的值
- start(可选):开始下标,默认 0
- end(可选):结束下标(不包含),默认到数组最后一个元素
返回值: 数组本身
示例:
const arr = ['1', '2', '3', '4', '5']
arr.fill('a', 2, 4) // ['1', '2', 'a', 'a', '5']
every()
用法:判断数组中所有元素是否都满足指定条件
语法:array.every(callback)
参数:
- callback(必需):回调函数,接收两个参数,第一个是当前元素,第二个是当前元素的下标
返回值:
- true:所有元素都满足条件
- false:至少有一个元素不满足条件
示例:
const arr = [1, 2, 3, 4, 5]
arr.every((item, index)=>{
return item > 0
}) // true
some()
用法:判断数组中是否至少有一个元素满足指定条件
语法:array.some(callback)
参数:
- callback(必需):回调函数,接收两个参数,第一个是当前元素,第二个是当前元素的下标
返回值:
- true:至少有一个元素满足条件
- false:所有元素都不满足条件
示例:
const arr = [1, 2, 3, 4, 5]
arr.some((item, index)=>{
return item > 2
}) // true
includes()
用法:判断数组中是否包含指定元素
语法:array.includes(item, index)
参数:
- item(必需):要查找的元素
- index(可选):开始下标,默认 0
返回值:
- true:数组中包含指定元素
- false:数组中不包含指定元素
示例:
const arr = [1, 2, 3, 4, 5]
arr.includes(3) // true
arr.includes(3, 4) // false
reduce()
用法:将数组中的元素进行累加计算,返回计算结果,从数组的第一项开始累加
语法:array.reduce(callback, initialValue)
参数:
- callback(必需):回调函数,接收四个参数,第一个是累加结果,第二个是当前元素,第三个是当前元素的下标,第四个是数组本身
- initialValue(可选):初始值,默认第一个元素
返回值: 计算结果
示例:
const arr = [1, 2, 3, 4, 5]
arr.reduce((pre, cur, index, a)=>{
return pre + cur
}) // 15
arr.reduce((pre, cur, index, a)=>{
return pre + cur
}, 10) // 25
reduceRight()
用法:将数组中的元素进行累加计算,返回计算结果,从数组的末尾开始累加
语法同 reduce()
find()
用法:查找数组中第一个满足指定条件的元素
语法:array.find(callback)
参数:
- callback(必需):回调函数,接收两个参数,第一个是当前元素,第二个是当前元素的下标,第三个元素是数组本身
返回值:
- 找到的元素:返回该元素
- 未找到的元素:返回 undefined
示例:
const arr = [1, 2, 3, 4, 5]
arr.find((item, index, a)=>{
return item > 2
}) // 3
findIndex()
用法:查找数组中第一个满足指定条件的元素的下标
语法:array.findIndex(callback)
参数:
- callback(必需):回调函数,接收两个参数,第一个是当前元素,第二个是当前元素的下标,第三个元素是数组本身
返回值:
- 找到的元素的下标:返回该元素的下标
- 未找到的元素的下标:返回-1
示例:
const arr = [1, 2, 3, 4, 5]
arr.findIndex((item, index, a)=>{
return item > 2
}) // 2
copyWithin()
用法:浅复制数组的一部分到同一数组中的另一个位置,并返回
注意事项
会改变原数组的内容,但原数组长度不变
语法:array.copyWithin(target, start, end)
参数:
- target(必需):目标位置
- start(可选):开始下标,默认 0
- end(可选):结束下标(不包含),默认到数组最后一个元素
返回值: 数组本身
示例:
const arr = [1, 2, 3, 4, 5]
arr.copyWithin(2, 0, 3) // [1, 2, 1, 2, 3]
flat()
用法:将多维数组扁平化
语法:array.flat(depth)
参数:
- depth(可选):表示要展开的层数,默认1
返回值: 扁平化后的数组
示例:
const arr = [1, 2, [3, 4, [5, 6]]]
arr.flat() // [1, 2, 3, 4, [5, 6]]
arr.flat(2) // [1, 2, 3, 4, 5, 6]
// 使用 Infinity 作为深度,展开任意深度的嵌套数组
arr.flat(Infinity) // [1, 2, 3, 4, 5, 6]
// 利用 flat 去除数组中的空项
const arr2 = [1, 2 , , 4 , 5]
arr2.flat() // [1, 2, 4, 5]
flatMap()
用法:使用映射函数映射每个元素,然后将结果压缩成一个新数组(只会处理一层)
语法:array.flatMap(callback)
参数:
- callback:回调函数,接收两个参数,第一个是当前元素,第二个是当前元素的下标,第三个元素是数组本身
返回值: 处理后的数组
示例:
const arr = [1, 2, 3, 4, 5]
arr.flatMap((item)=>{
return [item, item * 2]
}) // [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
entries()、keys()、values()
用法:遍历数组,返回一个迭代器对象
语法:array.entries()
、array.keys()
、array.values()
返回值:迭代器对象
示例:
const arr = ['a', 'b']
console.log(arr.entries()) // [[0, 'a'], [1, 'b']]
for(let [index, item] of arr.entries()){
console.log(index, item)
}
// 0 a
// 1 b
for(let item of arr.keys()){
console.log(item)
}
// 0
// 1
for(let item of arr.values()){
console.log(item)
}
// a
// b
for…in 和 for…of
两者均可以用来遍历数组或对象
- for…in:遍历的是数组的索引或者对象的 key
- for…of:遍历的是值
Map处理
是 es6 提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是键的范围不仅限于字符串,各种类型的值都可以
当做键键值对结构,键值对的插入顺序与添加顺序一致,如果后续添加的key重复,则会覆盖原有的值
创建
- 带值的初始化:
const map = new Map([['name', 'Bob'], ['age', 12]])
- 初始化:
const map = new Map()
map.set('name', 'Bob')
map.set('age', 12)
属性
size: 成员数量
const map = new Map()
map.size // 0
map.set('name', 'Bob')
map.size // 1
实例方法
- get():获取指定 key 对应的 value
const map = new Map()
map.set('name', 'Bob')
map.set('age', 12)
map.get('name') // Bob
- has():判断是否存在指定 key
const map = new Map()
map.has('name') // false
map.set('name', 'Bob')
map.has('name') // true
- clear():清空所有元素
const map = new Map()
map.set('name', 'Bob')
map.set('age', 12)
map.clear()
map.size // 0
- delete():删除指定 key 对应的 value
const map = new Map()
map.set('name', 'Bob')
map.set('age', 12)
map.delete('name')
map.size // 1
遍历
for…of循环
keys()、values()、entries()
与 Object 的区别
-
使用 Map:
- 储存的键不是字符串/数字/或者 Symbol 时,选择 Map,因为 Object 并不支持
- 储存大量的数据时,选择 Map,因为它占用的内存更小
- 需要进行许多新增/删除元素的操作时,选择 Map,因为速度更快
- 需要保持插入时的顺序的话,选择 Map,因为 Object 会改变排序
- 需要迭代/遍历的话,选择 Map,因为它默认是可迭代对象,迭代更为便捷
-
使用 Object:
- 只是简单的数据结构时,选择 Object,因为它在数据少的时候占用内存更少,且新建时更为高效
- 需要用到 JSON 进行文件传输时,选择 Object,因为 JSON 不默认支持 Map
- 需要对多个键值进行运算时,选择 Object,因为句法更为简洁
- 需要覆盖原型上的键时,选择 Object
Set 处理
类似数组,但是没有重复的值,并且无序
创建
- 带值的初始化:
const set = new Set([1, 2, 3])
- 初始化:
const set = new Set()
set.add(1)
set.add(2)
set.add(3)
属性
size: 成员数量
const set = new Set()
set.size // 0
set.add(1)
set.size // 1
实例方法
- add():添加元素
const set = new Set()
set.add(1)
set.add(2).add(3)
- delete():删除元素
const set = new Set()
set.add(1)
set.delete(1) // true
- has():判断是否存在指定元素
const set = new Set()
set.add(1)
set.has(1) // true
- clear():清空所有元素
const set = new Set()
set.add(1)
set.clear()
set.size // 0
call()、apply()、bind()
都是用于改变函数的this指向,不同点在于传参方式以及返回值不同
注意事项
若不向方法的第一个参数传值或者传递 undefined、null,则在 JavaScript 正常模式下,目标函数内部的 this 指向 window 对象,严格模式下,分别指向 undefined、null
call()
语法:函数名.call(param1, param2, ...paramN)
参数:
- param1:this 要指向的对象
- param2~paramN:函数所需要的参数
返回值:返回调用函数的返回结果,属于立即执行函数
//此处声明若用 let,则第一个调用函数输出 undefined,
//因为此处 let 声明的变量虽然也是全局变量但其不会成为全局对象 window 的属性,故 say() 直接调用时为undefined
var word = "我是window";
function say(params1,params2){
console.log(params1+" "+params2+","+this.word)
}
let obj = {
word: "我是obj"
}
let newObj= {
word: "我是newObj"
}
say("Hi","friend"); // Hi friend,我是我是window // let声明 则输出:Hi friend,undefined
say.call(obj,"Hi","friend") // Hi friend,我是obj
say.apply(newObj,["Hi","friend"]) // Hi friend,我是newObj
apply()
语法:函数名.apply(param1, param2)
参数:
- param1:this 要指向的对象
- param2:函数所需要的参数组成的数组
返回值:返回调用函数的返回结果,属于立即执行函数
//此处声明若用 let,则第一个调用函数输出 undefined,
//因为此处 let 声明的变量虽然也是全局变量但其不会成为全局对象 window 的属性,故 say() 直接调用时为undefined
var word = "我是window";
function say(params1,params2){
console.log(params1+" "+params2+","+this.word)
}
let obj = {
word: "我是obj"
}
let newObj= {
word: "我是newObj"
}
say("Hi","friend"); // Hi friend,我是我是window // let声明 则输出:Hi friend,undefined
say.call(obj,"Hi","friend") // Hi friend,我是obj
say.apply(newObj,["Hi","friend"]) // Hi friend,我是newObj
bind()
语法:函数名.bind(param1, param2, ...paramN)
参数:
- param1:this 要指向的对象
- param2~paramN:函数所需要的参数
返回值:返回新的函数
var word = "我是window";
function say(params1,params2){
console.log(params1+" "+params2+","+this.word)
}
let Obj1= {
word: "我是newObj1"
}
let Obj2= {
word: "我是newObj2"
}
//返回一个新的函数
let newFunc = say.bind(Obj1,"hello","friend");
newFunc() // hello friend,我是 newObj1
// 可将其改为立即执行函数,此时返回和call(),apply()相同
say.bind(Obj2,"hello","friend")(); // hello friend,我是 newObj2
let、var
相同点
两者都是声明变量的,其中let是es6中出现的
不同点
-
作用域不同
- var:函数作用域+全局作用域
- let: 块级作用域(es6 新增)
-
let 不能在定义之前访问,但 var 可以(因为var有变量提升,也就是预解析)
console.log(a) // 预解析只声明不复制 undefined var a = 10 // var 后面的变量,变量提升了(也就是预解析了) console.log(a) // 10 console.log(b) // 报错(Uncaught ReferenceError: Cannot access 'b' before initialization),let声明的变量不能在定义(初始化)之前访问 let b = 20
-
let不能被重新定义,但var可以
let a = 10 let a = "你好" // 报错(Uncaught SyntaxError: Identifier 'a' has already been declared)let后面的变量不能重新定义,var可以 console.log(a) var b = 10 var b = "你好" console.log(b)
js中的原型和原型链
// 定义函数对象(也就是构造函数)
function Person(name, age){
this.name = name;
this.age = age;
this.eat = function(food){
console.log(`${this.name}在吃${food}`);
}
}
// 通过原型对象 prototype 给 Person 类添加属性和方法
Person.prototype.city = '中国'
Person.prototype.sleep = function(){
console.log(`${this.name}正在睡觉`)
}
// 定义实例对象(一个普通对象)
let person = new Person('张三', 18);
person.sleep(); // 张三正在睡觉
person.eat('苹果'); // 张三在吃苹果
person.city; // 中国
-
prototype
定义:每个函数都有一个 prototype 属性,被称作原型,prototype 原型指向一个对象,所以也被称为原型对象只有函数对象才会拥有该属性,原型对象(Person.prototype)是构造函数(Person)的一个实例
-
__proto__
JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做
__proto__
的内置属性,用于指向创建它的构
造函数的原型对象
Person.prototype.constructor === Person // true
person.constructor === Person // true
person.__proto__ === Person.prototype // true
person.__proto__.__proto__ === Object.prototype // true
// 以下三个成立,是因为 Person、Object、Function 都是函数对象,是通过 new Function() 创建的
// 其中 Function 比较特殊,自己创建自己
Person.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
Person.prototype.__proto__ === Object.prototype // true
Function.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__ === null // true 原型链的尽头是 null
原型链原理:
- 当我查找 person 实例的 city 属性时,会先再这个person对象本身属性上查找,如果没有找到,就去
person.__proto__
上找(也就是Person.prototype
原型对象),直到最顶层Object.prototype.__proto__
为null
时停止 - 如果对象自身和它的原型都定义了同一个属性名,那么优先读取对象自身的属性,这叫做“覆盖”
总结:
- 原型和原型链是 JS 实现继承的一种模型
- 原型链的形成是真正是靠
__proto__
而非prototype