ECMAScript 6.0简称ES6,是Javasript语言的下一代标准,在2015年6月正式发布,之后采取了年份命名,如ES2015,ES6一般指ES2015,也可泛指“下一代JavaScript语言”。
各大浏览器对ES6的支持可以查看compat-table.github.io/compat-tabl…
语言和平台的关系
ECMASript是JavaScript的规格,JavaScript是ECMAScript的一种实现方式。
let和const命令
let和const只在代码块中生效,在同一代码块中不允许重复声明且不存在变量提升问题,推荐在日常编码中不使用var,主用const,配合使用let。
解构赋值
1.数组的解构赋值
let [a,b,c] = [1,2,3];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
let [x, ...y] = [1, 2, 3];
console.log(x); // 1
console.log(y); // [2, 3]
2.对象的解构赋值
对象的解构需要同名属性才会给对应的变量赋值
let {foo, bar} = {foo: 'hello', bar: 'world'};
console.log(foo); // hello
对象的解构可以设置默认值
let {foo, bar="张三"} = {foo: 'hello'};
console.log(foo,bar); // hello
3.字符串的解构赋值
let [a,b,c,d,e,...f] = 'hello world';
console.log(a,b,c,d,e); // h
console.log(f); // h
4.函数参数的解构赋值
function sum(x,y){
return x + y;
}
console.log(sum(1,2)); // 3
字符串的扩展
1.模版字符串
// 单行字符串
console.log(`In JavaScript '\n' is a line-feed.`);
// 多行字符串
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
2.字符串的扩展方法
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值 ,表示参数字符串是否在原字符串的尾部。
let str = "Hello World";
console.log(str.startsWith('He'));
console.log(str.includes('lo'));
console.log(str.endsWith('ld'));
支持第二个参数,表示开始搜索的位置
// 支持第二个参数
console.log(str.startsWith('World', 6));
console.log(str.endsWith('Hello',5));
console.log(str.includes('lo', 3));
数值的扩展
console.log( parseInt(12.34));
console.log( parseFloat("12.34#"));
console.log(Number.parseInt(12.34));
console.log(Number.parseFloat("12.34#"));
console.log(Number.isNaN(NaN));
console.log(Number.isInteger(12.1));
bigInt大整数
const a = 2172141653n;
const b = 15346349309n;
console.log(a + b); // 17518590962n
console.log(a * b); // 33334444555566667777n
console.log(Number(a)+Number(b)); //
console.log(Number(a)*Number(b)); // 普通数字计算会丢失精度
函数的扩展
ES6支持在形参中设置参数默认值
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello'); // Hello World
log('Hello', 'JavaScript'); // Hello JavaScript
log('Hello', '');
剩余参数
// 剩余参数
function sum(a,...args) {
console.log(a,args); // [1, 2, 3]
}
sum(1, 2, 3);
箭头函数
简化定义函数的代码
const arr = [1, 2, 3, 4, 5];
// 箭头函数写法
arr.filter(item => item % 2);
// 原写法
arr.filter(function(item) {
return item % 2;
});
箭头函数不会改变this的指向
const person = {
name: '张三',
age: 25,
// greet() {
// console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
// }
greet:()=>{
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
console.log(person.name); // 张三
console.log(person['age']); // 25
person.greet();
Class的继承
// 对象的继承
class Animal {
eat(){
console.log(`eating.`);
}
}
class Dog extends Animal {
constructor(name) {
super(); // 调用父类的构造函数
this.name = name;
}
bark() {
console.log(`${this.name} is barking.`);
}
}
const dog = new Dog('Tom');
dog.eat(); // eating.
dog.bark(); // Tom is barking.
对象的方法
Object.aissign复制对象
const a ={a:1};
const b ={b:2};
Object.assign(a, b); // 将 b 的属性复制到 a
console.log(a); // { a: 1, b: 2 }
Object.assign(a, b, {c:3}); // 可以传入多个对象
console.log(a); // { a: 1, b: 2, c: 3 }
const d = Object.assign({}, a, b); // 创建一个新的对象
console.log(d); // { a: 1, b: 2, c: 3 }
Object.is判断对象是否相等
// Object.is() 方法
console.log(Object.is('foo', 'foo')); // true
console.log(Object.is(a,d)); // false
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false
Object.keys(), Object.values(), Object.entries() ,Object.fromEntries(),Object.hasOwn方法
//Object.keys(), Object.values(), Object.entries() ,Object.fromEntries() 方法
const obj = {
a: 1,
b: 2,
c: 3,
};
Object.keys(obj).forEach((key) => {
console.log(`${key}: ${obj[key]}`); // 输出每个键值对
});
Object.values(obj).forEach((key) => {
console.log(`${key}`); // 输出每个键值对
});
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key}: ${value}`); // 输出每个键值对
});
console.log(
Object.fromEntries([
["a", 1],
["b", 2],
["c", 3],
])
);
console.log(Object.hasOwn(obj, 'a')); // true
Proxy
为对象设置访问代理 ,外界对该对象的访问,都必须通过这层拦截,因此可以对外界的访问进行过滤和改写。
const person = {
name: '张三',
age: 25,
}
const personProxy = new Proxy(person, {
get(target,property){
return property in target ? target[property] : `Property ${property} does not exist`;
},
set(target,property,value){
if (property === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
target[property] = value;
return true; // 表示设置成功
}
} )
console.log(personProxy.name); // 张三
console.log(personProxy.age=15); // 25
proxy对数组的监听
const list = []
const listProxy = new Proxy(list, {
set(target, property, value) {
if (property === target.length) {
throw new Error('Cannot set length directly');
}
target[property] = value;
console.log(value, 'added to list at index', property);
return true; // 表示设置成功
}
})
listProxy.push(1); // 添加元素
listProxy.push(2); // 添加元素
Reflect对象
统一了操作对象的API,让所有的Object操作变为函数行为。
Reflect.get(target, name, receiver) 获取值
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}
console.log(Reflect.get(myObject, 'foo')); // 1
console.log(Reflect.get(myObject, 'bar'));
console.log(Reflect.get(myObject, 'baz')); // 3
var myReceiverObject = {
foo: 4,
bar: 4,
};
// this 指向 receiver
console.log(Reflect.get(myObject, 'baz', myReceiverObject)); // 4
Reflect.set(target, name, receiver) 设置值
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}
var myReceiverObject = {
foo: 4,
bar: 4,
};
console.log(Reflect.set(myObject, 'foo', 10)); // true
console.log(Reflect.get(myObject, 'foo')); // 10
console.log(Reflect.set(myObject, 'aa',myReceiverObject))
console.log(Reflect.get(myObject, 'aa')); // 10
Reflect.deleteProperty(target, name);
删除对象的属性
Reflect.deleteProperty(myObject, 'foo'); // true
console.log(Reflect.get(myObject, 'foo'));
promise
let promise = new Promise((resolve, reject) => {
if (Math.random() < 0.5) {
resolve("成功");
} else {
reject("失败");
}
});
promise
.then((value) => {
console.log(value); // 成功
})
.catch((error) => {
console.log(error);
});
- Promise.all()等待所有Promise成功,任一失败则整体失败 并行请求且需全部成功
- Promise.race()以第一个完成的Promise结果为准(无论成功/失败) 请求超时控制
- Promise.any()等待第一个成功的Promise(ES2021,全部失败时抛AggregateError) 多源数据择优
- Promise.allSettled() 等待所有Promise完成,返回状态描述数组(无论成功/失败)
set数据类型
const set = new Set();
set.add(1).add(2).add(3);
console.log(set);
可以利用set数据特性用来数组去重
const set2 = new Set([1, 2, 3,4,2,3]);
console.log(set2);
Map数据类型
对象只能用字符串作为键,map可以用任意类型的值作为键
const map = new Map();
// 添加数据
map.set('name', '张三');
const o = { age: 18 };
map.set('age', o);
console.log(map);
symbol
适合作为对象的私有属性
const a = Symbol('a');
const b = Symbol('a');
console.log(a);
console.log(typeof a); // "symbol"
console.log(a === b); // false, 因为每个 Symbol 都是唯一的
for of循环
适合遍历所有数据结构
// for...of 循环可以遍历 Set 中的元素
const set = new Set([1,2,3,4,5,6,7,8,9,10]);
for (const item of set) {
console.log(item); // 1 2 3 4 5 6 7 8 9 10
}
// for...of 循环可以遍历 Map 中的键值对
const map = new Map([
['name', '张三'],
['age', 18]
]);
for (const [key, value] of map) {
console.log(`${key}: ${value}`); // name: 张三, age: 18
}
for of可以使用break终止循环
for (const item of set) {
if (item === 5) {
continue; // 遇到 5 时跳过当前循环
}
if (item === 8) {
break; // 遇到 8 时终止循环
}
console.log(item); // 1 2 3 4 5 6 7 8 9 10
}
Iterator可迭代接口
数组\对象\set\map都是可迭代对象
迭代器模式
特性:惰性执行
function * foo(params) {
console.log('111');
yield 100;
console.log('222');
yield 200;
console.log('333');
yield 300;
}
const generator = foo();
console.log(generator.next());
console.log(generator.next());
console.log(generator.next());
叫号器例子
function * createIdMaker(){
let id=1;
while(true){
yield id++;
}
}
const idMaker = createIdMaker();
console.log(idMaker.next().value); // 1
console.log(idMaker.next().value); // 2
console.log(idMaker.next().value);
Async/Await
Async/Await 是 ES2017 引入的语法糖,基于 Promise 实现,旨在以同步写法管理异步操作,彻底解决回调地狱问题。
async 声明函数:隐式返回 Promise 对象,若返回非 Promise 值,会被自动包装为 Promise.resolve(value)17。
await 表达式:暂停当前 async 函数执行,等待右侧 Promise 完成,并返回其解决值(若拒绝则抛出错误)
async function fetchData() {
try {
// 动态加载 JSON 文件
const data = await require('./data.json');
return data.users; // 返回用户数据
} catch (err) {
console.error("读取失败:", err);
return []; // 失败返回空数组
}
}
fetchData().then(users => {
console.log("用户数据:", users);
})
面试题
谈谈你对vue的理解?
vue是什么?
- vue是基于javascript的渐进式框架,单页面应用
vue的核心特性:
- 数据视图双向绑定(MVVM)(model view view-model )
- 组件化思想
- 响应式指令
说说你对双向绑定的理解?
什么是双向绑定?
我们可以先聊一下单向绑定,就是把model绑定到view,当使用JavaScript更新model的时候,view自动更新就是单向绑定。
当用户填表单的时候,此时会更新view,如果此时也可以自动更新model的状态,这时候可以认为model和view进行了双向绑定。
双向绑定的原理:
MVVM分为三部分:
数据层(Model):应用的数据及业务逻辑
视图层(View):应用的展示效果,各类UI组件
业务逻辑层(ViewModel):框架核心,将数据与视图关联起来
ViewModel的主要职责:
- 数据变化后更新视图
- 视图变化后更新数据
ViewModel的主要职责:
监听器(Observer):对所有属性进行监听
解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,绑定相应的更新函数