这是我参与「第四届青训营 」笔记创作活动的第2天
js高级
函数进阶
函数提升
函数提升与变量提升比较类似,是指函数在声明之前即可被调用 函数表达式不存在提升的现象
函数参数
动态参数
arguments 是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
- arguments 是一个伪数组,只存在于函数中
- arguments 的作用是动态获取函数的实参
- 可以通过for循环依次得到传递过来的实参
剩余参数
... 是其语法符号,置于最末函数形参之前,用于获取多余的实参 借助 ... 获取的剩余实参,是个真数组
function fn(a, b, ...arr) {
console.log(arr) //[3,4,5]
}
fn(1, 2, 3, 4, 5)
箭头函数
箭头函数没有 arguments 动态参数,但是有 剩余参数 ..args 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this
const user = {
name: '小明',
sleep: function() {
console.log(this) //指向 user
const fn = () => {
console.log(this) //也指向 user
}
fn()
}
}
user.sleep()
解构赋值
数组解构
- 赋值运算符 = 左侧的 [] 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量
- 数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法
- 变量的顺序对应数组单元值的位置依次进行赋值操作
const [max, min, avg] = [100, 60, 80]
console.log(max) //100
console.log(min) //60
console.log(avg) //80
//交换两个变量的值
let a = 1
let b = 3
[b,a] = [a,b]
1.利用剩余参数解决变量少 单元值多的情况:
const [a, ...tel] = ['小米', '华为', '苹果']
console.log(a) //小米
console.log(tel) //['华为', '苹果']
2.防止有undefined传递单元值的情况,可以设置默认值
const [a = '手机', b = '华为'] = ['小米']
console.log(a) // 小米
console.log(b) // 华为
3.多维数组解构
const [a, b] = [1, [2, 3]]
console.log(a) //1
console.log(b) //[2,3]
const [a, [b,c]] = [1, [2, 3]]
console.log(a) //1
console.log(b) //2
console.log(c) //3
对象解构
- 赋值运算符 = 左侧的 {} 用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量
- 对象属性的值将被赋值给与属性名相同的变量
- 注意解构的变量名不要和外面的变量名冲突否则报错
- 对象中找不到与变量名一致的属性时变量值为 undefined
1.给新的变量名赋值
const user = {
name: '小明',
age: 18
}
const {name: uname, age} = user
console.log(uname) //小明
console.log(age) //18
2.数组对象解构
const user = [{
name: '小明',
age: 18
}]
const [{ name,age}] = user
console.log(name) //小明
console.log(age) //18
多级对象解构
const user = [{
name: '小明',
family: {
mother: '小红',
father: '小马'
},
age: 18
}]
const [{name,family: {mother,father}}] = user
console.log(name) //小明
console.log(mother) //小红
console.log(father) //小马
代码前面加分号
如果一行代码是以 (、[、` 这三种情况开头的,则最好都在其前面补上一个分号。
深入对象
构造函数
- 函数命名以大写开头
- 构造函数的作用是快速创建多个类似的对象
- 使用 new 关键字调用函数的行为被称为实例化
- 构造函数内部无需写return,返回值即为新创建的对象
- 构造函数实例创建的对象彼此独立、互不影响
- new Object() new Date() 也是实例化构造函数
//创造构造函数
function Phone(name, price) {
this.name = name
this.price = price
}
//new 关键词调用构造函数
const apple = new Phone('苹果', 8999)
console.log(apple) //{name: '苹果', price: 8999}
实例成员和静态成员
- 通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员
- 构造函数的属性和方法被称为静态成员
- 一般公共特征的属性或方法静态成员设置为静态成员
function Person(name, age) {
//实例成员
this.name = name
this.age = age
}
//静态成员
Person.eyes = 2
Person.arms = 2
Person.walk = function() {
console.log('人都会走路')
}
原型
- 利用原型对象实现方法共享
- 构造函数通过原型分配的函数是所有对象所共享的
- 每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象
- 这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存
- 我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法
内置构造函数
Object
1.Object.keys
Object.keys 静态方法获取对象中所有属性(键)
const phone = {name: 'apple',price: 8999}
//获得对象的所有键,返回值是一个数组
const arr = Object.keys(phone)
console.log(arr) //['name','price']
2.Object.values
Object.values 静态方法获取对象中所有属性值
const phone = {name: 'apple',price: 8999}
//获得对象的所有值,返回值是一个数组
const arr = Object.values(phone)
console.log(arr) //['apple',8999]
3.Object. assign
Object. assign 静态方法常用于对象拷贝,给对象添加属性
const phone = {name: 'apple',price: 8999}
Object.assign(phone, {px: 6.2})
const obj = {}
Object.assign(obj, phone)
console.log(obj) //{name: 'apple',price: 8999,px:6.2}
Array
展开运算符
展开运算符(…),将一个数组进行展开 典型运用场景: 求数组最大值(最小值)、合并数组、复制数组等 扩展运算符(...)也可以将部署了 Iterator 接口的数据结构转为数组 1.合并数组
const arr1 = [1, 2, 3]
console.log(...arr1)//1,2,3
const arr2 = [4, 5]
arr3 = [...arr1, ...arr2]
console.log(arr3) //[1,2,3,4,5]
arr1.push(...arr2)//[1,2,3,4,5]
2.复制数组
通过展开运算符复制数组
const a1 = [1, 2];
const a2 = a1;
a2[0] = 2;
a1 // [2,2]
const arr2 = [...arr1] //通过这种方法复制数组从而使得修改arr4不会对arr1产生影响
3.与字符串结合
扩展运算符还可以将字符串转为真正的数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]
4.实现了 Iterator 接口的对象
任何定义了遍历器(Iterator)接口的对象(字符串)都可以用扩展运算符转为真正的数组
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
Array.from()
- Array.from()可以将类似数组的对象(有length属性)和可遍历(iterable)的对象转换为真正的数组
- 其还可以接受一个函数成为第二个参数,用来对每个元素进行处理
let spans = document.querySelectorAll('span.name');
let names1 = Array.from(spans, s => s.textContent)
Array.of()
用于将一组值转换为数组,弥补Array()因参数个数不同而行为不同
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array(3) //[,,,]
join()
将数组转换成字符串,只接受一个参数(得到的字符串以该符号分隔) 不改变原数组
console.log([1, 2, 3].join('')) //1,2,3
console.log([1, 2, 3].join('\\')) //1\2\3
sort()
对数组的元素进行排序,且改变原数组 sort() 不按照数组元素数值的大小对数字进行排序,是按照字符编码的顺序进行排序
[9, 80].sort() //[80,9]
const arr = [2, 4, 3, 1]
const arr1 = [...arr].sort((a, b) => a - b)//按小到大排序
const arr2 = [...arr].sort((a, b) => b - a)//按大到小排序
console.log(arr1) // [1, 2, 3, 4]
console.log(arr2) // [4, 3, 2, 1]
reverse()
颠倒数组中元素的顺序,且改变原数组
const arr = [2, 4, 3, 1]
console.log(arr.reverse()) // [1, 3, 4, 2]
console.log(arr) // [1, 3, 4, 2]
push() & unshift()
push() 向数组的末尾添加一个或多个元素,并返回新的长度 unshift() 向数组的开头添加一个或多个元素,并返回新的长度 改变原数组
const arr = [1, 2, 3]
console.log(arr.push(4, 5)) //5
arr.unshift(6, 7)
console.log(arr) //[6,7,1,2,3,4,5]
shift() & pop()
shift() 从数组中删除第一个元素,并返回该元素的值 pop() 从数组中删除最后一个元素,并返回该元素的值 改变原数组
const arr = [6,7,1,2,3,4,5]
console.log(arr.shift()) //6
console.log(arr.pop()) // 5
console.log(arr) //[7,1,2,3,4]
slice()
slice([start], [end]) 从start处开始选取,从end处结束选取,索引从0开始,包括 begin,不包括end,不改变原数组
const arr = [1, 2, 3, 4, 5]
console.log(arr.slice(0, 2)) //[1,2]
console.log(arr.slice()) //[1,2,3,4,5]
console.log(arr.slice(3)) //[4,5]
console.log(arr.slice(1, -2)) //[2,3]
console.log(arr.slice(1, -5)) //[]
splice()
splice(start, [deleteCount], [item1,item2,...]) start 代表添加/删除元素的起始位置, deleteCount 代表删除元素的个数,item代表要插入的元素 返回值:由被删除的元素组成的一个数组
const arr = [1, 2, 3]
const arr1 = [1, 2, 3]
console.log(arr.splice(2, 0, 4)) //[]
console.log(arr) // [1,2,4,3]
console.log(arr1.splice(0, 2, 4)) //[1,2]
console.log(arr1) // [4,3]
forEach
数组内置的方法参数为函数的情况下,其return语句不可作为外层函数的返回语句
- forEach(callback(curretvalue, [index], [arr]),[this])
- forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数,无返回值
- 主要使用场景: 遍历数组的每个元素
被遍历的数组.forEach((当前数组元素,当前元素索引号)=>{
函数体
})
const arr = ['pink', 'blue', 'red']
arr.forEach((item, index) => {
console.log(`第${index+1}个元素是${item}`)
})
filter()
find(callback(element, [index], [arr]) , [this]) 返回值:新数组 通过回调函数对数组进行测试(用于比较),测试通过的形成一个新数组
const arr = [2, 4, 5]
arr.filter((e) => {
return e > 3 //[4,5]
})
map()
map(callback(curretvalue, [index], [arr]),[this]) map() 方法创建一个新数组,这个数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
const arr = [2, 4, 5]
arr.map((e) => {
return e > 3 //[false, true, true]
})
arr.map((e) => {
return e + 3 //[5, 7, 8]
})
reduce()
reduce(callback(total, cur, [index], [arr]) , [initialValue]) initialValue为传递给函数的初始值 对数组中所有项进行迭代计算,每一次计算完都会将值返回给total
const arr = [1,2,3]
arr.reduce((total, cur) => {
return total + cur * 10 //70
}, 10)
some()
some(callback(element, [index], [arr]) , [this]) 数组中有至少一个元素通过回调函数的测试就会返回true;所有元素都没有通过回调函数的测试返回值才会为 false
const arr = [2, 4, 5]
arr.some(e => e > 4) //ture
arr.some(e => e > 6) //false
every()
every(callback(element, [index], [arr]) , [this]) 数组中有所有元素都通过回调函数的测试才会返回true,否则返回false
const arr = [2, 4, 5]
arr.every(e => e > 1) //ture
arr.every(e => e > 2) //false
find() , findIndex()
find(callback(value, [index], [arr]) , [this]) 第一个参数是一个回调函数,第二个参数是指代回调函数中的this指向
const people = {
name: 'casual',
age: 18
}
const a = [6, 8, 20, 2].find(function(value) {
return value > this.age
}, people)
const b = [6, 8, 20, 2].findIndex(function(value) {
return value > this.age
}, people)
console.log(a) //20
console.log(b) //2
findIndex()方法的用法与find()方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
fill()
fill(value, [start], [end]) 返回值:新数组 用一个固定值填充一个数组中从初始索引到终止索引里的全部元素,不包括终止索引
const arr = [2, 4, 5]
console.log(arr.fill(7, 1, 2)) //[2,7,5]
includes()
includes(searchElement , [fromIndex]) fromIndex:从该索引处开始查找 searchElement,如果为负值,就从arr.length + formIndex处开始搜索 用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
数组遍历
keys(), value(), entries() keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
const arr = [2, 9]
for (let index of arr.keys()) {
console.log(index) //0,1
}
for (let value of arr.values()) {
console.log(value) //2,9
}
for (let entries of arr.entries()) {
console.log(entries)
//[0,2]
//[1,9]
}