1、ES6版本引入了哪些特性?(全部跟着写一遍,理解)
1.1let 和 const 关键字。
1.2箭头函数以及默认参数。
1.3模板字符串。
1.4解构赋值。
1.5Promise
1.6模块化
1.7扩展运算符
1.8Set 和 Map
1.1let 和 const 关键字
//let 和 const 关键字。
const name = '刘玉洁'
let sex = '女'
1.2箭头函数以及默认参数
//箭头函数以及默认参数
const fnOne = (age=19) => {
return `姓名: ${name},性别: ${sex},年龄${age}`
}
fnOne() // 姓名: 刘玉洁,性别: 女,年龄19
1.3模板字符串
//多行字符串 \n\换行
`
姓名:刘玉洁\n\
性别:女\n\
年龄:25
`
//输出:
//姓名:刘玉洁
//性别:女
//年龄:25
1.4解构赋值
//解构赋值
// 从数组中提取值并赋给变量
let [a,b,c] = [1,2,3];
console.log(a) // 1
console.log(b) // 2
console.log(c) // 3
// 交换变量的值
var x = 1;
var y = 2;
[x, y] = [y, x];
console.log(x); // 输出 2
console.log(y); // 输出 1
// 从对象中提取值并赋给变量
var {name, age} = {name: "Alice", age: 25};
console.log(name); // 输出 "Alice"
console.log(age); // 输出 25
// 为变量指定新的名称
var {name: n, age: s} = {name: "Alice", age: 25};
console.log(n); // 输出 "Alice"
console.log(s); // 输出 25
1.5Promise
const promise = new Promise((resolve,reject)=>{
if(true){
resolve('成功')
}else{
reject('失败')
}
})
promise.then(res=>{
// 成功回调
console.log(res)
},(reason)=>{
// 失败回调, 执行当前失败回调,catch回调将不会执行
console.log('reason: '+reason)
}).catch(reject=>{
// 失败回调
console.log(reject)
}).finally(()=>{
// promise 成功或失败都会执行finally回调
console.log('finally')
})
//Promise.all方法:
//接受一个Promise数组作为参数,并返回一个新的Promise。当所有的Promise都变为成功状态时,新的Promise的状态才会变为成功。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('1')
}, 500);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('2')
}, 2000);
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('3')
}, 1000);
})
var promises = [promise1, promise2, promise3];
Promise.all(promises).then(function (values) {
console.log(values)
// 处理所有Promise的成功状态 只要有一个promise没有返回,或者报错就不会返回
}).catch(function (reason) {
console.log('reason'+reason)
// 处理第一个Promise的失败状态
});
//Promise.race方法:接受一个Promise数组作为参数,并返回一个新的Promise。当任意一个Promise变为成功或失败状态时,新的Promise的状态就会变为相应的状态。
// 注意:1.如果同时有一个成功一个失败,会返回成功状态
Promise.race(promises).then(function (value) {
console.log(value)
// 处理第一个Promise的状态
}).catch(function (reason) {
console.log('reason',reason)
// 处理第一个Promise的状态
}).finally(() => {
// promise 成功或失败都会执行finally回调(返回第一个)
console.log('finally')
})
1.6模块化 export import
// init.js文件声明方法
const time = ()=>{
return new Date()
}
export default time
// vue 导入使用
import time from './init.js'
time()
1.7扩展运算符
//JavaScript中的扩展运算符(spread operator)可以用于展开数组或对象。它使用三个点(...)作为语法,可以将数组或对象的元素展开为独立的参数或属性。
在数组中使用扩展运算符可以将一个数组展开为多个独立的元素,例如:
const arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5, 6]; console.log(arr2); // [1, 2, 3, 4, 5, 6]
在对象中使用扩展运算符可以将一个对象的属性展开到另一个对象中,例如:
const obj1 = { a: 1, b: 2 }; const obj2 = { ...obj1, c: 3, d: 4 }; console.log(obj2); // { a: 1, b: 2, c: 3, d: 4 }
1.8Set 和 Map(注:Set和Map都是可迭代的,可以使用for...of循环遍历它们的元素)
//Set是一种类似于数组的数据结构,它的成员是唯一且无序的。Set中的元素不会重复,可以用来去除数组中的重复元素。Set提供了一些常用的方法,如add、delete、has等。
const set = new Set();
set.add(1).add(2).add(3).add(4).add(2).add(3).add(1)
console.log([...set]) // [1.2.3.4]
//Map是一种键值对的数据结构,它类似于对象,但键可以是任意类型。Map提供了一些常用的方法,如set、get、has等。
const map = new Map(); map.set('name', 'John'); map.set('age', 25);
console.log(map.get('name')); // John
console.log(map.has('age')); // true
map.delete('age');
console.log(map); // Map { 'name' => 'John' }
2、var、const 和 let 的主要区别是什么?(变量提升,作用域,重复声明,变量赋值,声明时初始化代码走一遍)
变量提升:var声明的变量存在变量提升,即在声明之前就可以使用变量。而const和let声明的变量不存在变量提升,必须在声明之后才能使用变量。
作用域:var声明的变量存在函数作用域,即在函数内部声明的变量在函数外部是不可访问的。而const和let声明的变量存在块级作用域,即在块(如if语句、for循环等)内部声明的变量在块外部是不可访问的。
重复声明:var可以重复声明同一个变量,而const和let不允许重复声明同一个变量。
变量赋值:var和let声明的变量可以重新赋值,而const声明的变量是常量,不允许重新赋值。
声明时初始化:var声明的变量和let声明的变量可以不进行初始化,而const声明的变量必须进行初始化。
3.什么是promise和 async-await
Promise是JavaScript中用于处理异步操作的对象。它可以将异步操作封装成一个Promise对象,通过then方法来处理异步操作的结果。Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当异步操作完成时,Promise对象的状态会从pending变为fulfilled或rejected,并调用相应的回调函数。
async/await是ES8中新增的用于处理异步操作的语法糖。它基于Promise,可以使异步代码看起来像同步代码,更加易读和易写。async函数是一个返回Promise对象的函数,可以在函数内部使用await关键字来等待一个Promise对象的状态变为fulfilled,并返回异步操作的结果。
async function fn() {
const data = await new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('111111111')
}, 1000);
})
console.log('22222222')
}
fn() // 一秒后输出 111111 2222222
注意:
1.await 只能在申明了async 的函数里面使用
2.await 后面必须跟随一个promise 如果跟随不是promise 会被自动转换为立即执行resolved的Promise对象,并将相应的值作为结果返回。
4.什么是闭包?
1.闭包可以理解为一个函数和其相关的引用环境的组合
2.闭包的作用:闭包可以用来创建私有变量和方法,实现模块化的编程。
3.闭包的弊端:内存泄漏,因为闭包会持有外部函数的变量和引用,导致这些变量无法被垃圾回收。因此,在使用闭包时需要注意内存的管理。
5. BOM 是什么?
BOM,也称为浏览器对象模型,用作浏览器的交互介质。默认对象是窗口,所有函数都可以直接调用,也可以通过指定窗口来调用。History、Screen、location,是 Window 的不同属性。
console.log(window)
6. DOM 是什么?
Document Object Model,俗称DOM,代表HTML文档,它用于更改 HTML 文档的内容。
console.log(document)
7.js数据克隆方法
//1.JSON.parse(JSON.stringify(obj));
const copyobj = JSON.parse(JSON.stringify(obj)); // 函数不能clone
//2....运算符
const copyobj = { ...obj }; // 只能clone 第一层
//3.structuredClone方法
const copyobj = window.structuredClone(obj); // 函数不能clone
//4.创建一个函数克隆所有元素
function clone(obj) {
var o;
if (typeof obj == "object") {
if (obj === null) {
o = null;
} else {
if (obj instanceof Array) {
o = [];
for (var i = 0, len = obj.length; i < len; i++) {
o.push(clone(obj[i]));
}
} else {
o = {};
for (var j in obj) {
o[j] = clone(obj[j]);
}
}
}
} else {
o = obj;
}
return o;
}
8.如何判断数据类型
8.1 typeof:用于判断基本数据类型,返回字符串类型的值
typeof undefined; // "undefined"
typeof true; // "boolean"
typeof 123; // "number"
typeof "hello"; // "string"
typeof BigInt(123); // "bigint"
typeof Symbol("foo"); // "symbol"
typeof {}; // "object"
typeof []; // "object"
typeof null; // "object"
8.2 instanceof:用于判断对象的类型,返回布尔值。
const arr = [1, 2, 3];
arr instanceof Array; // true
const obj = { name: "Tom" };
obj instanceof Object; // true
function Person(name) {
this.name = name;
}
const person = new Person("Jack");
person instanceof Person; // true
8.3Object.prototype.toString.call():可以判断所有的类型,返回字符串类型的值。
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call("hello"); // "[object String]"
Object.prototype.toString.call(BigInt(123)); // "[object BigInt]"
Object.prototype.toString.call(Symbol("foo")); // "[object Symbol]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call([]); // "[object Array]"
9.数组的常用方法
const list = [1,2,3 ,4];
// 数组后面新增
list.push(1)
console.log(list) // [1, 2, 3, 4, 1]
// 删除数组最后面一个
list.pop()
console.log(list) // [1, 2, 3]
//数组前面新增
list.unshift(5,34)
console.log(list) // [5,34,1, 2, 3, 4]
//删除数组最前面一个元素
list.shift()
console.log(list) // [ 2, 3, 4]
// splice 改变原数组 , 下标为0开始,截取长度为1,其余参数都为新增参数
list.splice(0,1,5)
console.log(list) //[5,1,2,3]
// slice 原数组不变 , 下标1开始(包括),截取到下标3(不包括)
const newList = list.slice(1,3)
console.log(newList) //[2, 3]
// reverse 改变元数组 反转数组
list.reverse()
console.log(list) //[4, 3, 2, 1]
// join 数组转字符串
const newList = list.join(',');
console.log(newList) //1,2,3,4
// forEach 循环
list.forEach((item,index)=>{
list[index] = ++item
})
console.log(list) //[2, 3, 4, 5]
// map 不改变原数组,生成新数组
const newList = list.map((item, index) => ++item)
console.log(newList) //[2, 3, 4, 5]
// filter 过滤返回匹配的所有项生成数组
const newList = list.filter(item => item > 3)
console.log(newList) //[4]
// find 返回匹配的第一项
const newList = list.find(item => item > 2)
console.log(newList) //3
// every 数组元素全部满足条件返回true
const newList = list.every(item => item >=1)
console.log(newList) //true
// some 数组元素有一个满足条件返回true
const newList = list.some(item => item >=1)
console.log(newList) //true
// reduce 累加器,传入一个函数和初始值
// 函数里面有两个值
// preValue 累加后的值
// curValue 每一项
const newList = list.reduce((preValue, curValue) =>{
return preValue+curValue
},10)
console.log(newList) //20
10.数组去重的几种方法
10.1 new Set 去重
const list = [1, 2, 3, 4, 1, 2, 3, 4, 5];
// new Set 去重
const oneList = [...new Set(list)];
console.log(oneList);
10.2 filter 去重
const list = [1, 2, 3, 4, 1, 2, 3, 4, 5];
// filter 去重
const newList = list.filter((item, index, array) => {
return array.indexOf(item) === index;
});
console.log(newList);
10.3 reduce+includes 去重
const twoList = list.reduce((array, b) => {
return array.includes(b) ? [...array] : [...array, b];
}, []);
console.log(twoList);
10.4 reduce+indexOf 去重
const twoList = list.reduce((array, b) => {
const bol = !!~array.indexOf(b);
return bol ? [...array] : [...array, b];
}, []);
console.log(twoList);
10.5 reduce 去重数组对象
const list = [
{ a: 1, b: 2 },
{ a: 1, b: 2 },
{ a: 1, b: 3 },
];
const twoList = list.reduce((array, b) => {
const bol = !!~JSON.stringify(array).indexOf(JSON.stringify(b));
return bol ? [...array] : [...array, b];
}, []);
console.log(twoList); // [ { a: 1, b: 2 }, { a: 1, b: 3 }]
11.bind、call、apply 区别
总结:
bind 方法返回一个新的函数,并可以预先绑定上下文和参数。
call 方法立即调用函数,并传递指定的上下文和参数作为参数。
apply 方法立即调用函数,并传递指定的上下文以及参数数组作为参数。
11.1 bind 方法会创建一个新函数,将其绑定到指定的对象,并返回这个新函数。新函数可以在之后的调用中作为普通函数被调用,也可以作为构造函数使用(使用 new 运算符)。bind 方法可以传递参数给原函数,这些参数会预先传入到新函数中。 例如:
const obj = { name: 'John' };
function getName() {
console.log(this.name);
}
const boundGetName = getName.bind(obj);
boundGetName(); // 输出:John
11.2 call 方法和 apply 方法都可以立即调用一个函数,并且可以显式地设置函数执行时的上下文(this 值)。唯一的区别在于传递参数的方式不同。
11.2.1call 方法接受一个指定的上下文对象和一系列参数作为参数,并将函数立即执行。 例如:
const obj = { name: 'Sarah' };
function sayHello(message) {
console.log(`${message}, ${this.name}!`);
}
sayHello.call(obj, 'Hello'); // 输出:Hello, Sarah!
11.2.2 apply 方法也接受一个指定的上下文对象和一个参数数组作为参数,并将函数立即执行。不同的是,参数被传递为数组。 例如:
const obj = { name: 'Emily' };
function sayHello(message) {
console.log(`${message}, ${this.name}!`);
}
sayHello.apply(obj, ['Hello']); // 输出:Hello, Emily!
12 什么是js执行上下文
JavaScript 执行上下文(Execution Context)是 JavaScript 引擎在执行代码时创建的一个环境。每当 JavaScript 代码执行时,都会创建一个执行上下文,并且这些执行上下文被组织为一个执行上下文栈(Execution Context Stack)。
每个执行上下文包含了三个重要的组成部分:
1.变量对象(Variable Object):用于存储变量和函数声明。变量对象可以看作是当前上下文中的作用域链的一部分。在全局执行上下文中,变量对象被称为全局对象(Global Object)。
2.作用域链(Scope Chain):用于解析变量和函数的访问权限。它是由当前执行上下文的变量对象以及其上层执行上下文的变量对象构成的链式结构。
3.this 值(This Value):指向当前执行上下文所属的对象。
JavaScript 的执行上下文可以包括全局执行上下文(Global Execution Context)、函数执行上下文(Function Execution Context)和 eval 函数执行上下文。
全局执行上下文是最顶层的执行上下文,它在代码开始执行时创建,全局变量和函数声明都会被添加到全局执行上下文的变量对象中。
函数执行上下文,在调用函数时创建,每次函数调用都会创建一个新的函数执行上下文,函数参数、局部变量和内部函数都会被添加到函数执行上下文的变量对象中。
eval 函数执行上下文是通过 eval 函数执行代码时创建的,只有在代码含有 eval 函数调用时才会生成 eval 函数执行上下文。
当 JavaScript 引擎执行代码时,它会根据执行上下文栈(Execution Context Stack)的顺序依次执行各个执行上下文,当前执行上下文执行完成后,会弹出执行上下文栈,并开始执行上一个执行上下文,直到最后一个执行上下文执行完毕,整个代码执行过程结束。
通过理解和管理执行上下文,我们可以更好地理解 JavaScript 代码的执行过程,并且能够正确地访问和修改变量、了解作用域规则以及正确理解 this 的指向。