1.let和const以及与var区别
1.1 作用域
var:
变量提升(Hoisting):var 声明的变量会被提升到其作用域的顶部,但赋值不会提升。这意味着你可以在声明之前引用该变量(但会得到 undefined)。
console.log(llb);
var llb="123456789";
函数作用域:var 声明的变量在整个函数内都是可访问的,即使它们在代码块(如 if 语句或 for 循环)内声明。
let、const:
块级作用域:块是由 {} 包围的代码块。
没有变量提升:
//如果尝试在声明之前访问 let 变量,会抛出 ReferenceError
console.log(xi);
let xi='123456789';
常量:一旦 const 变量被赋值,其值就不能被重新赋值(但如果是对象或数组,其内容可以被修改)。
1.2 重复声明
var:
可以在同一作用域内多次声明同一个变量而不会报错。
let 和 const:
不允许在同一作用域内重复声明同一个变量,否则会抛出 SyntaxError。
1.3 重新赋值
var 和 let:
可以在声明后重新赋值。
const:
必须在声明时初始化,并且之后不能重新赋值(但如果是对象或数组,其内容仍然可以修改)
// let 示例
if (true) {
let y = 20;
console.log(y); // 输出: 20
}
// console.log(y); // 会抛出 ReferenceError,因为 let 有块级作用域
// const 示例
const z = { value: 30 };
console.log(z.value); // 输出: 30
z.value = 40;
console.log(z.value); // 输出: 40,对象内容可以修改
// z = {}; // 会抛出 TypeError,因为 const 不能重新赋值
2.解构赋值
一、数组解构赋值
数组解构允许直接从数组中提取值,将它们赋给声明的变量。使用方括号[]
包围变量名,并与待解构的数组相对应。
- 基本用法:
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a); // 输出 1
console.log(b); // 输出 2
console.log(c); // 输出 3
- 忽略某些值:
如果解构的变量数量少于数组中的元素,未指定的元素将被忽略。
const [x, y] = [1, 2, 3, 4];
console.log(x); // 输出 1
console.log(y); // 输出 2
- 设置默认值:
以防解构的变量在数组中不存在,可以设置默认值。
const [x = 10, y = 20] = [1, 2];
console.log(x); // 输出 1
console.log(y); // 输出 2
注意,如果数组成员的值不严格等于undefined
,默认值不生效(null
的话相应值依然为null
)。
- 使用剩余参数:
使用剩余参数...rest
可以捕获数组中未指定的其余元素。
const [x, y, ...rest] = [1, 2, 3, 4, 5];
console.log(x); // 输出 1
console.log(y); // 输出 2
console.log(rest); // 输出 [3, 4, 5]
数组套数组的时候,可以使用同样的结构对应原数组,解构出对应的值。
let [a, [b, c, d]] = [1, [3, 4, 5]];
console.log(a, b, c, d); // 输出 1, 3, 4, 5
二、对象解构赋值
对象解构允许从对象中提取数据,并将它们赋值给声明的变量,这些变量名需要与对象的属性名相匹配(除非显式指定别名)。使用花括号{}
包围变量名和它们对应的属性名。
- 基本用法:
const obj = { name: 'Alice', age: 25 };
const { name, age } = obj;
console.log(name); // 输出 Alice
console.log(age); // 输出 25
- 设置别名:
可以为解构的属性设置别名。
const { name: userName, age: userAge } = obj;
console.log(userName); // 输出 Alice
console.log(userAge); // 输出 25
- 设置默认值:
对象解构赋值同样支持默认值。
const { address = 'Unknown' } = obj;
console.log(address); // 输出 Unknown
注意,对象解构中的默认值生效条件是对象属性值严格等于undefined,null不会生效,解构失败值为undefined
- 剩余属性:
使用剩余参数...
可以捕获对象中未指定的其余属性。
const { address = 'Unknown', ...otherInfo } = obj;
console.log(address); // 输出 Unknown
console.log(otherInfo); // 输出 { age: 25 }
- 嵌套对象解构:
对象包含对象的时候,可以通过属性名:{}获取对应的属性值。
let person = { uname: 'zs', age: 34, dog: { name: '汪仔', age: 3 }, cat: { name: '小花', age: 2 } };
let { uname, cat: { name } } = person;
console.log(uname, name); // 输出 zs, 小花
- 使用表达式:
解构赋值中,如果默认值是表达式,表达式惰性求值,只有在用到的时候才会去执行。默认值也可以引用解构赋值的其他变量,但该变量必须已声明。
三、解构赋值的应用场景
- 函数参数:
解构赋值可以用于函数参数,使函数更加简洁和易于理解。
function fn({ name, age }) {
console.log(name, age);
}
fn({ name: 'Alice', age: 25 }); // 输出 Alice, 25
- 遍历数据结构:
解构赋值可以用于遍历数组、对象、Map等数据结构。
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// 输出 first is hello, second is world
- 提取JSON数据:
在Ajax请求返回数据处理中,可以使用解构赋值提取JSON数据。
const data = { needServicePwd: true, needImgCode: false, needSmsCode: true };
({ needServicePwd: this.needServicePwd, needImgCode: this.needImgCode, needSmsCode: this.needSmsCode } = data);
3.模板字符串
一、定义与语法
ES6模板字符串:
使用反引号(`)包裹,而不是传统的单引号(')或双引号(")。
支持在字符串中嵌入表达式,通过${expression}的占位符语法实现。
ES5及之前字符串:
只能使用单引号或双引号包裹。
不支持在字符串中直接嵌入表达式,通常需要通过字符串拼接(使用+操作符)来实现。
二、功能特性
字符串插值:
ES6:支持字符串插值,允许在字符串中嵌入变量或表达式的结果。
let myname= 'John';
let greeting = `Hello ${myname}, how are you?`;
console.log(greeting);
ES5及之前:不支持字符串插值,需要通过字符串拼接来实现。
let name = 'John'; let greeting = 'Hello, ' + name + '!';
多行字符串:
ES6:模板字符串默认支持多行,无需使用特殊的换行符或字符串连接符。
const name = "Alice";
const age = 30;
const personalInfo = `姓名: ${name}
年龄: ${age}
职业: 开发者`;
console.log(personalInfo);//输出:姓名: Alice 年龄: 30 职业: 开发者
ES5及之前:不支持多行字符串,需要使用字符串连接符(+)或数组(通过join方法)来创建多行字符串。
嵌套表达式:
ES6:允许在模板字符串的占位符中嵌套更复杂的表达式,包括函数调用、算术运算等。
let a1 = 5; let b1 = 10;
let sum =`The sum of ${a1} and ${b1} is ${a1 + b1}`;
ES5及之前:不支持在字符串中直接嵌套表达式,需要通过字符串拼接和额外的计算来实现。
标签模板:
ES6:支持标签模板(tagged templates),允许在模板字符串前面加上一个标签函数来自定义字符串的处理方式
function greet(name) {
return `你好, ${name}!`;
}
const user = "Bob";
const message = `欢迎信息: ${greet(user)}
今天是个好日子。`;
console.log(message);
ES5及之前:不支持标签模板,无法实现对字符串的自定义处理。
原始字符串:
ES6:通过String.raw方法可以创建原始字符串,即不进行特殊字符的转义处理。这对于处理包含转义字符的字符串特别有用。
let name = 'Alice';
console.log(String.raw`Hello, ${name}!`);
ES5及之前:无法直接创建原始字符串,需要手动处理转义字符。
4.ES6箭头函数
基本语法
箭头函数使用 => 符号来定义函数。以下是几种常见的用法:
没有参数或只有一个参数:
const sayHello = () => {
console.log("Hello!");
};
//1)可以省略小括号,当形参只有一个的时候
const square = x => x * x;
多个参数:
const add = (a, b) => a + b;
带有函数体的箭头函数:
如果箭头函数需要包含多条语句,则必须使用花括号 {} 将它们包围起来,并且需要显式地返回结果(使用 return 关键字):
const multiplyAndAdd = (a, b, c) => {
const result = a * b;
return result + c;
};
特性
1.没有自己的 this:
箭头函数不会创建自己的 this 上下文,它会捕获其所在上下文的 this 值。这意味着在箭头函数内部使用 this,其值来自于箭头函数定义时的上下文,而不是调用时的上下文。
function Person() {
this.age = 0;
setInterval(() => {
this.age++; // `this` 指向 Person 实例
console.log(this.age);
}, 1000);
}
const p = new Person();
2.没有 arguments 对象:
箭头函数不提供 arguments 对象。如果需要访问函数的参数列表,可以使用剩余参数(...args)来替代:
const showArguments = (...args) => {
console.log(args);
};
showArguments(1, 2, 3); // 输出: [1, 2, 3]
3.不能用作构造函数:
箭头函数不能使用 new 关键字来调用,因为它们没有 [[Construct]] 方法,不能被用作构造函数。
const Foo = () => {};
// 会抛出错误:TypeError: Foo is not a constructor
const bar = new Foo();
4.没有 prototype 属性:
由于箭头函数不能用作构造函数,因此它们也没有 prototype 属性。
const Foo = () => {};
console.log(Foo.prototype); // 输出: undefined
5.不支持 yield:
箭头函数不能用作生成器函数(即不能使用 yield 关键字)。
const gen = () => {
yield 1; // 会抛出错误:SyntaxError: Unexpected strict mode reserved word
};
应用场景
以下是一个更复杂的示例,展示了箭头函数在数组操作中的应用:
const numbers = [1, 2, 3, 4, 5];
// 使用箭头函数计算数组元素的平方并返回一个新数组
const squares = numbers.map(x => x * x);
console.log(squares); // 输出: [1, 4, 9, 16, 25]
//找出大于2的数组
const newArr2 = arr.filter(num => num >2);
console.log(newArr2);
点击div改变颜色结合定时器(this指向外围作用域的this)
const box = document.getElementById('box');
box.addEventListener('click', function(){
setTimeout(() => {
this.style.backgroundColor = 'blue';
}, 2000);
});
注意
- 箭头函数适合与this无关的问题的回调,定时器,数组的方法的回调
- 箭头函数不适合与this有关的回调,事件回调,对象的方法
5. ES6允许给函数的参数赋初始值
- 在 ES6(ECMAScript 2015)中,你可以在函数定义时为参数设置默认值。这使得函数调用时如果未提供某些参数,则会使用默认值。
- 带默认值的参数必须位于没有默认值的参数之后。如果违反这一规则,会导致语法错误。
//ES6允许给函数function的参数设置默认值,这样可以简化调用函数的过程
const add=(a,b,c=10)=>{
return a + b + c;
}
console.log(add(1,2));
console.log(add(1,2,3));
输出
函数赋值与解构赋值相结合
connect({
name: 'Jack',
age: 25,
address: 'New York'
});
function connect({name, age, address}){
console.log(`My name is ${name}, I am ${age} years old, and I live in ${address}.`);
}
6. ES6扩展运算符(Spread Operator)和剩余参数(Rest Parameters)
ES6中的Rest参数(Rest parameters)是一种语法结构,它允许我们将一个不定数量的参数表示为一个数组
一、语法
Rest参数以三个点(...)开头,后跟一个参数名。这个参数名实际上是一个数组,用于收集函数调用时传入的所有剩余参数。
function myFunction(a, b, ...rest) {
// rest是一个数组,包含所有剩余的参数
console.log(rest);
}
二、使用场景
处理可变数量的参数:
当函数需要接收任意数量的参数时,可以使用Rest参数来收集所有剩余的参数。
function sum(a, b, ...rest) {
let total = a + b;
for (let i = 0; i < rest.length; i++) {
total += rest[i];
}
return total;
}
console.log(sum(1, 2, 3, 4, 5)); // 输出: 15
从数组中提取数据:
可以使用Rest参数将数组中的元素作为参数传递给函数。
const arr = [1, 2, 3, 4];
function printNumbers(...numbers) {
numbers.forEach(num => console.log(num));
}
printNumbers(...arr); // 输出: 1 2 3 4
结合其他参数使用:
Rest参数可以与其他参数一起使用,但必须放在参数列表的最后。
function processValues(operation, ...values) {
if (operation === 'sum') {
return values.reduce((acc, val) => acc + val, 0);
} else if (operation === 'average') {
const sum = values.reduce((acc, val) => acc + val, 0);
return sum / values.length;
}
return null;
}
console.log(processValues('sum', 1, 2, 3, 4)); // 输出: 10
console.log(processValues('average', 1, 2, 3, 4, 5)); // 输出: 3
三、注意事项
位置要求:
Rest参数必须放在参数列表的最后,且一个函数中只能有一个Rest参数。
参数解构:
Rest参数可以被解构,但需要注意解构后的变量名与数组元素的对应关系。
function f(...[a, b, c]) {
return a + b + c;
}
console.log(f(1, 2, 3)); // 输出: 6
console.log(f(1, 2, 3, 4)); // 输出: 6(第四值没有与之对应的变量名)
函数length属性:
函数的length属性返回的是没有Rest参数时的参数个数。
function example(a, b, ...c) {}
console.log(example.length); // 输出: 2
四、与扩展运算符的区别
虽然Rest参数和扩展运算符(Spread operator)都用到了三个点(...),但它们的作用和用途是不同的。Rest参数用于函数定义中,用于收集剩余的参数;而扩展运算符用于数组、对象等可迭代对象的展开。
// 扩展运算符示例
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // 将arr1的元素展开到arr2中
console.log(arr2); // 输出: [1, 2, 3, 4, 5]
数组中的扩展运算符
扩展运算符用三个点号(...
)表示,用于将数组元素展开到不同的地方。
示例1:合并数组
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const mergedArray = [...arr1, ...arr2];
console.log(mergedArray); // 输出: [1, 2, 3, 4, 5, 6]
示例2:在数组字面量中使用
const elements = ['fire', 'air'];
const nature = ['earth', ...elements, 'water'];
console.log(nature); // 输出: ['earth', 'fire', 'air', 'water']
示例3:将类数组对象转换为数组
const arrayLike = {0: 'a', 1: 'b', length: 2};
const arr = [...arrayLike];
console.log(arr); // 输出: ['a', 'b']
示例4:复制数组
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
console.log(copiedArray); // 输出: [1, 2, 3]
函数中的剩余参数
剩余参数用三个点号(...
)表示,用于将函数接收到的所有剩余参数收集到一个数组中。
示例1:基本用法
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 输出: 10
示例2:结合普通参数使用
function multiply(factor, ...numbers) {
return numbers.map(num => num * factor);
}
console.log(multiply(2, 1, 2, 3, 4)); // 输出: [2, 4, 6, 8]
对象中的扩展运算符
在 ES2018 中,扩展运算符也被引入到了对象中,用于合并和克隆对象。
示例1:合并对象
const obj1 = {a: 1, b: 2};
const obj2 = {b: 3, c: 4};
const mergedObj = {...obj1, ...obj2};
console.log(mergedObj); // 输出: {a: 1, b: 3, c: 4}
示例2:克隆对象
const originalObj = {a: 1, b: 2};
const clonedObj = {...originalObj};
console.log(clonedObj); // 输出: {a: 1, b: 2}
示例3:结合数组和对象使用
const people = [
{name: 'Alice', age: 25},
{name: 'Bob', age: 30}
];
const peopleWithCities = people.map(person => ({...person, city: 'New York'}));
console.log(peopleWithCities);
// 输出: [{name: 'Alice', age: 25, city: 'New York'}, {name: 'Bob', age: 30, city: 'New York'}]
注意事项
- 数组和对象的浅拷贝:扩展运算符执行的是浅拷贝,即只复制了对象的第一层属性。对于嵌套的对象或数组,深层次的引用仍会保留。
- 函数参数中的默认值:剩余参数不能用于设置默认参数值。
7.Symbol()类型运用
Symbol 是 ES6(ECMAScript 2015)中引入的一种新的原始数据类型,表示独一无二的值。与字符串和数字不同,每次创建一个新的 Symbol 时,即使它的描述相同,它们也是不同的值。这使得 Symbol 类型非常适合用作对象的唯一属性键,以避免属性名冲突。
创建 Symbol
要创建一个新的 Symbol,你可以使用 Symbol() 函数,并传递一个可选的描述字符串(该描述仅用于调试目的,不会影响 Symbol 的唯一性):
const sym1 = Symbol('description');
const sym2 = Symbol('description');
console.log(sym1 === sym2); // false
console.log(sym1.toString()); // "Symbol(description)"
console.log(sym2.toString()); // "Symbol(description)"
使用 Symbol 作为对象属性键
Symbol 可以用作对象的属性键,这样可以确保属性键的唯一性:
const sym = Symbol('uniqueKey');
const obj = {
[sym]: 'This is a unique property'
};
console.log(obj[sym]); // "This is a unique property"
// 使用 for...in 循环无法遍历 Symbol 类型的属性
for (let key in obj) {
console.log(key); // 不会输出任何内容
}
// 使用 Object.keys() 也不会列出 Symbol 类型的属性
console.log(Object.keys(obj)); // []
// 使用 Object.getOwnPropertySymbols() 可以获取 Symbol 类型的属性
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(uniqueKey)]
// 使用 Object.getOwnPropertyNames() 也不会列出 Symbol 类型的属性
console.log(Object.getOwnPropertyNames(obj)); // []
全局 Symbol 注册表
Symbol 还提供了一个全局注册表,使用 Symbol.for() 方法。此方法会检查传入的字符串是否已经存在于全局 Symbol 注册表中,如果存在则返回该 Symbol,否则创建一个新的 Symbol 并注册到表中:
const symGlobal1 = Symbol.for('globalKey');
const symGlobal2 = Symbol.for('globalKey');
console.log(symGlobal1 === symGlobal2); // true
与直接调用 Symbol() 创建的 Symbol 不同,通过 Symbol.for() 创建的 Symbol 是全局唯一的,即使它们在不同的代码块或文件中创建。
内置 Symbol 属性
JavaScript 还定义了一些内置的 Symbol 属性,这些属性通常用于对象方法的钩子(traps),如:
- Symbol.iterator:定义对象的默认迭代行为。
- Symbol.toPrimitive:定义对象在转换为原始值时的行为。
- Symbol.toStringTag:定义对象在 Object.prototype.toString.call() 时的返回值。
例如,定义一个可迭代对象:
const iterable = {
[Symbol.iterator]() {
let i = 0;
const data = [1, 2, 3];
return {
next() {
if (i < data.length) {
return { value: data[i++], done: false };
} else {
return { done: true };
}
}
};
}
};
for (let value of iterable) {
console.log(value); // 1, 2, 3
}
8.ES6-迭代器
ES6 引入了迭代器(Iterator)的概念,它是一种统一遍历不同数据结构(如数组、对象、Map、Set 等)的方式。迭代器对象实现了迭代协议,该协议规定了 next() 方法,该方法会返回迭代结果的对象,该对象包含两个属性:value 和 done。value 表示当前遍历到的值,done 是一个布尔值,表示遍历是否结束。
以下是关于 ES6 迭代器的一些关键点和用法示例:
可迭代对象(Iterable)
首先,要明白什么是可迭代对象。一个对象如果实现了 @@iterator 方法(在对象上或通过其原型链),那么它就是可迭代的。@@iterator 方法应该返回一个迭代器对象。
默认迭代器
对于内置的可迭代对象(如数组、字符串、Map 和 Set),JavaScript 提供了默认的迭代器。
const arr = [1, 2, 3];
const iter = arr[Symbol.iterator]();
console.log(iter.next()); // { value: 1, done: false }
console.log(iter.next()); // { value: 2, done: false }
console.log(iter.next()); // { value: 3, done: false }
console.log(iter.next()); // { value: undefined, done: true }
自定义迭代器
你也可以为自定义对象实现迭代器。为此,你需要在对象上定义 @@iterator 方法,或者在其原型链上定义。
const myIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return { value: data[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};
for (const value of myIterable) {
console.log(value); // 1, 2, 3
}
使用 for...of 循环
for...of 循环是遍历可迭代对象的一种简洁方式。
const str = 'hello';
for (const char of str) {
console.log(char); // h, e, l, l, o
}
迭代器的高阶应用
迭代器可以用于创建更高级的数据处理功能,如生成器(Generator)、解构赋值(destructuring assignment with rest)、扩展运算符(spread operator)等。
生成器函数(Generator Function)
生成器函数是 JavaScript ES6 引入的一种特殊类型的函数,它允许你暂停和恢复函数的执行。生成器函数使用 function* 语法来定义,并且可以在函数体内使用 yield 关键字来暂停函数的执行并返回一个值。每次调用生成器函数的 .next() 方法时,函数会从上次暂停的地方继续执行,直到遇到下一个 yield 或函数结束。
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
生成器函数传参情况
//生成器函数
function* myGenerator(a,b,c) {
yield a;
yield b;
yield c;
yield a+b+c;
}
const gen=myGenerator(4,5,6);
console.log(gen.next().value); // 4
console.log(gen.next().value); // 5
console.log(gen.next().value); // 6
console.log(gen.next().value); // 15
console.log(gen.next().done); // true
console.log(gen.next().value); // undefined
for (const value of myGenerator(1,2,3)) {
console.log(value);
}
解构赋值与扩展运算符
解构赋值和扩展运算符都可以与迭代器一起使用,以简洁的方式处理可迭代对象。
const [first, ...rest] = [1, 2, 3, 4];
console.log(first); // 1
console.log(rest); // [2, 3, 4]
const arrCopy = [...arr]; // 使用扩展运算符复制数组
9.ES6-class关键字
ES6引入了类(class)的概念,使面向对象编程在JavaScript中变得更加直观和易于管理。以下是关于ES6类属性以及继承的一些基本介绍和示例。
类属性
在ES6中,你可以在类中定义属性(包括静态属性和实例属性)。虽然ES6本身并没有直接提供类的实例属性的简洁语法,但可以通过在构造函数中定义或者在类字段语法(从ES2022/ES13开始引入)中定义属性。
在构造函数中定义属性
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const person = new Person('Alice', 30);
person.greet(); // Hello, my name is Alice and I am 30 years old.
使用类字段语法定义属性(ES2022/ES13+)
class Person {
name;
age;
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const person = new Person('Alice', 30);
person.greet(); // Hello, my name is Alice and I am 30 years old.
类字段语法还支持在声明时直接初始化属性:
class Person {
name = 'Unknown';
age = 0;
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const person = new Person();
person.greet(); // Hello, my name is Unknown and I am 0 years old.
静态属性(Static Properties)
静态属性属于类本身,而不是类的实例。它们使用 static
关键字定义。
class MathUtils {
static PI = 3.14159;
static circleArea(radius) {
return MathUtils.PI * radius * radius;
}
}
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.circleArea(5)); // 78.53975
继承
在ES6中,你可以使用 extends
关键字实现类的继承。子类可以使用 super
关键字调用父类的构造函数和方法。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类的构造函数
this.breed = breed;
}
speak() {
super.speak(); // 调用父类的方法
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak();
// Buddy makes a sound.
// Buddy barks.
静态方法的继承
静态方法不能被实例调用,也不能被子类的实例重写(尽管它们可以在子类中重新定义)。
class Parent {
static greet() {
console.log('Hello from Parent');
}
}
class Child extends Parent {
static greet() {
console.log('Hello from Child');
}
}
Parent.greet(); // Hello from Parent
Child.greet(); // Hello from Child
在这个例子中,Child
类有自己的 greet
静态方法,调用 Child.greet()
会输出 "Hello from Child",而不是从 Parent
类继承的方法。
总结
- 类属性:可以在构造函数中定义,或者在类字段语法中直接声明和初始化。
- 静态属性:使用
static
关键字定义,属于类本身而不是实例。 - 继承:使用
extends
关键字实现,super
关键字用于调用父类的构造函数和方法。