数组
数组很简单,其实没什么好说的,只要了解下常用的API使用就行了
创建数组
js 里有两种创建数组的方式
使用数组字面量创建数组
let myArray = [1, 2, 3, 4, 5];
使用Array构造函数创建数组
let anotherArray = new Array(1, 2, 3, 4, 5);
数组遍历的方法
for 循环:
这种是最基础的写法,没啥好说的
let myArray = [1, 2, 3, 4, 5];
for (let i = 0; i < myArray.length; i++) {
console.log(myArray[i])
}
forEach 方法:
可以传递一个回调函数作为参数,该函数将在数组的每个元素上调用。这个回调函数可以接受三个参数:当前元素、当前索引和数组本身。
let myArray = [1, 2, 3, 4, 5];
// 使用 forEach 遍历数组
myArray.forEach((element, index, array) => {
// element: 当前元素的值
// index: 当前元素的索引
// array: 原始数组
// 在这里执行对每个元素的操作
console.log(`Element at index ${index}: ${element}`);
});
for...of 循环:
for...of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
element 可被修改,不想被修改就用 const 定义
let myArray = [1, 2, 3, 4, 5];
for (const element of myArray) {
// 处理每个元素
console.log(element)
}
map 方法:
遍历数组的每个元素,并对每个元素执行提供的回调函数,最终返回一个新数组,该数组包含对原始数组中的每个元素应用回调函数后的结果。以下是 map
方法的详细用法:
let originalArray = [1, 2, 3, 4, 5];
// 使用 map 遍历数组
let newArray = originalArray.map((element, index, array) => {
// element: 当前元素的值
// index: 当前元素的索引
// array: 原始数组
// 返回经过回调函数处理后的新值
return element * 2;
});
// 输出新数组
console.log(newArray); // [2, 4, 6, 8, 10]
filter 方法:
用于遍历数组的每个元素,并根据提供的回调函数的条件,筛选出符合条件的元素,最终返回一个新数组
let originalArray = [1, 2, 3, 4, 5];
// 使用 filter 遍历数组
let filteredArray = originalArray.filter((element, index, array) => {
// element: 当前元素的值
// index: 当前元素的索引
// array: 原始数组
// 返回一个布尔值,决定是否保留该元素
return element % 2 === 0; // 保留偶数元素
});
// 输出新数组
console.log(filteredArray); // [2, 4]
reduce 方法:
用于对数组中的所有元素执行一个指定的回调函数(也称为 reducer 函数),并将结果累积到一个最终值。reduce
提供了一种将数组元素合并、累积或转换为单一值的强大机制。
reduce
的回调函数接受四个参数:累加器(accumulator
)、当前值(currentValue
)、当前索引(currentIndex
)、原始数组(array
)。在使用 reduce
时,你需要决定如何使用这些参数来实现你想要的逻辑。通常,reduce
在需要对数组进行累积、汇总或转换的情况下非常有用。
数组求和:
let numbers = [1, 2, 3, 4, 5];
let sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 15
数组求积:
let numbers = [2, 3, 4];
let product = numbers.reduce((accumulator, currentValue) => accumulator * currentValue, 1);
console.log(product); // 24
数组拼接:
let words = ["Hello", " ", "World"];
let sentence = words.reduce((accumulator, currentValue) => accumulator + currentValue, "");
console.log(sentence); // "Hello World"
查找最大值:
let values = [10, 5, 8, 15];
let maxValue = values.reduce((max, currentValue) => (currentValue > max ? currentValue : max), values[0]);
console.log(maxValue); // 15
对象数组转换为对象:
let data = [
{ key: "a", value: 1 },
{ key: "b", value: 2 },
{ key: "c", value: 3 }
];
let result = data.reduce((obj, item) => {
obj[item.key] = item.value;
return obj;
}, {});
console.log(result); // { a: 1, b: 2, c: 3 }
对象
对象是一种无序的键值对集合,其中键是字符串或符号,值可以是任意类型。以下是一些关键的对象操作和概念:
对象的创建
使用对象字面量创建对象
let myObject = { key1: 'value1', key2: 'value2' };
使用Object构造函数创建对象
let anotherObject = new Object({ key1: 'value1', key2: 'value2' });
对象的访问
// 通过点号访问属性
let value = myObject.key1; // 'value1'
// 通过方括号访问属性
let anotherValue = myObject['key2']; // 'value2'
属性定义
const a = "foo";
const b = 42;
const c = {};
const o1 = {
a: a,
b: b,
c: c,
};
// 简写属性名
const o2 = { a, b, c };
console.log(o1.a === o2.a); // true
计算属性名
将一个表达式放在中括号 []
中,它将被计算并作为属性名使用
const item1 = "name";
const obj1 = {
[item1]: "Hello",
};
console.log(obj1.name); // "Hello"
const item2 = ["A", "B", "C"];
const obj2 = {
[item2]: "World",
};
console.log(obj2["A,B,C"]); // "World"
扩展属性
对象字面量支持扩展语法。它将自己提供的对象的枚举属性复制到一个新的对象上。
const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const clonedObj = { ...obj1 };
console.log(clonedObj.foo, clonedObj.x)
const mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj.foo, mergedObj.x, mergedObj.y)
// 输出
bar 42
baz 42 13
扩展属性可以实现一个对象的拷贝
对象原型
对象原型(Object Prototype)在 JavaScript 中是一个重要的概念,它是构成原型链的基础。原型是每个对象都拥有的一个特殊属性,它指向另一个对象,称为原型对象。通过原型,对象可以继承原型对象上的属性和方法。
在 JavaScript 中,每个对象都有一个原型对象,包括内置对象(如数组、函数等)和自定义对象。对象的原型对象可以通过 __proto__
属性(不推荐使用)或 Object.getPrototypeOf
方法来获取。
原型的作用主要有以下几点:
-
继承属性和方法: 对象通过原型链继承原型对象上的属性和方法。如果对象本身没有某个属性或方法,JavaScript 将在其原型链上查找,直到找到相应的属性或方法,或者到达原型链的末端。
-
实现属性和方法的共享: 当多个对象共享同一个原型对象时,它们可以共享原型对象上定义的属性和方法,从而实现一定程度的代码复用。
-
构建对象之间的关系: 通过原型链,对象可以与其他对象建立关系,形成对象之间的继承关系。
创建对象原型的方式有如下几种:
使用对象字面量创建原型
name 属性不在对象的原型上,无法通过关键字 __proto__
获取到原型上的属性
const myPrototype = {
protoProp: '我是原型上的属性',
};
const myObject = Object.create(myPrototype);
myObject.name = "我是常规属性"
console.log(myObject.protoProp, myObject.name)
console.log(myObject.__proto__.protoProp)
console.log(myObject.__proto__.name)
// 输出
> 我是原型上的属性 我是常规属性
> 我是原型上的属性
>
可以使用 Object.getPrototypeOf
将属性转换为原型上的属性
const prototypeOfMyObject = Object.getPrototypeOf(myObject);
prototypeOfMyObject.name = "转换为对象原型上的属性"
console.log(myObject.__proto__.name)
// 输出
> 转换为对象原型上的属性
使用 Object.setPrototypeOf 方法
Object.setPrototypeOf
方法可以将一个对象设置为另一个对象的原型。
const myPrototype = {
protoProp: 'I am a property in the prototype'
};
const myObject = {};
Object.setPrototypeOf(myObject, myPrototype);
console.log(myObject.__proto__.protoProp)
使用 ES6 的 class 语法:
类对象 myObject 可以直接获取其构造器上的属性,还可以通过 prototype
来设置原型上的属性
class MyClass {
constructor() {
this.constructorProp = '我是构造器上的属性';
}
}
MyClass.prototype.protoProp = '我是原型上的属性';
const myObject = new MyClass();
console.log(myObject.constructorProp)
console.log(myObject.__proto__.protoProp)
// 输出
> 我是构造器上的属性
> 我是原型上的属性
对象的遍历方式
for...in 循环:
这种方式会遍历对象的所有可枚举属性,包括原型链上的属性。因此,需要使用 hasOwnProperty
进行过滤,以确保只遍历对象自身的属性。
let myObject = { a: 1, b: 2, c: 3 };
for (let key in myObject) {
console.log(key, myObject[key]);
}
// 输出
a 1
b 2
c 3
for (let key in myObject) {
if (myObject.hasOwnProperty(key)) {
console.log(key, myObject[key]);
}
}
Object.keys 方法:
Object.keys
方法返回一个包含对象所有可枚举属性的数组,然后可以使用数组的遍历方法(如 forEach
)来遍历对象的属性。
let myObject = { a: 1, b: 2, c: 3 };
let keys = Object.keys(myObject);
keys.forEach(key => {
console.log(key, myObject[key]);
});
// 输出
a 1
b 2
c 3
Object.values 方法:
这种只能拿到对象的 value 值
let myObject = { a: 1, b: 2, c: 3 };
let values = Object.values(myObject);
values.forEach(value => {
console.log(value);
});
// 输出
1
2
3
Object.entries 方法:
返回一个包含对象所有可枚举属性的 [key, value]
对的数组,然后可以使用数组的遍历方法来遍历这些键值对。
let myObject = { a: 1, b: 2, c: 3 };
let entries = Object.entries(myObject);
entries.forEach(([key, value]) => {
console.log(key, value);
});
// 输出
a 1
b 2
c 3
解构
解构赋值使用类似的语法,但在赋值的左侧定义了要从原变量中取出哪些值。
数组的解构
基本变量赋值
const x = [1, 2, 3, 4, 5];
const [y, z] = x;
console.log(y); // 1
console.log(z); // 2
交换变量
没有解构赋值的情况下,交换两个变量需要一个临时变量,这个很实用啊
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
解析一个从函数返回的数组
这种写法非常的常见,通常函数封装成工具类,可直接解构返回的结果
function f() {
return [1, 2];
}
const [a, b] = f();
console.log(a); // 1
console.log(b); // 2
忽略某些返回值
使用空值,来表示忽略返回,下面的例子将中间的值忽略不返回
function f() {
return [1, 2, 3];
}
const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
const [c] = f();
console.log(c); // 1
对象的解构
基本赋值
const people = {
name: '张三',
age: 19,
};
const { name, age } = people;
console.log(name, age); // 张三,19
赋值给新的变量名
可以从对象中提取属性,并将其赋值给名称与对象属性不同的变量。
const people = {
name: '张三',
age: 19,
};
const { name:x, age:y } = people;
console.log(x, y); // 张三,19
将 对象中的 name 属性值赋给 x,age 属性赋值给 y
从作为函数参数传递的对象中提取属性
下面这个示例中有一个 user 对象,通过函数来获取 user 的属性 id,参数值 { id }
表示传递给函数的对象的 id
属性应该被提取到一个同名变量中
const user = {
id: 1001,
displayName: "jdoe",
fullName: {
firstName: "Jane",
lastName: "Doe",
},
};
function getUserId({ id }) {
return id;
}
console.log(getUserId(user)); // 42
获取对象的 displayName,这里可以重新指定提取的属性名称
function userDisplayName({ displayName: dname }) {
return dname;
}
console.log(userDisplayName(user)); // `jdoe`
嵌套对象属性的提取
function whois({ displayName, fullName: { firstName: name } }) {
return `${displayName} is ${name}`;
}
console.log(whois(user)); // "jdoe is Jane"
设置函数参数的默认值
默认值可以使用 =
指定,如果指定的属性在传递的对象中不存在,则将其用作变量值。
在 drawChart
的函数签名中,解构的左侧具有空对象 = {}
的默认值。
function drawChart({
size = "big",
coords = { x: 0, y: 0 },
radius = 25,
} = {}) {
console.log(size, coords, radius);
// do some chart drawing
}
drawChart({
coords: { x: 18, y: 30 },
radius: 30,
});
解构对象时查找原型链
当解构一个对象时,JavaScript 会按照以下规则查找属性:
-
直接属性(Own Properties): 首先,JavaScript 会查找对象本身是否具有要解构的属性。如果对象有这个属性,就会从对象本身获取相应的值。
-
原型链(Prototype Chain): 如果对象本身没有这个属性,JavaScript 将沿着原型链继续查找。原型链是对象之间的连接,每个对象都有一个指向它的原型对象的链接。如果属性在原型对象中找到,就会返回相应的值。
const obj = {
self: "123",
__proto__: {
prot: "456",
},
};
const { self, prot } = obj;
console.log(self, prot) // 123 456
obj 的原型对象是 { prot: "456", }
,所以当无法从 obj 属性上找到 prot 属性时,就会去其原型对象上继续寻找 prot 属性