1:js什么是防抖和节流?有什么区别?如何实现?
答:
防抖和节流是前端开发中常用的优化性能的方法。防抖是指在一定时间内,多次触发同一事件,只执行最后一次操作,以减少函数调用次数。节流是指在一定时间内,多次触发同一事件,只执行一次操作,以减少函数调用次数。两者的区别在于防抖只执行最后一次操作,而节流只执行第一次操作。
区别:
防抖是指在一定时间内,只执行最后一次操作,比如、窗口大小改变、搜索框输入联想,只在用户停止输入后才会发送请求
节流是指在一定时间内,只执行一次操作,比如滚动加载,mousemove事件等,只有在用户停止滚动后才会加载数据
防抖函数
// 防抖函数
function debounce(fn, delay) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
}
}
节流函数
// 节流函数
function throttle(fn, delay) {
let timer = null;
return function() {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
}
}
}
2:ES6的几个新特性?
答:
- let和const关键字用于声明变量和常量
- 箭头函数
- 模板字符串
- 解构赋值
- 默认参数
- 扩展运算符
- 类和继承
- Promise对象
- 模块化
- 迭代器和生成器
1. let和const关键字用于声明变量和常量
let a = 1;
const b = 2;
2. 箭头函数
const sum = (a, b) => a + b;
3. 模板字符串
const name = 'John';
console.log(`Hello, ${name}!`);
4. 解构赋值
const { x, y } = { x: 1, y: 2 };
5. 默认参数
const greet = (name = 'World') => `Hello, ${name}!`;
6. 扩展运算符
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2];
7. 类和继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const d = new Dog('Mitzie');
d.speak();
8. Promise对象
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then((value) => {
console.log(value);
});
9. 模块化
// file1.js
export const sum = (a, b) => a + b;
// file2.js
import { sum } from './file1.js';
console.log(sum(1, 2));
10. 迭代器和生成器
function* generator() {
yield 1;
yield 2;
yield 3;
}
const gen = generator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
3:说说var,let,const创建变量有什么区别?
答:
变量区别:
var声明的变量是函数作用域或全局作用域,而let和const声明的变量是块级作用域。
var声明的变量可以被重复声明,而let和const声明的变量不能被重复声明。
var声明的变量可以被修改,而const声明的变量不能被修改,let声明的变量可以被修改。
var,let,const实现方法
1:var 实现方法
// var 实现方法
var x = 10;
console.log(x); // Output: 10
2: let 实现方法
// let 实现方法
let y = 20;
console.log(y); // Output: 20
3:const 实现方法
// const 实现方法
const z = 30;
console.log(z); // Output: 30
var,let,const的区别:
var 声明的变量可以被重新赋值和重新声明
// var 声明的变量可以被重新赋值和重新声明
var x = 10;
console.log(x); // Output: 10
x = 20;
console.log(x); // Output: 20
var x = 30;
console.log(x); // Output: 30
1:let 声明的变量可以被重新赋值,但不能被重新声明
// let 声明的变量可以被重新赋值,但不能被重新声明
let y = 40;
console.log(y); // Output: 40
y = 50;
console.log(y); // Output: 50
// let y = 60; // SyntaxError: Identifier 'y' has already been declared
2:const 声明的变量不能被重新赋值和重新声明
// const 声明的变量不能被重新赋值和重新声明
const z = 70;
console.log(z); // Output: 70
// z = 80; // TypeError: Assignment to constant variable.
// const z = 90; // SyntaxError: Identifier 'z' has already been declared
4:值类型和引用类型有那些区别?
答:值类型和引用类型是JavaScript中的两种基本数据类型。
值类型是指简单数据类型,如数字、字符串、布尔值、null和undefined。
引用类型是指复杂数据类型,如对象、数组和函数。值类型的变量存储的是实际的值,而引用类型的变量存储的是指向实际对象的指针。
因此,当我们复制一个值类型的变量时,实际上是将该变量的值复制到新变量中。而当我们复制一个引用类型的变量时,实际上是将该变量的指针复制到新变量中,因此两个变量指向同一个对象。这就是值类型和引用类型的主要区别。
1:值类型实现方法
// 值类型实现方法
let a = 1;
let b = a;
b = 2;
console.log(a); // 1
console.log(b); // 2
2:引用类型实现方法
// 引用类型实现方法
let obj1 = {name: 'Alice'};
let obj2 = obj1;
obj2.name = 'Bob';
console.log(obj1.name); // 'Bob'
console.log(obj2.name); // 'Bob'
5:数组中常用的方法有那些?
答:
常用的数组方法有:
- push():向数组末尾添加一个或多个元素,并返回新的长度。
- pop():删除数组末尾的元素,并返回该元素的值。
- shift():删除数组的第一个元素,并返回该元素的值。
- unshift():向数组的开头添加一个或多个元素,并返回新的长度。
- splice():从数组中添加或删除元素。
- slice():返回一个新的数组,包含从开始到结束(不包括结束)的元素。
- concat():连接两个或多个数组,并返回新的数组。
- join():将数组中的所有元素转换为一个字符串。
- indexOf():返回数组中指定元素的第一个索引,如果不存在则返回-1。
- lastIndexOf():返回数组中指定元素的最后一个索引,如果不存在则返回-1。
- forEach():对数组中的每个元素执行一次指定的函数。
- map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
- filter():创建一个新数组,其中包含所有通过指定函数测试的元素。
- reduce():对数组中的所有元素执行一个指定的函数,并将结果累加到单个值中。
- sort():对数组中的元素进行排序。
- reverse():颠倒数组中元素的顺序。
1. push():向数组末尾添加一个或多个元素,并返回新的长度。
// push()
let arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
2. pop():删除数组末尾的元素,并返回该元素的值。
// pop()
let arr2 = [1, 2, 3];
let lastElement = arr2.pop();
console.log(lastElement); // 3
console.log(arr2); // [1, 2]
3. shift():删除数组的第一个元素,并返回该元素的值。
// shift()
let arr3 = [1, 2, 3];
let firstElement = arr3.shift();
console.log(firstElement); // 1
console.log(arr3); // [2, 3]
4. unshift():向数组的开头添加一个或多个元素,并返回新的长度。
// unshift()
let arr4 = [1, 2, 3];
arr4.unshift(0);
console.log(arr4); // [0, 1, 2, 3]
5. splice():从数组中添加或删除元素。
// splice()
let arr5 = [1, 2, 3];
arr5.splice(1, 1, 4, 5);
console.log(arr5); // [1, 4, 5, 3]
6. slice():返回一个新的数组,包含从开始到结束(不包括结束)的元素。
// slice()
let arr6 = [1, 2, 3];
let newArr = arr6.slice(1, 2);
console.log(newArr); // [2]
7. concat():连接两个或多个数组,并返回新的数组。
// concat()
let arr7 = [1, 2];
let arr8 = [3, 4];
let newArr2 = arr7.concat(arr8);
console.log(newArr2); // [1, 2, 3, 4]
8. join():将数组中的所有元素转换为一个字符串。
// join()
let arr9 = [1, 2, 3];
let str = arr9.join('-');
console.log(str); // "1-2-3"
9. indexOf():返回数组中指定元素的第一个索引,如果不存在则返回-1。
// indexOf()
let arr10 = [1, 2, 3];
let index = arr10.indexOf(2);
console.log(index); // 1
10. lastIndexOf():返回数组中指定元素的最后一个索引,如果不存在则返回-1。
// lastIndexOf()
let arr11 = [1, 2, 3, 2];
let lastIndex = arr11.lastIndexOf(2);
console.log(lastIndex); // 3
11. forEach():对数组中的每个元素执行一次指定的函数。
// forEach()
let arr12 = [1, 2, 3];
arr12.forEach(function(item, index, array) {
console.log(item, index, array);
});
//运行结果
1 0 [1, 2, 3]
2 1 [1, 2, 3]
3 2 [1, 2, 3]
12. map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
// map()
let arr13 = [1, 2, 3];
let newArr3 = arr13.map(function(item, index, array) {
return item * 2;
});
console.log(newArr3) // [2,4,6]
13. filter():创建一个新数组,其中包含所有通过指定函数测试的元素。
let arr14 = [1, 2, 3, 4, 5];
let newArr4 = arr14.filter(function(item, index, array) {
return item % 2 === 0;
});
console.log(newArr4); // [2, 4]
14. reduce():对数组中的所有元素执行一个指定的函数,并将结果累加到单个值中。
// reduce()
let arr15 = [1, 2, 3];
let sum = arr15.reduce(function(prev, curr, index, array) {
return prev + curr;
});
console.log(sum); // 6
15. sort():对数组中的元素进行排序。
// sort()
let arr16 = [3, 1, 4, 2];
arr16.sort();
console.log(arr16); // [1, 2, 3, 4]
16. reverse():颠倒数组中元素的顺序。
// reverse()
let arr17 = [1, 2, 3];
arr17.reverse();
console.log(arr17); // [3, 2, 1]
6:javaScript中的Promise使用?介绍下 promise 的特性、优缺点,内部是如何实现的,动手实现 Promise?什么是 async/await 及其如何工作?async和promise的作用和用法分别有哪些?
答:
Promise的特性:
- Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
- Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
- Promise对象的状态一旦改变,就永久保持该状态,不会再变了。
- Promise对象有then方法,then方法可以接受两个回调函数作为参数,分别代表异步操作成功时的回调和异步操作失败时的回调。
- Promise对象可以链式调用,即then方法返回的是一个新的Promise对象,可以继续调用then方法。
Promise的优缺点
优点:
- 可以避免回调地狱,使代码更加清晰易懂。
- 可以更好地处理异步操作的结果,使代码更加健壮。
- 可以链式调用,使代码更加简洁。
缺点:
- Promise对象一旦被创建,就无法取消。
- Promise对象的错误处理机制不够完善,需要使用catch方法来捕获错误。
- Promise对象的使用需要一定的学习成本
Promise的内部实现
Promise的内部实现主要包括以下几个部分:
- Promise构造函数:用于创建Promise对象。
- then方法:用于注册回调函数。
- resolve方法:用于将Promise对象的状态从pending变为fulfilled。
- reject方法:用于将Promise对象的状态从pending变为rejected。
- Promise的状态转换机制:用于控制Promise对象的状态转换。
动手实现Promise
可以参考以下代码:
class MyPromise {
constructor(executor) {
this.status = 'pending';
this.value this.reason
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback(this.value));
}
};
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(this.reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason };
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.status === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected for promise'));
}
let called = false;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
const then = x.then;
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x);
}
}
}
6.1:什么是 async/await 及其如何工作?
答:async/await 是一种异步编程的方式,它是基于 Promise 的语法糖。async/await 使得异步代码看起来像同步代码,使得代码更加易读易懂。async/await 通过 async 函数来定义异步函数,await 关键字用于等待 Promise 对象的结果。当 await 关键字等待 Promise 对象时,它会暂停当前函数的执行,直到 Promise 对象返回结果。如果 Promise 对象返回的是一个错误,那么 await 关键字会抛出这个错误,否则它会返回 Promise 对象的结果。
async function example() {
try {
const result1 = await promise1();
const result2 = await promise2(result1);
return result2;
} catch (error) {
console.error(error);
}
}
function promise1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('result1');
}, 1000);
});
}
function promise2(result1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`result2 with ${result1}`);
}, 1000);
});
}
example().then((result) => {
console.log(result);
});
输出result2 with result1。
这段代码是一个使用async/await语法实现的异步操作示例。首先,我们定义了两个返回Promise对象的函数promise1()和promise2(result1),分别用于模拟两个异步操作。然后,我们定义了一个async函数example(),用于串行执行这两个异步操作,并返回最终的结果。
在example()函数中,我们使用await关键字等待promise1()函数返回结果,并将其存储在变量result1中。然后,我们使用await关键字等待promise2(result1)函数返回结果,并将其存储在变量result2中。最后,我们使用return关键字返回result2变量的值。
在example()函数中,我们使用了try/catch语句来捕获可能发生的异常,并将异常信息输出到控制台。
最后,我们调用example()函数,并使用then()方法注册一个回调函数,用于在example()函数返回结果后输出最终的结果。
因为promise1()和promise2(result1)函数都是使用setTimeout()模拟异步操作,所以它们会在 1 秒后返回结果。因此,当我们运行这段代码时,它会在 2 秒后输出result2 with result1。
async/await 的实现方法是通过 async 函数来定义异步函数,await 关键字用于等待 Promise 对象的结果。当 await 关键字等待 Promise 对象时,它会暂停当前函数的执行,直到 Promise 对象返回结果。如果 Promise 对象返回的是一个错误,那么 await 关键字会抛出这个错误,否则它会返回 Promise 对象的结果。在上面的代码中,我们定义了两个 Promise 对象 promise1 和 promise2,然后在 example 函数中使用了 async/await 来等待这两个 Promise 对象的结果。在 example 函数中,我们首先等待 promise1 的结果,然后将其作为参数传递给 promise2,最后返回 promise2 的结果。如果在等待过程中出现错误,我们使用 try/catch 语句来捕获错误并输出错误信息。最后,我们通过调用 example 函数并使用 then 方法来获取最终的结果。
6.2:async和promise的作用和用法分别有哪些?
答:
async和promise都是用于处理异步操作的工具,它们的作用是让异步操作更加简单和可读。Promise是ES6中引入的一种异步编程的解决方案,它可以将异步操作封装成一个Promise对象,通过链式调用then方法来处理异步操作的结果。而async/await是ES7中引入的一种异步编程的解决方案,它可以让异步操作的代码看起来像同步代码,使得异步操作更加易于理解和维护。async函数是一个返回Promise对象的函数,可以使用await关键字来等待异步操作的结果。
// Promise的作用和用法
// Promise是一种异步编程的解决方案,比传统的回调函数和事件更加的优雅和简洁。
// Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
// Promise的实现方法:
// 1. 使用Promise构造函数
const promise = new Promise((resolve, reject) => {
// 异步操作
if (/* 异步操作成功 */) {
resolve(value);
} else {
reject(error);
}
});
// 2. 使用Promise.resolve()方法
const promise = Promise.resolve(value);
// 3. 使用Promise.reject()方法
const promise = Promise.reject(error);
// async的作用和用法
// async是ES7引入的一种新的异步编程方式,它是Generator函数的语法糖,使得异步操作更加的简单和直观。
// async函数返回一个Promise对象,可以使用then方法进行链式调用。
// async的实现方法:
async function foo() {
// 异步操作
return value;
}
// async函数的错误处理
async function foo() {
try {
// 异步操作
return value;
} catch (error) {
console.log(error);
}
}
7:详解JS四种异步:回调函数、Promise、Generator、async/await?
答:
回调函数
回调函数是一种异步编程的方式,通过将函数作为参数传递给另一个函数,在异步操作完成后调用该函数来处理结果。
但是,回调函数会导致回调地狱,代码难以维护和阅读。
// 回调函数
function callbackFunc(callback) {
setTimeout(() => {
callback('callback');
}, 1000);
}
callbackFunc((data) => {
console.log(data);
});
Promise
Promise 是一种更加优雅的异步编程方式,它可以避免回调地狱,通过链式调用 then 方法来处理异步操作的结果。
Promise 有三种状态:pending、fulfilled、rejected,状态一旦改变就不会再变。
// Promise
function promiseFunc() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise');
}, 1000);
});
}
promiseFunc().then((data) => {
console.log(data);
});
Generator
Generator 是一种基于迭代器的异步编程方式,它可以通过 yield 关键字来暂停函数的执行,等待异步操作完成后再继续执行。
Generator 可以通过 next 方法来控制函数的执行流程。
// Generator
function* generatorFunc() {
yield setTimeout(() => {
console.log('generator');
gen.next();
}, 1000);
}
const gen = generatorFunc();
gen.next();
async/await
async/await 是一种基于 Promise 的异步编程方式,它可以让异步代码看起来像同步代码,使得代码更加易读易维护。
async/await 是基于 Generator 和 Promise 实现的,async 函数返回一个 Promise 对象,await 关键字可以暂停函数的执行,等待 Promise 对象的状态改变后再继续执行。
// async/await
async function asyncFunc() {
const data = await promiseFunc();
console.log(data);
}
asyncFunc();
8:js中this闭包、作用域和作用域链? js中this指向什么?闭包优缺点?什么是闭包(closure),为什么要用它?
8.1:js中this闭包、作用域和作用域链?
在 JavaScript 中,this 关键字用于引用当前执行上下文中的对象。
闭包是指函数可以访问其定义时的词法作用域,即使函数在其定义的作用域之外执行。
作用域是指变量和函数的可访问范围。
作用域链是指在嵌套的作用域中查找变量和函数的过程。
实现 this 关键字
- 使用 call()、apply()、bind() 方法来改变函数执行时的 this 指向
- 在对象方法中使用 this 关键字来引用该对象
- 在构造函数中使用 this 关键字来引用新创建的对象
// 示例代码:
// this 关键字示例
const person = {
name: 'John',
age: 30,
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
};
person.greet(); // 输出:Hello, my name is John and I am 30 years old.
实现闭包
- 在函数内部定义一个函数,并返回该函数
- 在返回的函数中访问外部函数的变量
// 闭包示例
function outer() {
const message = 'Hello, ';
function inner(name) {
console.log(message + name);
}
return inner;
}
const sayHello = outer();
sayHello('John'); // 输出:Hello, John
实现作用域和作用域链
- JavaScript 中有全局作用域和局部作用域
- 在函数内部定义的变量只能在该函数内部访问,称为局部变量
- 在函数外部定义的变量可以在全局范围内访问,称为全局变量
- 在嵌套的函数中,内部函数可以访问外部函数的变量,但外部函数不能访问内部函数的变量
- 当访问一个变量时,JavaScript 引擎会先在当前作用域中查找该变量,如果找不到则会向上一级作用域查找,直到找到该变量或者到达全局作用域为止,这个查找的过程就是作用域链。
// 作用域和作用域链示例
const globalVar = 'I am global';
function outerFunc() {
const outerVar = 'I am outer';
function innerFunc() {
const innerVar = 'I am inner';
console.log(innerVar); // 输出:I am inner
console.log(outerVar); // 输出:I am outer
console.log(globalVar); // 输出:I am global
}
innerFunc();
}
outerFunc();
8.2:js中this指向什么?
答:this指向当前执行代码的对象,即调用该方法的对象。
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const john = new Person('John', 30);
john.sayHello(); // Output: Hello, my name is John and I am 30 years old.
8.3:闭包优缺点?
答:
闭包优点:
- 可以访问函数内部的变量和参数,即使函数已经返回。
- 可以将函数内部的变量和方法保存在内存中,供其他函数调用。
- 可以模拟私有变量和方法,保护数据安全性。
闭包缺点:
- 闭包会占用内存,如果使用不当,可能会导致内存泄漏。
- 闭包的作用域链可能会导致性能问题,因为它需要在每次访问变量时遍历整个作用域链。
- 闭包可能会导致代码可读性和维护性的问题,因为它可以使代码变得复杂和难以理解。
// 闭包示例
function outerFunction() {
let count = 0;
function innerFunction() {
count++;
console.log(count);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // 输出 1
closure(); // 输出 2
closure(); // 输出 3
8.4:什么是闭包(closure),为什么要用它?
答:闭包是指函数和其相关的引用环境组合而成的实体,它可以访问函数定义时所在的词法作用域中的变量和参数,即使函数在其他地方被调用时,也可以使用这些变量和参数。闭包可以用于封装变量和函数,实现模块化编程,避免变量污染和命名冲突,以及实现某些高级特性,如柯里化、惰性求值、函数式编程等。
9:=和的区别?
答
===是严格相等,比较时不会进行类型转换,只有在两个值类型相同且值相等时才返回true;
==是相等,比较时会进行类型转换,如果两个值类型不同,会尝试将它们转换为相同的类型,然后再进行比较。
console.log(1 === "1"); // false
console.log(1 == "1"); // true
console.log(1 == true); // true
console.log(1 === true); // false
10:Js的浅拷贝和深拷贝?
答:
Js的浅拷贝和深拷贝
浅拷贝只是复制了对象的引用,而不是对象本身
深拷贝则是复制了对象本身,而不是对象的引用
深拷贝可以使用JSON.parse(JSON.stringify(obj))或第三方库如lodash实现
// 浅拷贝示例
let obj1 = {a: 1, b: {c: 2}};
let obj2 = Object.assign({}, obj1);
let obj3 = {...obj1};
obj1.b.c = 3;
console.log(obj2); // {a: 1, b: {c: 3}}
console.log(obj3); // {a: 1, b: {c: 3}}
// 深拷贝示例
let obj4 = {a: 1, b: {c: 2}};
let obj5 = JSON.parse(JSON.stringify(obj4));
obj4.b.c = 3;
console.log(obj5); // {a: 1, b: {c: 2}}
10.1 Js的浅拷贝和深拷贝区别
答:
Js的浅拷贝和深拷贝区别
浅拷贝只是复制了对象的引用,而不是对象本身,所以当原对象改变时,拷贝对象也会改变。
深拷贝则是复制了对象本身,所以当原对象改变时,拷贝对象不会改变。
// 浅拷贝示例
let obj1 = {a: 1, b: {c: 2}};
let obj2 = Object.assign({}, obj1);
obj1.b.c = 3;
console.log(obj1); // {a: 1, b: {c: 3}}
console.log(obj2); // {a: 1, b: {c: 3}}
// 深拷贝示例
let obj3 = {a: 1, b: {c: 2}};
let obj4 = JSON.parse(JSON.stringify(obj3));
obj3.b.c = 3;
console.log(obj3); // {a: 1, b: {c: 3}}
console.log(obj4); // {a: 1, b: {c: 2}}
11:JavaScript 什么是原型和原型链?有什么特点?原型与原型链
答:什么是原型和原型链?
JavaScript中每个对象都有一个原型属性,它指向该对象的原型对象。原型对象也是一个对象,它也有自己的原型对象,这样就形成了一个原型链。原型链的特点是当我们访问一个对象的属性时,如果该对象本身没有该属性,那么就会去它的原型对象中查找,如果还没有,就会去原型对象的原型对象中查找,直到找到该属性或者到达原型链的顶端为止。原型链的顶端是Object.prototype,它是所有对象的原型对象。原型链的作用是实现对象之间的继承关系,通过原型链,我们可以让一个对象继承另一个对象的属性和方法。
原型和原型链区别
原型是每个对象都具有的属性,它指向该对象的原型对象。
原型对象也是一个对象,它也有自己的原型对象,这样就形成了一个原型链。原型链的作用是实现对象之间的继承关系,通过原型链,我们可以让一个对象继承另一个对象的属性和方法。而原型链是由原型对象组成的链式结构,它的顶端是Object.prototype,它是所有对象的原型对象。原型链的作用是实现对象之间的继承关系,通过原型链,我们可以让一个对象继承另一个对象的属性和方法。因此,原型和原型链是密不可分的,原型是原型链的基础,原型链是原型的体现。
原型和原型链实现方法
JavaScript中,我们可以使用构造函数来创建对象,每个构造函数都有一个prototype属性,它指向该构造函数的原型对象。我们可以在原型对象上定义属性和方法,这样所有通过该构造函数创建的对象都可以共享这些属性和方法。这种方式可以实现对象之间的继承关系,即通过一个构造函数创建的对象可以继承该构造函数原型对象上的属性和方法。同时,我们也可以通过修改原型对象上的属性和方法来实现动态修改所有对象的属性和方法。这种方式是JavaScript中实现原型和原型链的基础。
另外,JavaScript中还有一种方式可以实现对象之间的继承关系,即通过Object.create()方法创建对象。该方法接收一个原型对象作为参数,返回一个新的对象,该对象的原型对象就是传入的原型对象。这种方式可以实现对象之间的继承关系,同时也可以实现动态修改所有对象的属性和方法。这种方式是JavaScript中实现原型和原型链的另一种方式。
原型代码
//原型代码
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name + " and I am " + this.age + " years old.");
};
var person1 = new Person("Alice", 25);
var person2 = new Person("Bob", 30);
person1.sayHello(); // Hello, my name is Alice and I am 25 years old.
person2.sayHello(); // Hello, my name is Bob and I am 30 years old.
原型链代码
//原型链代码
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log("My name is " + this.name);
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.sayBreed = function() {
console.log("My breed is " + this.breed);
};
var dog1 = new Dog("Buddy", "Golden Retriever");
var dog2 = new Dog("Charlie", "Poodle");
dog1.sayName(); // My name is Buddy
dog1.sayBreed(); // My breed is Golden Retriever
dog2.sayName(); // My name is Charlie
dog2.sayBreed(); // My breed is Poodle
原型和原型链代码
// 创建一个构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 给构造函数的原型上添加方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}, I'm ${this.age} years old.`);
}
// 创建一个实例
const person1 = new Person('Tom', 18);
// 调用实例上的方法
person1.sayHello();
// 判断实例是否是构造函数的实例
console.log(person1 instanceof Person); // true
// 判断构造函数的原型是否是实例的原型
console.log(Person.prototype.isPrototypeOf(person1)); // true
// 获取实例的原型
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
// 创建一个构造函数
function Student(name, age, grade) {
// 调用父类的构造函数
Person.call(this, name, age);
this.grade = grade;
}
// 继承父类的原型
Student.prototype = Object.create(Person.prototype);
// 修复构造函数指向
Student.prototype.constructor = Student;
// 给子类的原型上添加方法
Student.prototype.sayGrade = function() {
console.log(`My grade is ${this.grade}.`);
}
// 创建一个实例
const student1 = new Student('Jerry', 20, 'A');
// 调用实例上的方法
student1.sayHello();
student1.sayGrade();
// 判断实例是否是构造函数的实例
console.log(student1 instanceof Student); // true
console.log(student1 instanceof Person); // true
// 判断构造函数的原型是否是实例的原型
console.log(Student.prototype.isPrototypeOf(student1)); // true
console.log(Person.prototype.isPrototypeOf(student1)); // true
// 获取实例的原型
console.log(Object.getPrototypeOf(student1) === Student.prototype); // true
这段代码演示了如何使用原型链实现构造函数的继承。
首先,我们创建了一个Person构造函数,它有两个属性name和age,以及一个sayHello方法。然后,我们给Person构造函数的原型上添加了sayHello方法。
接着,我们创建了一个person1实例,并调用了它的sayHello方法。然后,我们使用instanceof运算符判断person1实例是否是Person构造函数的实例,以及使用isPrototypeOf方法判断Person.prototype是否是person1实例的原型。最后,我们使用Object.getPrototypeOf方法获取person1实例的原型。
然后,我们创建了一个Student构造函数,它继承了Person构造函数,并添加了一个grade属性和一个sayGrade方法。为了实现继承,我们使用call方法调用了Person构造函数,并将this指向了Student构造函数的实例。然后,我们使用Object.create方法创建了一个新对象,将其原型设置为Person.prototype,并将其赋值给Student.prototype,从而实现了Student构造函数对Person.prototype的继承。最后,我们修复了Student.prototype.constructor指向,并给Student构造函数的原型上添加了sayGrade方法。
接着,我们创建了一个student1实例,并调用了它的sayHello和sayGrade方法。然后,我们使用instanceof运算符判断student1实例是否是Student构造函数和Person构造函数的实例,以及使用isPrototypeOf方法判断Student.prototype和Person.prototype是否是student1实例的原型。最后,我们使用Object.getPrototypeOf方法获取student1实例的原型。
因为Student构造函数继承了Person构造函数,并且Student.prototype继承了Person.prototype,所以student1实例既是Student构造函数的实例,也是Person构造函数的实例。同时,Student.prototype和Person.prototype都是student1实例的原型。
11:javaScript原型链与继承?
答:JavaScript原型链与继承
所有的 JavaScript 对象都有一个原型对象,原型对象又有自己的原型,直到某个对象的原型为 null 为止,组成了原型链。
JavaScript 对象是动态的属性“包容器”,即对于一个 JavaScript 对象,它可以添加或删除属性,但当查找一个对象的属性时,它不仅仅查
找该对象本身的属性,还要查找该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到该名称的属性或到达原型链的末尾。
原型链的继承是 JavaScript 对象的一种属性继承方式,即在创建一个对象时,可以指定这个对象的原型对象,从而继承原型对象的属性和方法。
// 举个例子,我们创建一个对象 person,它有一个属性 name 和一个方法 sayHello
let person = {
name: "John",
sayHello: function() {
console.log("Hello, my name is " + this.name);
}
};
// 现在我们创建一个新的对象 student,它的原型对象是 person,这样 student 就继承了 person 的属性和方法
let student = Object.create(person);
student.name = "Alice";
// 现在我们可以调用 student 的 sayHello 方法,它会输出 "Hello, my name is Alice",因为 student 继承了 person 的 sayHello 方法,并且 student 的 name 属性被设置为 "Alice"
student.sayHello();
运行结果:Hello, my name is Alice
12:javaScript中null和undefined区别?
答:在JavaScript中,null和undefined都表示没有值。但是它们的含义略有不同。null表示一个空对象指针,而undefined表示一个未定义的原始值。当声明一个变量但没有给它赋值时,它的默认值是undefined。而null通常是由程序员显式地赋值给变量的。
let a;
console.log(a); // 输出undefined
// 示例2
let b = null;
console.log(b); // 输出null
// 示例3
console.log(typeof null); // 输出object
console.log(typeof undefined); // 输出undefined
// 示例4
console.log(null == undefined); // 输出true
console.log(null === undefined); // 输出false
13:如何使用JSON.parse和JSON.stringify()?
答:JSON.parse和JSON.stringify()区别;
JSON.parse()用于将JSON字符串转换为JavaScript对象,而JSON.stringify()用于将JavaScript对象转换为JSON字符串。
// 使用JSON.parse将JSON字符串转换为JavaScript对象
const jsonString = '{"name":"John", "age":30, "city":"New York"}';
const obj = JSON.parse(jsonString);
console.log(obj.name); // 输出 "John"
// 使用JSON.stringify将JavaScript对象转换为JSON字符串
const obj2 = {name: "Jane", age: 25, city: "Los Angeles"};
const jsonString2 = JSON.stringify(obj2);
console.log(jsonString2); // 输出 '{"name":"Jane","age":25,"city":"Los Angeles"}'
14:介绍Js的基本数据类型?原始类型有哪些?如何查看JS数据类型?
答:
Js的基本数据类型有:数字(Number)、字符串(String)、布尔(Boolean)、空值(null)、未定义(undefined)。
原始类型有:数字(Number)、字符串(String)、布尔(Boolean)、空值(null)、未定义(undefined)。
可以使用typeof运算符来查看JS数据类型,例如:
typeof 123; // "number"
typeof "hello"; // "string"
typeof true; // "boolean"
typeof null; // "object"
typeof undefined; // "undefined"
15:栈和堆的区别?
答:栈和堆都是计算机内存中的存储区域,但是它们的使用方式和存储数据的方式不同。
栈是一种先进后出的数据结构,用于存储函数调用时的临时变量、函数的参数值等。
堆是一种动态分配内存的方式,用于存储程序运行时需要的数据,如对象、数组等。栈的大小是固定的,而堆的大小是动态变化的。栈的访问速度比堆快,但是栈的空间有限,堆的空间相对较大。
// 栈的示例
function foo() {
let a = 1;
let b = 2;
let c = a + b;
return c;
}
foo();
// 堆的示例
let obj = {name: 'John', age: 30};
let arr = [1, 2, 3, 4, 5];
16:null,undefined或undeclared的区别?
答:在JavaScript中,null表示一个空对象指针,即变量被定义了但是没有被赋值。undefined表示变量未被定义或者被定义了但是没有被赋值。而undeclared则表示变量未被声明,即在代码中没有出现过该变量名。
1:null表示一个空对象指针,即该对象不指向任何内存地址
// null表示一个空对象指针,即该对象不指向任何内存地址
var obj1 = null;
console.log(obj1); // null
2:undefined表示一个未定义的值,即该变量没有被赋值
// undefined表示一个未定义的值,即该变量没有被赋值
var num;
console.log(num); // undefined
// undeclared表示一个未声明的变量,即该变量没有被定义过
console.log(num2); // ReferenceError: num2 is not defined
17:for…in 和 object.keys的区别?
答:for…in循环可以遍历对象的所有可枚举属性,包括继承的属性,而Object.keys()方法只返回对象自身的可枚举属性组成的数组。
// for..in循环遍历对象属性
for (let key in obj) {
console.log(key + ': ' + obj[key]);
}
//结果
a: 1
b: 2
c: 3
// Object.keys()返回一个由对象的自身可枚举属性组成的数组
Object.keys(obj).forEach(function(key) {
console.log(key + ': ' + obj[key]);
});
//结果
a: 1
b: 2
c: 3
// for..in循环遍历对象的属性名
const obj = {a: 1, b: 2, c: 3};
for (let prop in obj) {
console.log(prop); // 输出 a, b, c
}
// Object.keys返回对象的属性名数组
const obj2 = {a: 1, b: 2, c: 3};
const keys = Object.keys(obj2);
console.log(keys); // 输出 ["a", "b", "c"]
// for..in循环遍历对象的属性名
const obj = {a: 1, b: 2, c: 3};
for (let prop in obj) {
console.log(prop); // 输出 a, b, c
}
// object.keys返回对象的属性名数组
const obj2 = {a: 1, b: 2, c: 3};
const keys = Object.keys(obj2);
console.log(keys); // 输出 ["a", "b", "c"]
for…in循环遍历对象的属性名,包括继承的属性,而object.keys只返回对象自身的属性名数组。
18:ES6分别几种方法声明变量?
答:
ES6有三种方法声明变量:
- let:用于声明块级作用域的变量,可以被重新赋值。
- const:用于声明块级作用域的常量,一旦被赋值就不能再被修改。
- var:用于声明函数作用域或全局作用域的变量,可以被重新赋值。
// 使用 let 声明变量
let a = 1;
// 使用 const 声明常量
const b = 2;
// 使用 var 声明变量(不推荐)
var c = 3;
19:javaScript响应事件有哪些?
答:
JavaScript响应事件有很多种,包括但不限于:
- 鼠标事件:click、dblclick、mousedown、mouseup、mousemove、mouseover、mouseout、mouseenter、mouseleave、contextmenu
- 键盘事件:keydown、keyup、keypress
- 表单事件:submit、reset、change、focus、blur、input
- 文档/窗口事件:load、unload、resize、scroll
- 视频/音频事件:play、pause、ended、volumechange、timeupdate
- 动画事件:animationstart、animationend、animationiteration
- 过渡事件:transitionend
1:鼠标事件示例
// 鼠标事件示例
document.getElementById("myButton").addEventListener("click", function(){
alert("Hello World!");
});
2:键盘事件示例
// 键盘事件示例
document.addEventListener("keydown", function(event) {
if (event.code === "KeyA") {
console.log("The 'A' key is pressed.");
}
});
3:表单事件示例
// 表单事件示例
document.getElementById("myForm").addEventListener("submit", function(event){
event.preventDefault();
console.log("Form submitted.");
});
4:文档/窗口事件示例
// 文档/窗口事件示例
window.addEventListener("resize", function(){
console.log("Window resized.");
});
5:视频/音频事件示例
// 视频/音频事件示例
var myVideo = document.getElementById("myVideo");
myVideo.addEventListener("play", function(){
console.log("Video is playing.");
});
6:动画事件示例
// 动画事件示例
var myElement = document.getElementById("myElement");
myElement.addEventListener("animationend", function(){
console.log("Animation ended.");
});
7:过渡事件示例
// 过渡事件示例
var myElement2 = document.getElementById("myElement2");
myElement2.addEventListener("transitionend", function(){
console.log("Transition ended.");
});
20:javaScript中this的指向?
答:JavaScript中的this关键字指向当前执行代码的上下文对象。具体来说,它指向调用当前函数的对象。如果函数没有被任何对象调用,则this指向全局对象(在浏览器中通常是window对象)。此外,this的值可以通过使用call()、apply()或bind()方法来显式地设置。
1. 作为函数调用,this指向全局对象window
// JavaScript中this的指向取决于函数的调用方式
// 1. 作为函数调用,this指向全局对象window
function test() {
console.log(this); // window
}
test();
2. 作为对象的方法调用,this指向该对象
// 2. 作为对象的方法调用,this指向该对象
var obj = {
name: 'Alice',
sayName: function() {
console.log(this.name);
}
};
obj.sayName(); // Alice
3. 作为构造函数调用,this指向新创建的对象
// 3. 作为构造函数调用,this指向新创建的对象
function Person(name) {
this.name = name;
}
var person = new Person('Bob');
console.log(person.name); // Bob
4. 使用apply或call方法调用,this指向传入的第一个参数
// 4. 使用apply或call方法调用,this指向传入的第一个参数
function sayHello() {
console.log('Hello, ' + this.name);
}
var obj1 = { name: 'Alice' };
var obj2 = { name: 'Bob' };
sayHello.apply(obj1); // Hello, Alice
sayHello.call(obj2); // Hello, Bob
21:call,apply,bind的区别?
答:call,apply,bind都是用来改变函数内部this指向的方法。
call和apply的作用是一样的,都是改变函数内部this指向,区别在于传参的方式不同。
call是一个一个传参,apply是以数组的形式传参。
bind方法则是返回一个新的函数,这个函数的this指向被绑定了,不会再改变。同时,bind方法也可以传参。
call示例
// call示例
def func1(a, b):
print(a + b)
func1.call(None, 1, 2) // 输出3
apply示例
//apply示例
def func2(a, b):
print(a + b)
func2.apply(None, [1, 2]) // 输出3
bind示例
// bind示例
def func3(a, b):
print(a + b)
new_func = func3.bind(None, 1)
new_func(2) // 输出3
22:Javascript作用链域?
答:JavaScript的作用域链是指在当前执行环境中,变量和函数的查找顺序。当代码在一个环境中执行时,会创建变量对象的一个作用域链,用于保证对执行环境有权访问的变量和函数的有序访问。作用域链的前端始终是当前执行环境的变量对象,全局执行环境的变量对象始终是作用域链的最后一个对象。
// Javascript作用域链
var a = 10;
function foo() {
var b = 20;
function bar() {
var c = 30;
console.log(a + b + c);
}
bar();
}
foo(); // 输出60
23:描述一下cookies,sessionStorage和localStorage的区别及用法?有几种前端储存的方式?这些方式的区别是什么?
答:
Cookies、sessionStorage和localStorage都是前端储存数据的方式,但它们之间有一些区别。
1. Cookies
Cookies是一种在客户端存储数据的方式,可以在浏览器和服务器之间传递数据。Cookies最初是为了解决HTTP协议无状态的问题而出现的,它可以存储一些用户信息,如用户名、密码等。Cookies的大小限制为4KB左右,且每个域名下的Cookies数量也有限制。Cookies的使用需要注意安全性问题,如防止XSS攻击、CSRF攻击等。
2. sessionStorage
sessionStorage是HTML5中新增的一种前端储存数据的方式,它可以在浏览器窗口关闭后自动清除数据。sessionStorage的大小限制为5MB左右,且只能在同一窗口或标签页中共享数据。sessionStorage的使用场景一般是在同一窗口或标签页中传递数据。
3. localStorage
localStorage也是HTML5中新增的一种前端储存数据的方式,它可以在浏览器关闭后仍然保留数据。localStorage的大小限制为5MB左右,且可以在同一域名下的不同窗口或标签页中共享数据。localStorage的使用场景一般是在不同窗口或标签页中传递数据。
前端储存数据的方式还有IndexedDB、Web SQL、Cache API等,它们之间的区别主要在于数据存储的方式、大小限制、使用场景等方面。IndexedDB是一种基于对象存储的数据库,可以存储大量数据;Web SQL是一种基于SQL语句的数据库,已经被废弃;Cache API是一种缓存数据的方式,可以提高网页的访问速度。
cookies
// 设置cookie
document.cookie = "username=John Doe; expires=Thu, 18 Dec 2022 12:00:00 UTC; path=/";
// 读取cookie
let username = document.cookie;
console.log(username);
sessionStorage
// 设置sessionStorage
sessionStorage.setItem("key", "value");
// 读取sessionStorage
let value = sessionStorage.getItem("key");
console.log(value);
localStorage
// 设置localStorage
localStorage.setItem("key", "value");
// 读取localStorage
let value = localStorage.getItem("key");
console.log(value);
24:JS里垃圾回收机制是什么,常用的是哪种,怎么处理的?
答:JavaScript中的垃圾回收机制是自动的,它会定期检查不再使用的变量和对象,并释放它们所占用的内存。常用的垃圾回收算法是标记清除算法,它会标记所有活动对象,然后清除所有未标记的对象。在JavaScript中,开发人员不需要手动处理垃圾回收,因为它是自动的。
// 代码示例
let a = {name: 'John'};
let b = {name: 'Mary'};
a.friend = b;
b.friend = a;
a = null;
b = null;
// 在这里,a和b的引用已经被释放,它们所占用的内存将被垃圾回收机制清除。
25:同步和异步的区别?
答:同步指的是程序按照代码的顺序依次执行,每一行代码都必须等待上一行代码执行完成后才能执行下一行代码。异步指的是程序不按照代码的顺序执行,而是在执行某些代码的同时,可以执行其他代码,不必等待上一行代码执行完成。在异步编程中,通常会使用回调函数、Promise、async/await等方式来处理异步操作。
// 同步代码示例
console.log("start"); //start
console.log("middle"); //middle
console.log("end"); //end
//结果
//start
//middle
//end
// 异步代码示例
console.log("start");
setTimeout(() => {
console.log("middle");
}, 1000);
console.log("end");
//结果
//start
//end
//middle
26:ES6 模块与 CommonJS 模块、AMD、CMD 的差异?
答:ES6 模块与 CommonJS 模块、
AMD、CMD 的主要差异在于其语法和加载方式。
ES6 模块使用 import 和 export 语句进行导入和导出,
而 CommonJS 模块使用 require 和 module.exports 语句进行导入和导出。
AMD 和 CMD 则是异步加载模块的规范,
AMD 使用 define 和 require 语句,
CMD 使用 define 和 require.async 语句。此外,
ES6 模块是静态的,意味着其导入和导出的模块名必须是确定的,
而 CommonJS、AMD、CMD 则是动态的,可以在运行时根据条件进行加载。
ES6 模块示例
// 导出模块
export const name = 'John';
export function sayHi() {
console.log('Hi!');
}
// 导入模块
import { name, sayHi } from './example.js';
CommonJS 模块示例
// 导出模块
module.exports = {
name: 'John',
sayHi: function() {
console.log('Hi!');
}
};
// 导入模块
const example = require('./example.js');
const name = example.name;
const sayHi = example.sayHi;
AMD 模块示例
// 定义模块
define(['./example.js'], function(example) {
return {
name: example.name,
sayHi: example.sayHi
};
});
// 加载模块
require(['./example.js'], function(example) {
const name = example.name;
const sayHi = example.sayHi;
});
CMD 模块示例
// 定义模块
define(function(require, exports, module) {
const example = require('./example.js');
exports.name = example.name;
exports.sayHi = example.sayHi;
});
// 加载模块
require(['./example.js'], function(example) {
const name = example.name;
const sayHi = example.sayHi;
});
27:数组对象有哪些原生方法,列举一下?
答:
数组对象有以下原生方法:
- push():向数组末尾添加一个或多个元素,并返回新的长度。
- pop():删除并返回数组的最后一个元素。
- shift():删除并返回数组的第一个元素。
- unshift():向数组开头添加一个或多个元素,并返回新的长度。
- slice():返回一个新的数组,包含从开始到结束(不包括结束)的所有元素。
- splice():向/从数组中添加/删除项目,然后返回被删除的项目。
- concat():连接两个或更多的数组,并返回结果。
- join():把数组的所有元素放入一个字符串。
- reverse():颠倒数组中元素的顺序。
- sort():对数组元素进行排序。
- indexOf():返回数组中第一个找到的元素的索引。
- lastIndexOf():返回数组中最后一个找到的元素的索引。
- forEach():为数组中的每个元素执行一次回调函数。
- map():通过指定函数处理数组的每个元素,并返回处理后的数组。
- filter():通过指定函数过滤数组的每个元素,并返回过滤后的数组。
- reduce():通过指定函数将数组元素(从左到右)合并为单个值。
- reduceRight():通过指定函数将数组元素(从右到左)合并为单个值。
- every():检测数组中的所有元素是否都符合指定条件。
- some():检测数组中的某些元素是否符合指定条件。
- find():返回数组中符合条件的第一个元素。
- findIndex():返回数组中符合条件的第一个元素的索引。
数组对象有以下原生方法代码示例:
- push():向数组末尾添加一个或多个元素,并返回新的长度。
// push()
const arr = [1, 2, 3, 4, 5];
arr.push(6);
console.log(arr); // [1, 2, 3, 4, 5, 6]
- pop():删除并返回数组的最后一个元素。
// pop()
const arr = [1, 2, 3, 4, 5];
arr.pop();
console.log(arr); // [1, 2, 3, 4]
- shift():删除并返回数组的第一个元素。
// shift()
const arr = [1, 2, 3, 4, 5];
arr.shift();
console.log(arr); // [2, 3, 4, 5]
- unshift():向数组开头添加一个或多个元素,并返回新的长度。
// unshift()
const arr = [1, 2, 3, 4, 5];
arr.unshift(1);
console.log(arr); // [1, 2, 3, 4, 5]
- slice():返回一个新的数组,包含从开始到结束(不包括结束)的所有元素。
// slice()
const arr = [1, 2, 3, 4, 5];
const slicedArr = arr.slice(1, 3);
console.log(slicedArr); // [2, 3]
- splice():向/从数组中添加/删除项目,然后返回被删除的项目。
// splice()
const arr = [1, 2, 3, 4, 5];
const splicedArr = arr.splice(2, 1, 6);
console.log(splicedArr); // [3]
console.log(arr); // [1, 2, 6, 4, 5]
- concat():连接两个或更多的数组,并返回结果。
// concat()
const arr = [1, 2, 3, 4, 5];
const arr2 = [7, 8, 9];
const concatenatedArr = arr.concat(arr2);
console.log(concatenatedArr); // [1, 2, 6, 4, 5, 7, 8, 9]
- join():把数组的所有元素放入一个字符串。
// join()
const arr = [1, 2, 3, 4, 5, 6];
const joinedArr = arr.join('-');
console.log(joinedArr); // "1-2-6-4-5-6"
- reverse():颠倒数组中元素的顺序。
// reverse()
const arr = [1, 2, 3, 4, 5, 6];
arr.reverse();
console.log(arr); // [6, 5, 4, 3, 2, 1]
- sort():对数组元素进行排序。
//sort()
const arr = [1, 2, 3, 4, 5, 6];
arr.sort();
console.log(arr); // [1, 2, 4, 5, 6]
- indexOf():返回数组中第一个找到的元素的索引。
// indexOf()
const arr = [1, 2, 3, 4, 5, 6];
const index = arr.indexOf(4);
console.log(index); // 3
- lastIndexOf():返回数组中最后一个找到的元素的索引。
// lastIndexOf()
const arr = [1, 2, 3, 4, 5, 6];
const lastIndex = arr.lastIndexOf(4);
console.log(lastIndex); // 3
- forEach():为数组中的每个元素执行一次回调函数。
// forEach()
const arr = [1, 2, 3, 4, 5, 6];
arr.forEach((item) => {
console.log(item);
}); // 1,2,3,4,5,6
- map():通过指定函数处理数组的每个元素,并返回处理后的数组。
// map()
const arr = [1, 2, 3, 4, 5, 6];
const mappedArr = arr.map((item) => {
return item * 2;
});
console.log(mappedArr); // [2, 4, 8, 10, 12]
- filter():通过指定函数过滤数组的每个元素,并返回过滤后的数组。
// filter()
const arr = [1, 2, 3, 4, 5, 6];
const filteredArr = arr.filter((item) => {
return item > 3;
});
console.log(filteredArr); // [4, 5, 6]
- reduce():通过指定函数将数组元素(从左到右)合并为单个值。
// reduce()
const arr = [1, 2, 3, 4, 5, 6];
const reducedArr = arr.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
});
console.log(reducedArr); // 21
- reduceRight():通过指定函数将数组元素(从右到左)合并为单个值。
// reduceRight()
const arr = [1, 2, 3, 4, 5, 6];
const reduceRightResult = arr.reduceRight((accumulator, currentValue) => {
return accumulator + currentValue;
});
console.log(reduceRightResult); // 21
- every():检测数组中的所有元素是否都符合指定条件。
// every()
const arr = [1, 2, 3, 4, 5, 6];
const everyResult = arr.every((item) => {
return item > 0;
});
console.log(everyResult); // true
- some():检测数组中的某些元素是否符合指定条件。
// some()
const arr = [1, 2, 3, 4, 5, 6];
const someResult = arr.some((item) => {
return item < 0;
});
console.log(someResult); // false
- find():返回数组中符合条件的第一个元素。
// find()
const arr = [1, 2, 3, 4, 5, 6];
const findResult = arr.find((item) => {
return item > 3;
});
console.log(findResult); // 4
- findIndex():返回数组中符合条件的第一个元素的索引。
// findIndex()
const arr = [1, 2, 3, 4, 5, 6];
const findIndexResult = arr.findIndex((item) => {
return item > 3;
});
console.log(findIndexResult); // 3