ES6基础语法介绍
概述
ECMAScript 6(简称 ES6)是 JavaScript 语言的一个重要版本,它引入了许多新的语法和特性,使得 JavaScript 更加强大和易于使用。以下是一些基础的 ES6 语法及其详细说明:
1. 变量声明:let 和 const
-
let:用于声明一个块作用域的局部变量,并且可以选择性地进行初始化。
let message = "Hello, ES6!"; let count;
-
const:用于声明一个块作用域的常量,必须在声明时进行初始化,且声明后不能被重新赋值。
const pi = 3.14159;
2. 模板字符串
模板字符串使用反引号(`)定义,允许嵌入表达式,并且可以进行多行定义。
let name = "Kimi";
let greeting = `Hello, ${name}!`;
console.log(greeting); // 输出:Hello, Kimi!
let multiLine = `
This is a
multi-line string.
`;
3. 解构赋值
解构赋值允许你从数组或对象中提取数据,并赋值给新的变量。
-
数组解构:
let scores = [80, 90, 70]; let [score1, score2, score3] = scores;
-
对象解构:
let person = { name: "Alice", age: 25 }; let { name, age } = person;
4. 箭头函数
箭头函数提供了一种更简洁的方式来写函数表达式。
let add = (a, b) => a + b;
如果函数体只有一条语句,可以省略 return
关键字和花括号。
let multiply = (a, b) => a * b;
5. 默认参数值
函数参数可以设置默认值,当函数被调用时没有提供该参数,则使用默认值。
function greet(name = "Guest") {
console.log(`Hello, ${name}!`);
}
6. 类(Classes)
ES6 引入了 class
语法,使得定义类和基于类的继承更加直观和简洁。
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
get area() {
return this.width * this.height;
}
set width(value) {
if (value > 0) this._width = value;
}
set height(value) {
if (value > 0) this._height = value;
}
}
7. 模块
ES6 引入了模块功能,允许你创建可复用的代码块,每个模块都有自己的作用域。
// math.js
export function add(a, b) {
return a + b;
}
// app.js
import { add } from './math.js';
console.log(add(2, 3)); // 输出:5
8. 扩展运算符(Spread Operator)
扩展运算符 ...
允许一个表达式被展开在需要多个参数(函数调用)或多个元素(数组字面量)或多个键值对(对象字面量)的地方。
-
函数调用:
function sum(x, y, z) { return x + y + z; } let numbers = [1, 2, 3]; console.log(sum(...numbers)); // 输出:6
-
数组字面量:
let parts = ['shoulders', 'knees']; let lyrics = ['head', ...parts, 'and', 'toes'];
-
对象字面量:
let obj1 = { foo: 'bar', x: 42 }; let obj2 = { foo: 'baz', y: 13 }; let clonedObj = { ...obj1 }; let mergedObj = { ...obj1, ...obj2 };
9. 对象字面量增强
ES6 增强了对象字面量的语法,允许在字面量中直接定义方法、使用属性值简写等。
let obj = {
name: "Alice",
getName() {
return this.name;
}
};
10. 符号(Symbols)
符号是一种新的基本数据类型,它是不可变的,可以用作对象的属性。
let mySymbol = Symbol('mySymbol');
let obj = {
[mySymbol]: 'Hello'
};
console.log(obj[mySymbol]); // 输出:Hello
11. 迭代器(Iterators)和生成器(Generators)
迭代器允许你定义对象的遍历接口,而生成器则是一种更简洁的迭代器实现方式。
function* idGenerator() {
let id = 1;
while (true) {
yield id;
id++;
}
}
let gen = idGenerator();
console.log(gen.next().value); // 输出:1
console.log(gen.next().value); // 输出:2
12. 承诺(Promises)
承诺是异步编程的一种解决方案,它代表了异步操作的最终完成(或失败)及其结果值。
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then((value) => {
console.log(value); // 输出:Success!
}).catch((error) => {
console.error(error);
});
这些特性构成了 ES6 的基础,它们极大地丰富了 JavaScript 的功能,并使得代码更加简洁和易于维护。
基本数据类型
在 ES6 中,JavaScript 的数据类型得到了扩展,增加了一种新的基本数据类型——符号(Symbol)。以下是 ES6 中的基础数据类型及其说明:
1. 字符串(String)
字符串类型在 ES6 中没有变化,仍然是由字符组成的文本,可以使用单引号、双引号或反引号(模板字符串)来定义。
let message = "Hello, ES6!";
let greeting = 'Hello, ES6!';
let multiLine = `
This is a
multi-line string.
`;
2. 数字(Number)
数字类型同样没有变化,可以表示整数或浮点数。
let integer = 42;
let float = 3.14159;
ES6 引入了一些新的数值常量:
let maxInteger = Number.MAX_SAFE_INTEGER; // 9007199254740991
let minInteger = Number.MIN_SAFE_INTEGER; // -9007199254740991
let maxFloat = Number.MAX_VALUE; // 1.7976931348623157e+308
let minFloat = Number.MIN_VALUE; // 5e-324
let epsilon = Number.EPSILON; // 2.220446049250313e-16
let infinity = Number.POSITIVE_INFINITY; // Infinity
let negativeInfinity = Number.NEGATIVE_INFINITY; // -Infinity
let notANumber = Number.NaN; // NaN
3. 布尔值(Boolean)
布尔类型用于表示逻辑值 true
或 false
。
let isDone = false;
let hasError = true;
4. 未定义(Undefined)
未定义类型表示变量已声明但未初始化时的值。
let sample;
console.log(sample); // 输出:undefined
5. 空值(Null)
空值类型表示“无”或“空”的意图。
let nothing = null;
6. 符号(Symbol)
符号是 ES6 引入的一种新的基本数据类型,它用于创建唯一的、不可变的标识符。
let mySymbol = Symbol('mySymbol');
符号可以用作对象的属性键,以确保不会与其他属性键冲突。
7. 对象(Object)
对象类型在 ES6 中仍然是键值对的集合,可以是字典、数组、函数等。
let obj = {
name: "Alice",
age: 25
};
8. 数组(Array)
数组类型用于表示有序集合,可以包含任意类型的元素。
let numbers = [1, 2, 3, 4, 5];
9. 函数(Function)
函数类型在 ES6 中仍然是可执行的代码块,可以带有参数和返回值。
function add(a, b) {
return a + b;
}
10. 整数(BigInt)
ES2020(ES11)引入了一种新的数值类型 BigInt
,用于表示大于 Number.MAX_SAFE_INTEGER
的整数。
let bigInt = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
BigInt
类型的值以 n
结尾,例如 123n
。
这些基础数据类型构成了 ES6 中 JavaScript 的基础,使得 JavaScript 能够更好地处理各种数据,并提供了更多的编程工具。
对象属性迭代
对象属性迭代
在 ES6 中,对象属性迭代可以通过几种不同的方法来实现。这些方法允许你访问对象中的属性,无论是通过传统的 for...in
循环,还是通过新的 Object.keys()
、Object.values()
和 Object.entries()
方法。
1. for...in
循环
for...in
循环可以遍历一个对象的所有可枚举属性,包括其原型链上的属性。
const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key]);
}
}
在这个例子中,hasOwnProperty
方法用于过滤掉原型链上的属性,只处理对象自身的属性。
2. Object.keys()
Object.keys()
方法返回一个包含对象自身可枚举属性名称的数组。
const obj = { a: 1, b: 2, c: 3 };
Object.keys(obj).forEach(key => {
console.log(key, obj[key]);
});
这个方法不会遍历原型链上的属性。
3. Object.values()
Object.values()
方法返回一个包含对象自身可枚举属性值的数组。
const obj = { a: 1, b: 2, c: 3 };
Object.values(obj).forEach(value => {
console.log(value);
});
同样,这个方法也不会遍历原型链上的属性。
4. Object.entries()
Object.entries()
方法返回一个给定对象自身可枚举属性的键值对数组,每个键值对是键和值的数组。
const obj = { a: 1, b: 2, c: 3 };
Object.entries(obj).forEach(([key, value]) => {
console.log(key, value);
});
这个方法提供了对象属性的键和值的访问方式,也不会遍历原型链上的属性。
5. Reflect.ownKeys()
Reflect.ownKeys()
方法返回一个由目标对象自身的属性键组成的数组。
const obj = { a: 1, b: 2, c: 3 };
Reflect.ownKeys(obj).forEach(key => {
console.log(key, obj[key]);
});
这个方法会返回所有自有属性键,无论它们是否可枚举,也不论它们是否不可枚举。
6. 使用 Symbol
属性
如果对象属性是 Symbol
类型,那么 Object.keys()
、Object.values()
和 Object.entries()
默认不会返回这些属性。要迭代包含 Symbol
属性的对象,你需要使用 Object.getOwnPropertySymbols()
方法。
const obj = { a: 1, [Symbol('b')]: 2, c: 3 };
Object.getOwnPropertySymbols(obj).forEach(symbol => {
console.log(symbol, obj[symbol]);
});
7. 使用 for...of
循环和 Map
迭代器
如果你需要迭代一个 Map
对象,可以使用 for...of
循环和 Map
的迭代器。
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const [key, value] of map) {
console.log(key, value);
}
这些方法提供了灵活的方式来迭代对象属性,你可以根据具体需求选择合适的方法。
数组迭代
在 ES6 中,数组迭代可以通过多种方式实现,包括传统的循环、数组方法以及迭代器。以下是一些常用的数组迭代方法:
1. for
循环
传统的 for
循环允许你访问数组的索引和元素。
const array = [1, 2, 3, 4, 5];
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
2. for...of
循环
for...of
循环提供了一种简洁的方式来迭代可迭代对象,包括数组。
const array = [1, 2, 3, 4, 5];
for (const value of array) {
console.log(value);
}
3. forEach
方法
forEach
方法对数组的每个元素执行一次提供的函数。
const array = [1, 2, 3, 4, 5];
array.forEach((value, index) => {
console.log(value, index);
});
4. map
方法
map
方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
const array = [1, 2, 3, 4, 5];
const newArray = array.map(value => value * 2);
console.log(newArray); // [2, 4, 6, 8, 10]
5. filter
方法
filter
方法创建一个新数组,包含通过所提供函数实现的测试的所有元素。
const array = [1, 2, 3, 4, 5];
const filteredArray = array.filter(value => value > 2);
console.log(filteredArray); // [3, 4, 5]
6. reduce
方法
reduce
方法对数组中的每个元素执行一个由你提供的“reducer”函数(升序执行),将其结果汇总为单个返回值。
const array = [1, 2, 3, 4, 5];
const sum = array.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 15
7. some
方法
some
方法测试数组中是不是至少有一个元素通过了被提供的函数测试。它返回的是一个布尔值。
const array = [1, 2, 3, 4, 5];
const hasEven = array.some(value => value % 2 === 0);
console.log(hasEven); // true
8. every
方法
every
方法测试数组的所有元素是否都通过了指定函数的测试。它返回的是一个布尔值。
const array = [1, 2, 3, 4, 5];
const allPositive = array.every(value => value > 0);
console.log(allPositive); // true
9. find
方法
find
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
。
const array = [1, 2, 3, 4, 5];
const firstEven = array.find(value => value % 2 === 0);
console.log(firstEven); // 2
10. findIndex
方法
findIndex
方法返回数组中满足提供的测试函数的第一个元素的索引。若没有满足条件的元素则返回 -1
。
const array = [1, 2, 3, 4, 5];
const firstEvenIndex = array.findIndex(value => value % 2 === 0);
console.log(firstEvenIndex); // 1
11. keys
方法
keys
方法返回一个包含数组中每个索引键的新 Array Iterator
对象。
const array = [1, 2, 3, 4, 5];
const iterator = array.keys();
for (const key of iterator) {
console.log(key); // 0, 1, 2, 3, 4
}
12. values
方法
values
方法返回一个包含数组中每个索引值的新 Array Iterator
对象。
const array = [1, 2, 3, 4, 5];
const iterator = array.values();
for (const value of iterator) {
console.log(value); // 1, 2, 3, 4, 5
}
13. entries
方法
entries
方法返回一个包含数组中每个索引的键值对的新 Array Iterator
对象。
const array = [1, 2, 3, 4, 5];
const iterator = array.entries();
for (const [index, value] of iterator) {
console.log(index, value); // 0 1, 1 2, 2 3, 3 4, 4 5
}
这些方法提供了灵活且强大的方式来迭代数组,你可以根据具体需求选择合适的方法。
this指代
在 JavaScript 中,this
是一个关键字,它指向当前执行上下文(execution context)中的对象。this
的值在函数调用时确定,它可以是全局对象、调用函数的对象、构造函数、或者由 bind
、call
、apply
方法指定的对象。以下是 this
在不同情况下的详细说明:
全局上下文
在全局执行上下文中(在任何函数体外部),this
指向全局对象。在浏览器中,全局对象是 window
;在 Node.js 中,全局对象是 global
。
console.log(this); // 在浏览器中输出 window 对象,在 Node.js 中输出 global 对象
函数调用
在普通函数调用中,this
指向全局对象(非严格模式)或 undefined
(严格模式)。
function normalFunction() {
console.log(this); // 非严格模式下输出 window 对象,严格模式下输出 undefined
}
normalFunction();
对象方法
在对象的方法中,this
指向调用该方法的对象。
const obj = {
myMethod: function() {
console.log(this); // 输出 obj 对象
}
};
obj.myMethod();
构造函数
在构造函数中,this
指向新创建的对象实例。
function MyConstructor() {
this.myProperty = 'value';
}
const myInstance = new MyConstructor();
console.log(myInstance.myProperty); // 输出 'value'
箭头函数
箭头函数不绑定自己的 this
,它们继承所在上下文的 this
值。
const obj = {
myMethod: function() {
const arrowFunction = () => {
console.log(this); // 输出 obj 对象,因为箭头函数继承了这个上下文的 this
};
arrowFunction();
}
};
obj.myMethod();
bind
、call
、apply
方法
使用 bind
、call
或 apply
方法调用函数时,this
被显式指定为方法的第一个参数。
function myFunction() {
console.log(this);
}
const myBoundFunction = myFunction.bind({ myProperty: 'value' });
myBoundFunction(); // 输出 { myProperty: 'value' }
const myObject = { myProperty: 'value' };
myFunction.call(myObject); // 输出 myObject
myFunction.apply(myObject); // 输出 myObject
DOM 事件处理
在 DOM 事件处理函数中,this
指向触发事件的元素。
document.getElementById('myElement').addEventListener('click', function() {
console.log(this); // 输出被点击的 DOM 元素
});
类方法
在类的方法中,this
指向类的实例。
class MyClass {
myMethod() {
console.log(this); // 输出 MyClass 的实例
}
}
const myInstance = new MyClass();
myInstance.myMethod(); // 输出 MyClass 的实例
理解 this
的行为对于编写正确的 JavaScript 代码至关重要。在不同的上下文中,this
的值可能会有很大差异,因此在使用时需要格外注意。
箭头函数和常规函数在this上有何不同?
箭头函数和常规函数(即函数表达式和函数声明)在处理 this
关键字时有着本质的不同。这些差异主要源于箭头函数不绑定自己的 this
,而是捕获其所在上下文的 this
值作为自己的 this
值。
常规函数(函数表达式和函数声明)
在常规函数中,this
的值是在函数被调用时确定的,这取决于函数的调用方式:
- 在全局执行上下文中(在任何函数体外部),
this
指向全局对象(在浏览器中是window
,在 Node.js 中是global
)。 - 在普通函数调用中,
this
指向全局对象(非严格模式)或undefined
(严格模式)。 - 在对象方法中,
this
指向调用该方法的对象。 - 在构造函数中,
this
指向新创建的对象实例。 - 使用
bind
、call
、apply
方法调用函数时,this
被显式指定为方法的第一个参数。
function normalFunction() {
console.log(this); // 全局对象或 undefined
}
normalFunction();
const obj = {
method: function() {
console.log(this); // 指向 obj
}
};
obj.method();
const boundFunction = (function() {
console.log(this); // 全局对象或 undefined
}).bind(obj);
boundFunction();
箭头函数
箭头函数不绑定自己的 this
,它们继承所在上下文的 this
值:
- 在全局执行上下文中,箭头函数的
this
指向全局对象。 - 在对象方法中,箭头函数的
this
指向对象。 - 在构造函数中,箭头函数的
this
指向全局对象,因为箭头函数不能用作构造函数。 - 使用
bind
、call
、apply
方法调用箭头函数时,this
不会改变,因为这些方法不能改变箭头函数的this
值。
const arrowFunction = () => {
console.log(this); // 全局对象
};
arrowFunction();
const obj = {
arrowMethod: () => {
console.log(this); // 全局对象
}
};
obj.arrowMethod();
const arrowFunctionWithThis = (function() {
return () => {
console.log(this); // 全局对象
};
})();
arrowFunctionWithThis()();
总结
箭头函数和常规函数的主要区别在于 this
的处理方式。箭头函数不绑定自己的 this
,而是捕获其所在上下文的 this
值,这使得箭头函数在需要引用外层 this
值时非常有用。然而,这也意味着箭头函数不能用作构造函数,因为它们没有自己的 this
绑定。