Common usage patterns
Block Scope and let/const
ES6 introduced the concept of block scope, where variables declared with let
and const
avoid issues like hoisting and global scope pollution. let
is used for mutable variables, while const
is used for immutable constants.
// Problem with var
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // Outputs 3, 3, 3
}
// Solution with let
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 100); // Outputs 0, 1, 2
}
// Usage of const
const PI = 3.14159;
// PI = 3.14; // Error: Assignment to constant variable
Block scope is particularly useful in scenarios like if
statements and for
loops, effectively preventing variable leakage and accidental overwrites.
Arrow Functions
Arrow functions are one of the most popular features in ES6. They simplify function expression syntax and automatically bind the current context's this
value.
// Traditional function
const numbers = [1, 2, 3];
const squares = numbers.map(function (n) {
return n * n;
});
// Simplified with arrow function
const cubes = numbers.map(n => n * n * n);
// this binding example
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++; // Arrow function automatically binds outer this
console.log(this.seconds);
}, 1000);
}
Arrow functions are ideal for callbacks and array methods but are not suitable as constructors or methods requiring dynamic this
.
Template Literals
Template literals use backticks (`
) for definition, support multiline text, and allow embedded expressions, greatly simplifying string concatenation.
const name = 'Alice';
const age = 28;
// Traditional concatenation
const greeting1 = 'Hello, ' + name + '! You are ' + age + ' years old.';
// Template literal
const greeting2 = `Hello, ${name}! You are ${age} years old.`;
// Multiline text
const html = `
<div class="container">
<h1>${name}</h1>
<p>Age: ${age}</p>
</div>
`;
// Expression evaluation
const total = `Total: ${5 * 10 + 3}`;
Template literals also support tagged templates for custom string processing:
function highlight(strings, ...values) {
return strings.reduce((result, str, i) =>
`${result}${str}<span class="highlight">${values[i] || ''}</span>`, '');
}
const output = highlight`Hello ${name}, you are ${age} years old.`;
Destructuring Assignment
Destructuring assignment allows extracting values from arrays or objects and assigning them to variables, greatly simplifying data extraction.
// Array destructuring
const colors = ['red', 'green', 'blue'];
const [firstColor, secondColor] = colors;
console.log(firstColor); // 'red'
// Object destructuring
const user = { name: 'Bob', age: 30, email: 'bob@example.com' };
const { name: userName, email } = user;
console.log(userName); // 'Bob'
// Function parameter destructuring
function greet({ name, age }) {
return `Hello ${name}, you are ${age} years old.`;
}
// Default values
const settings = { theme: 'dark' };
const { theme, fontSize = 16 } = settings;
// Nested destructuring
const company = {
name: 'Tech Corp',
employees: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
};
const { employees: [{ name: firstEmployeeName }] } = company;
Destructuring is particularly useful for functions returning multiple values, module imports, and similar scenarios.
Default Parameters and Rest Parameters
ES6 introduced default values and rest parameter syntax for function parameters, making function definitions more flexible.
// Default parameters
function createUser(name, role = 'user', isActive = true) {
return { name, role, isActive };
}
// Rest parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
// Combined with destructuring
function displayUser({ name, role = 'guest', ...otherProps }) {
console.log(`Name: ${name}, Role: ${role}`);
console.log('Other properties:', otherProps);
}
// Parameter collection
function logArguments(...args) {
args.forEach((arg, i) => console.log(`Argument ${i}:`, arg));
}
Rest parameters replace the traditional arguments
object, providing clearer syntax and true array functionality.
Spread Operator
The spread operator ...
expands iterable objects into individual elements, proving highly useful in array and object operations.
// Array spreading
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// Function calls
Math.max(...[1, 5, 3]); // Equivalent to Math.max(1, 5, 3)
// Object spreading
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// Shallow copying
const arrCopy = [...arr1];
const objCopy = { ...obj1 };
// Object merging
const defaults = { theme: 'light', fontSize: 14 };
const userSettings = { fontSize: 16 };
const finalSettings = { ...defaults, ...userSettings };
The spread operator is commonly used for array concatenation, object merging, function parameter passing, and similar scenarios.
Class Syntax
ES6 introduced prototype-based class syntax sugar, making object-oriented programming more intuitive.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name}`;
}
static createAnonymous() {
return new Person('Anonymous', 0);
}
}
class Employee extends Person {
constructor(name, age, position) {
super(name, age);
this.position = position;
}
work() {
return `${this.name} is working as ${this.position}`;
}
}
// Usage
const emp = new Employee('Alice', 30, 'Developer');
console.log(emp.greet());
console.log(emp.work());
Class syntax supports constructors, method definitions, static methods, inheritance, and other features, though it remains fundamentally prototype-based.
Module System
The ES6 module system provides standard import/export syntax, replacing non-standard solutions like CommonJS and AMD.
// math.js
export const PI = 3.14159;
export function square(x) {
return x * x;
}
export default class Calculator {
add(a, b) { return a + b; }
}
// app.js
import { PI, square } from './math.js';
import Calc from './math.js';
console.log(square(PI));
const calc = new Calc();
The module system supports named exports, default exports, renaming, and other features, forming the foundation of modern JavaScript applications.
Promises and Asynchronous Programming
Promises provide a more elegant solution for asynchronous programming, avoiding callback hell.
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
}
fetchData('https://api.example.com/data')
.then(data => {
console.log('Data received:', data);
return processData(data);
})
.then(processed => {
console.log('Processed data:', processed);
})
.catch(error => {
console.error('Error:', error);
});
// Promise static methods
Promise.all([fetchData(url1), fetchData(url2)])
.then(([data1, data2]) => {
console.log('All data received');
});
Promise.race([fetchData(url1), fetchData(url2)])
.then(firstResponse => {
console.log('First response received');
});
Promise chaining and composition methods make complex asynchronous flows more manageable.
Iterators and Generators
Iterators and generators provide the ability to customize iteration behavior, forming the basis of for...of
loops.
// Iterator protocol
const myIterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 3) {
return { value: step, done: false };
}
return { done: true };
}
};
}
};
for (const value of myIterable) {
console.log(value); // 1, 2, 3
}
// Generator function
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}
const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// Async generator
async function* fetchUrls(urls) {
for (const url of urls) {
const response = await fetch(url);
yield response.json();
}
}
Generators are particularly suitable for implementing lazy evaluation and asynchronous iteration.
Map and Set Data Structures
ES6 introduced new data structures like Map and Set to address limitations of Objects and Arrays.
// Map example
const userMap = new Map();
userMap.set('alice', { name: 'Alice', age: 30 });
userMap.set('bob', { name: 'Bob', age: 25 });
console.log(userMap.get('alice'));
console.log(userMap.size);
// Difference from Object
const objKey = { id: 1 };
userMap.set(objKey, 'Object as key');
console.log(userMap.get(objKey));
// Set example
const uniqueNumbers = new Set();
uniqueNumbers.add(1);
uniqueNumbers.add(2);
uniqueNumbers.add(1); // Duplicate value ignored
console.log(uniqueNumbers.size); // 2
console.log([...uniqueNumbers]); // [1, 2]
// WeakMap and WeakSet
const weakMap = new WeakMap();
const element = document.querySelector('.some-element');
weakMap.set(element, 'some data');
Map is ideal for key-value pairs, while Set is perfect for unique value collections. Both maintain insertion order and offer better performance.
Enhanced Object Literals
ES6 enhanced object literal syntax, making object definitions more concise and powerful.
const name = 'Alice';
const age = 30;
// Property shorthand
const user = { name, age };
// Method shorthand
const calculator = {
add(a, b) {
return a + b;
},
multiply(a, b) {
return a * b;
}
};
// Computed property names
const propName = 'status';
const dynamicObj = {
[propName]: 'active',
[`get${propName}`]() {
return this[propName];
}
};
// Object static methods
const defaults = { theme: 'light', fontSize: 14 };
const userSettings = { fontSize: 16 };
const finalSettings = Object.assign({}, defaults, userSettings);
console.log(Object.entries(finalSettings));
console.log(Object.values(finalSettings));
These enhancements reduce boilerplate code and make object operations more intuitive.
Proxy and Reflect
Proxy can intercept object operations, while Reflect provides a unified API for object operations.
// Proxy example
const target = { name: 'Alice' };
const handler = {
get(obj, prop) {
return prop in obj ? obj[prop] : 'Default';
},
set(obj, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
obj[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 'Alice'
console.log(proxy.unknown); // 'Default'
proxy.age = 30;
// Reflect example
const obj = { a: 1 };
console.log(Reflect.get(obj, 'a')); // 1
Reflect.set(obj, 'b', 2);
console.log(Reflect.has(obj, 'b')); // true
Proxy can be used for data validation, change observation, virtual property implementation, and other advanced features.
String and Regular Expression Enhancements
ES6 added numerous utility methods for strings and regular expressions.
// String methods
console.log('hello'.startsWith('he')); // true
console.log('hello'.endsWith('lo')); // true
console.log('hello'.includes('ell')); // true
console.log('x'.repeat(3)); // 'xxx'
// Template string tag functions
function upper(strings, ...values) {
let result = '';
for (let i = 0; i < strings.length; i++) {
result += strings[i];
if (i < values.length) {
result += String(values[i]).toUpperCase();
}
}
return result;
}
const name = 'alice';
const age = 30;
console.log(upper`Hello ${name}, you are ${age}`); // "Hello ALICE, you are 30"
// Regular expressions
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const match = regex.exec('2023-05-15');
console.log(match[1]); // '2023'
// Unicode support
console.log('𠮷'.length); // 2
console.log(Array.from('𠮷').length); // 1
These enhancements make string processing and regular expression matching more convenient and powerful.
Binary Data Handling
ES6 introduced ArrayBuffer and TypedArray for binary data processing.
// Creating ArrayBuffer
const buffer = new ArrayBuffer(16);
// Using TypedArray
const int32View = new Int32Array(buffer);
for (let i = 0; i < int32View.length; i++) {
int32View[i] = i * 2;
}
// Using DataView
const view = new DataView(buffer);
view.setInt16(0, 256, true); // Little-endian
console.log(view.getInt16(0, true));
// Blob and File
const blob = new Blob(['Hello, world!'], { type: 'text/plain' });
const file = new File(['File content'], 'example.txt', { type: 'text/plain' });
These APIs provide low-level support for WebGL, file operations, network communication, and similar scenarios.
Internationalization API
The Intl object provides language-sensitive string comparison, number formatting, and date formatting.
// Number formatting
const number = 123456.789;
console.log(new Intl.NumberFormat('de-DE').format(number)); // "123.456,789"
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(number)); // "$123,456.79"
// Date formatting
const date = new Date();
console.log(new Intl.DateTimeFormat('en-US').format(date)); // "5/15/2023"
console.log(new Intl.DateTimeFormat('ja-JP').format(date)); // "2023/5/15"
// String comparison
const names = ['Österreich', 'Andorra', 'Vietnam'];
console.log(names.sort(new Intl.Collator('de').compare)); // ["Andorra", "Österreich", "Vietnam"]
The Internationalization API enables applications to easily adapt to different regions and languages.
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:Proxy的性能考虑
下一篇:数组的扩展方法