2022.3.10
1.数组是特殊的对象
2.数组与对象的区别:
数组使用数字索引,对象使用命名索引
3.数组的创建:
let arr=[];
let arr2=new Array();
new 关键词只会使代码复杂化。它还会产生某些不可预期的结果:
var points = new Array(40, 100); // 创建包含两个元素的数组(40 和 100)
假如删除其中一个元素会怎么样?
var points = new Array(40); // 创建包含 40 个未定义元素的数组!!!
4.数组,添加数据的方法:
push、unshift 、length
5.识别数组的方式:
1)运算符 typeof 返回 "object"
2)ECMAScript 5 定义了新方法 Array.isArray()============>此方案的问题在于 ECMAScript 5 不支持老的浏览器。
3)创建您自己的 isArray() 函数以解决此问题:
function isArray(x) {
return x.constructor.toString().indexOf("Array") > -1;
}
假如对象原型包含单词 "Array" 则返回 true。
4)假如对象由给定的构造器创建,则 instanceof 运算符返回 true:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits instanceof Array // 返回 true
2022.3.11
数组方法:
1.转字符串
1).JavaScript 方法 toString() 把数组转换为数组值(逗号分隔)的字符串
var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits.toString();
Banana,Orange,Apple,Mango //结果
2)join() 方法也可将所有数组元素结合为一个字符串,它的行为类似 toString(),但是您还可以规定分隔符
var fruits = ["Banana", "Orange","Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits.join(" * ");
Banana * Orange * Apple * Mango //结果
2.添加
1)首端
unshift() 方法(在开头)向数组添加新元素,并“反向位移”旧元素
unshift() 方法返回新数组的长度。
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon"); // 返回 5
2)末端
push() 方法(在数组结尾处)向数组添加一个新的元素:
push() 方法返回新数组的长度:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi"); // 向 fruits 添加一个新元素
shift() 方法返回被“位移出”的字符串
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.shift(); // 返回 "Banana"
length 属性提供了向数组追加新元素的简易方法
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits[fruits.length] = "Kiwi"; // 向 fruits 追加 "Kiwi"
console.log(fruits) //['Banana', 'Orange', 'Apple', 'Mango', 'Kiwi']
3.删除
1)首端
shift() 方法会删除首个数组元素,并把所有其他元素“位移”到更低的索引。
2)末端
pop() 方法从数组中删除最后一个元素
pop() 方法返回“被弹出”的值:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var x = fruits.pop(); // x 的值是 "Mango"
既然 JavaScript 数组属于对象,其中的元素就可以使用 JavaScript delete 运算符来删除
var fruits = ["Banana", "Orange", "Apple", "Mango"];
delete fruits[0]; // 把 fruits 中的首个元素改为 undefined
使用 splice() 来删除元素
第一个参数(0)定义新元素应该被添加(接入)的位置。
第二个参数(1)定义应该删除多个元素。
其余参数被省略。没有新元素将被添加。
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(0, 1); // 删除 fruits 中的第一个元素
console.log(fruits ) // ['Orange', 'Apple', 'Mango']
4.更改元素
通过使用它们的索引号来访问数组元素:
数组索引(下标)以 0 开始。[0] 是第一个数组元素,[1] 是第二个,[2] 是第三个 ..
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits[0] = "Kiwi"; // 把 fruits 的第一个元素改为 "Kiwi"
(4) [empty, 'Orange', 'Apple', 'Mango']1: "Orange"2: "Apple"3: "Mango"length: 4[[Prototype]]: Array(0)
5.拼接数组
splice() 方法可用于向数组添加新项
第一个参数(2)定义了应添加新元素的位置(拼接)。
第二个参数(0)定义应删除多少元素。
其余参数(“Lemon”,“Kiwi”)定义要添加的新元素。
splice() 方法返回一个包含已删除项的数组
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 0, "Lemon", "Kiwi");
console.log(fruits ) // ['Banana', 'Orange', 'Lemon', 'Kiwi', 'Apple', 'Mango']
6.合并(连接)数组
concat() 方法通过合并(连接)现有数组来创建一个新数组
合并两个
var myGirls = ["Cecilie", "Lone"];
var myBoys = ["Emil", "Tobias", "Linus"];
var myChildren = myGirls.concat(myBoys); // 连接 myGirls 和 myBoys // 删除 fruits 中的第一个元素
console.log(myChildren ) // ['Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus']
concat() 方法不会更改现有数组。它总是返回一个新数组。
合并三个
var arr1 = ["Cecilie", "Lone"];
var arr2 = ["Emil", "Tobias", "Linus"];
var arr3 = ["Robin", "Morgan"];
var myChildren = arr1.concat(arr2, arr3); // 将arr1、arr2 与 arr3 连接在一起
console.log(myChildren ) // ['Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus', 'Robin', 'Morgan']
concat() 方法也可以将值作为参数
var arr1 = ["Cecilie", "Lone"];
var myChildren = arr1.concat(["Emil", "Tobias", "Linus"]);
console.log(myChildren ) //['Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus']
7.裁剪数组
slice() 方法用数组的某个片段切出新数组。
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1);
console.log(citrus ) //['Orange', 'Lemon', 'Apple', 'Mango']
slice() 可接受两个参数,比如 (1, 3)。
该方法会从开始参数选取元素,直到结束参数(不包括)为止。
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1, 3);
console.log(citrus ) // ['Orange', 'Lemon']
如果结束参数被省略,比如第一个例子,则 slice() 会切出数组的剩余部分。
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(2);
console.log(citrus ) // ['Lemon', 'Apple', 'Mango']
8.自动 toString()
如果需要原始值,则 JavaScript 会自动把数组转换为字符串。下面两个例子将产生相同的结果:
方法1:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits.toString();
方法2:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits;
结果均为:Banana,Orange,Apple,Mango
2022.3.12
数组排序
1)sort() 方法以字母顺序对数组进行排序:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort(); // 对 fruits 中的元素进行排序
console.log(fruits)
// 0: "Apple"
// 1: "Banana"
// 2: "Mango"
// 3: "Orange"
2)数字排序
默认地,sort() 函数按照字符串顺序对值进行排序。
该函数很适合字符串("Apple" 会排在 "Banana" 之前)。
不过,如果数字按照字符串来排序,则 "25" 大于 "100",因为 "2" 大于 "1"。
正因如此,sort() 方法在对数值排序时会产生不正确的结果。
我们通过一个比值函数来修正此问题
补充:
比较函数的目的是定义另一种排序顺序。
比较函数应该返回一个负,零或正值,这取决于参数
function(a, b){return a-b}
当 sort() 函数比较两个值时,会将值发送到比较函数,并根据所返回的值(负、零或正值)对这些值进行排序。
反转数组
reverse() 方法反转数组中的元素。
您可以使用它以降序对数组进行排序
var fruits = ["Banana", "Orange", "Apple", "Mango"];
let aa=fruits.sort();
console.log(aa) //['Apple', 'Banana', 'Mango', 'Orange']
let bb=aa.reverse();
console.log(bb) //['Orange', 'Mango', 'Banana', 'Apple']
3)以随机顺序排序数组
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return 0.5 - Math.random()});
查找最高、最低值
对数组使用Math.max()
您可以使用 Math.max.apply 来查找数组中的最高值
let arr=[1,4,9,45,23]
function myArrayMax(arr) {
return Math.max.apply(null, arr);
}
console.log(myArrayMax(arr)) //45
Math.max.apply([1, 2, 3]) 等于 Math.max(1, 2, 3)
对数组使用Math.min()
您可以使用 Math.min.apply 来查找数组中的最低值
let arr=[1,4,9,45,23]
function myArrayMin(arr) {
return Math.min.apply(null, arr);
}
console.log(myArrayMin(arr)) //1
Math.min.apply([1, 2, 3]) 等于 Math.min(1, 2, 3)。
自制Min/Max js方法实现值的查找
排序对象数组
即使对象拥有不同数据类型的属性,sort() 方法仍可用于对数组进行排序。
解决方法是通过比较函数来对比属性值:
cars.sort(function(a, b){return a.year - b.year});
var cars = [
{type:"Volvo", year:2016},
{type:"Saab", year:2001},
{type:"BMW", year:2010}];
let res=cars.sort(function(a, b){
var x = a.type.toLowerCase();
var y = b.type.toLowerCase();
if (x < y) {return -1;}
if (x > y) {return 1;}
return 0;
});
console.log(res)
结果:
2022.2.13
数组迭代
1.Array.forEach()
forEach() 方法为每个数组元素调用一次函数(回调函数)。
注释:该函数接受 3 个参数:
- 项目值
- 项目索引
- 数组本身
所有浏览器都支持 Array.forEach(),除了 Internet Explorer 8 或更早的版本:
2.Array.map()
map() 方法通过对每个数组元素执行函数来创建新数组。
map() 方法不会对没有值的数组元素执行函数。
map() 方法不会更改原始数组。
请注意,该函数有 3 个参数:
- 项目值
- 项目索引
- 数组本身
所有浏览器都支持 Array.map(),除了 Internet Explorer 8 或更早的版本:
3.Array.filter()
filter() 方法创建一个包含通过测试的数组元素的新数组。
请注意此函数接受 3 个参数:
- 项目值
- 项目索引
- 数组本身
所有浏览器都支持 Array.filter(),除了 Internet Explorer 8 或更早的版本:
4.Array.reduce()
reduce() 方法在每个数组元素上运行函数,以生成(减少它)单个值。
reduce() 方法在数组中从左到右工作。另请参阅 reduceRight()。
reduce() 方法不会减少原始数组
请注意此函数接受 4 个参数:
- 总数(初始值/先前返回的值)
- 项目值
- 项目索引
- 数组本身
var numbers1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduce(myFunction);
function myFunction(total, value, index, array) {
console.log(total, value, index, array)
return total + value;
}
所有浏览器都支持 Array.reduce(),除了 Internet Explorer 8 或更早的版本:
5.Array.reduceRight()
reduceRight() 方法在每个数组元素上运行函数,以生成(减少它)单个值。
reduceRight() 方法在数组中从右到左工作。另请参阅 reduce()。
reduceRight() 方法不会减少原始数组。
var numbers1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduceRight(myFunction);
function myFunction(total, value, index, array) {
console.log(total, value, index, array)
return total + value;
}
请注意此函数接受 4 个参数:
- 总数(初始值/先前返回的值)
- 项目值
- 项目索引
- 数组本身
所有浏览器都支持 Array.reduceRight(),除了 Internet Explorer 8 或更早的版本:
6.Array.every()
every() 方法检查所有数组值是否通过测试。
var numbers = [45, 4, 9, 16, 25];
var allOver18 = numbers.every(myFunction);
function myFunction(value, index, array) {
return value > 18;
}
console.log(allOver18) //false
请注意此函数接受 3 个参数:
- 项目值
- 项目索引
- 数组本身
所有浏览器都支持 Array.every(),除了 Internet Explorer 8 或更早的版本:
7.Array.some()
some() 方法检查某些数组值是否通过了测试。
var numbers = [45, 4, 9, 16, 25];
var numbers = [45, 4, 9, 16, 25];
var someOver18 = numbers.some(myFunction);
function myFunction(value, index, array) {
return value > 18;
}
console.log( someOver18) //true
请注意此函数接受 3 个参数:
- 项目值
- 项目索引
- 数组本身
所有浏览器都支持 Array.some(),除了 Internet Explorer 8 或更早的版本:
8.Array.indexOf()
indexOf() 方法在数组中搜索元素值并返回其位置;
如果未找到项目,Array.indexOf() 返回 -1。
如果项目多次出现,则返回第一次出现的位置。
array.indexOf(item, start)
item | 必需。要检索的项目。 |
start | 可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到结尾。 |
var fruits = ["Apple", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple");
var b=fruits.indexOf("ff");
console.log( a) //0
console.log(b) //-1
所有浏览器都支持 Array.indexOf(),除了 Internet Explorer 8 或更早的版本:
9.Array.lastIndexOf()
array.lastIndexOf(item, start)
item | 必需。要检索的项目。 |
start | 可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到开头。 |
Array.lastIndexOf() 与 Array.indexOf() 类似,但是从数组结尾开始搜索。
var fruits = ["Apple", "Orange", "Apple", "Mango"];
var a = fruits.lastIndexOf("Apple");
var b=fruits.lastIndexOf("frffg")
console.log( a) //2
console.log(b) //-1
10.Array.find()
find() 方法返回通过测试函数的第一个数组元素的值。
var numbers = [4, 9, 16, 25, 29];
var first = numbers.find(myFunction);
function myFunction(value, index, array) {
return value > 18;
}
console.log(first) //25
请注意此函数接受 3 个参数:
- 项目值
- 项目索引
- 数组本身
老旧的浏览器不支持 Array.find()。下面列出了完全支持此方法的首个浏览器版本:
11.Array.findIndex()
老旧的浏览器不支持 Array.findIndex()。下面列出了完全支持此方法的首个浏览器版本:
findIndex() 方法返回通过测试函数的第一个数组元素的索引。
var numbers = [4, 9, 16, 25, 29];
var first = numbers.findIndex(myFunction);
function myFunction(value, index, array) {
return value > 18;
}
console.log(first) //3
2022.3.14
ES6常用语法和方法总结
字符串扩展
1.at()
// 参数传入角标,返回值为角标对应的字符
let a='abc'.at(0)
let b='吉塔'.at(1)
console.log(a) //'a'
console.log(b) // '塔'
// 与ES5中charAt()不同之处,汉字的话ES5会返回对应Unicode编码,js内部用UTF-16
2.includes(), startsWith(), endsWith()
- includes(),返回值为布尔值,表示是否找到参数的字符串
- startsWith(),返回值为布尔值,表示参数字符串是否在原字符串的头部
- endsWith(),返回布尔值,表示参数字符串是否在原字符串的尾部
- 这三个方法都支持第二个参数,表示开始搜索的位置。endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束
let str = 'Hello World'
str.includes('Hello') // true
str.startsWith('Hello') // true
str.endsWith('d') // true
str.startsWith('world', 6) // true
str.endsWith('Hello', 5) // true
str.includes('Hello', 6) // false
3.repeat()
'x'.repeat(3) // "xxx"
注意:参数不能传负数和Infinity,参数NaN为0,参数为字符串会先转换为数字
4.padStart(),padEnd()
参数两个,第一个为位数,第二个是用什么补全,省略第二个参数时默认为空格补全。这两个更多的用途是补全指定位数
let a='1'.padStart(10, '0')
let b='12'.padStart(10, '0')
let c='123456'.padEnd(10, '0')
console.log(a) // "0000000001"
console.log(b) // "0000000012"
console.log(c) // "1234560000"
数组扩展
1.Array.from()
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
2....运算符
扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
- 关于函数传参的问题,如果函数直接用...传参,传入的参数实际上是个数组,且后面不能再有参数。如果函数参数定义了一个数组,用...传入,实际上参数为数组中的值
function fn(...items){}
//等同于
function fn([数组内容]){}
let items = ['a', 'b', 'c']
function fn(...items){}
// 等同于
function fn('a', 'b', 'c') {}
3. ...运算符的应用
- 复制数组(克隆数组)
let arr1 = [1, 2, 3]
let arr2 = [...arr1] // [1, 2, 3]
- 合并数组
const arr1 = ['a', 'b']
const arr2 = ['c']
const arr3 = ['d', 'e']
const arr4 = [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
- 与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
- 将字符串转换为真正的数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]
4. Array.of(), 用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
5. 数组实例的fill()
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
6.数组实例的 entries(),keys() 和 values()
三个方法都是遍历数组,都可以用for...of...唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
对象扩展
对象的话,解构赋值就不说了太基础了,我用的最多的就是...运算符和Object.assgin(),好吧,实际上...底层的方法就是assign()
Symbol
js数据类型除了string,number,boolean,undefined,null,object,第七种为symbol,他的作用就是防止定义变量时出现重复的定义导致覆盖的一些问题。
Set和Map结构
-
Set
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成Set数据结构。此结构不会添加重复的值(你想到了什么,一定想到了数组去重)
// 例一 const set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4] // 例二 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.size // 5 // 例三 数组去重 [...new Set(array)]
-
Map
这个结构我个人感觉不如对象好用,没用过。实际上Map结构就是键值对的结构,里面设置和获取分别用set和get方法,我要设置的话每次都set一下,我觉得很不方便
Proxy拦截
1.基本说明
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。get()方法
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
2. get()方法
get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(即this关键字指向的那个对象),其中最后一个参数可选。
var person = {
name: "张三"
};
var proxy = new Proxy(person, {
get: function(target, property) {
if (property in target) {
return target[property];
} else {
throw new ReferenceError("Property \"" + property + "\" does not exist.");
}
}
});
proxy.name // "张三"
proxy.age // 抛出一个错误
3.set()方法
set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// 对于满足条件的 age 属性以及其他属性,直接保存
obj[prop] = value;
}
};
let person = new Proxy({}, validator);
person.age = 100;
person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错
async和await
1.基本说明
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
2. await命令
正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
async function f() {
return await 123;
}
f().then(v => console.log(v))
// 123
class类
1.constructor()
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
class Point {
}
// 等同于
class Point {
constructor() {}
}
2.类继承中的super()
如果你要用类继承的话,里面一定要写super(),他是指定父类的this的,否则会报错
class A {}
class B extends A {
constructor() {
super();
}
}
浏览器加载
1.defer和async
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
defer与async的区别是:defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。
2.ES6的新语法
浏览器加载 ES6 模块,也使用<script>标签,但是要加入type="module"属性。浏览器对于带有type="module"的<script>,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>标签的defer属性。
<script type="module" src="./foo.js"></script>
- ES6 模块也允许内嵌在网页中,语法行为与加载外部脚本完全一致。
<script type="module">
import utils from "./utils.js";
// other code
</script>
对于外部的模块脚本(上例是foo.js),有几点需要注意。
- 代码是在模块作用域之中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。
- 模块脚本自动采用严格模式,不管有没有声明use strict。
- 模块之中,可以使用import命令加载其他模块(.js后缀不可省略,需要提供绝对 URL 或相对 URL),也可以使用export命令输出对外接口。
- 模块之中,顶层的this关键字返回undefined,而不是指向window。也就是说,在模块顶层使用this关键字,是无意义的。
- 同一个模块如果加载多次,将只执行一次。