JavaScript 是一种基于原型的语言,这意味着它没有传统的类继承结构,而是通过对象与原型链来实现继承和代码复用。随着 ES6 的到来,JavaScript 引入了 class
语法糖,让代码更接近面向对象的风格。
1. 构造函数
1.1 基本构造函数
构造函数是一种用于创建特定类型对象的函数。常见的命名约定是首字母大写:
1 2 3 4 5 6 7
| function Person(name, age) { this.name = name; this.age = age; }
let alice = new Person("Alice", 25); console.log(alice);
|
1.2 构造函数的属性和方法
可以在构造函数中添加方法,但这样做会为每个实例单独创建方法。更好的方法是使用 原型,这样所有实例可以共享方法。
1 2 3 4 5 6 7 8 9 10 11 12
| function Person(name, age) { this.name = name; this.age = age; }
Person.prototype.greet = function() { console.log(`Hello, my name is ${this.name}`); };
let bob = new Person("Bob", 30); bob.greet();
|
2. 原型与原型链
2.1 什么是原型
每个 JavaScript 对象(除了 null
)都与另一个对象关联,这个对象就是 原型。通过原型对象,我们可以实现属性和方法的继承。
1
| console.log(bob.__proto__ === Person.prototype);
|
2.2 原型链
当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 会沿着原型链向上查找,直到找到属性或达到原型链的顶端(null
)。
1
| console.log(bob.toString());
|
在上面的例子中,bob
没有定义 toString
方法,JavaScript 会在其原型链上找到 Object.prototype
并调用它的 toString
方法。
2.3 hasOwnProperty()
方法
用于检查对象本身是否拥有某个属性,而不是从原型链中继承的:
1 2
| console.log(bob.hasOwnProperty("name")); console.log(bob.hasOwnProperty("toString"));
|
3. ES6 类
3.1 基本类的创建
ES6 引入了 class
关键字,它是构造函数的语法糖,使代码更具结构化和可读性:
1 2 3 4 5 6 7 8 9 10 11 12
| class Animal { constructor(name) { this.name = name; }
speak() { console.log(`${this.name} makes a sound`); } }
let dog = new Animal("Dog"); dog.speak();
|
3.2 类的继承
使用 extends
可以创建子类,子类会继承父类的所有属性和方法。子类中的构造函数中需使用 super
调用父类的构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Dog extends Animal { constructor(name, breed) { super(name); this.breed = breed; }
bark() { console.log(`${this.name} barks`); } }
let labrador = new Dog("Buddy", "Labrador"); labrador.speak(); labrador.bark();
|
3.3 静态方法
静态方法是直接定义在类上的方法,而不是在实例上。使用 static
关键字定义静态方法,可以直接通过类来调用。
1 2 3 4 5 6 7
| class MathUtility { static square(x) { return x * x; } }
console.log(MathUtility.square(5));
|
4. this
关键字的作用
在 JavaScript 中,this
的值取决于 它被调用的方式。在面向对象编程中,this
通常指向当前对象的实例。
4.1 箭头函数与 this
箭头函数不绑定 this
,它会捕获所在作用域的 this
值。在对象方法中,如果用箭头函数定义方法,this
会指向父作用域,而不是对象实例。
1 2 3 4 5 6 7 8 9 10
| class Counter { count = 0;
increment = () => { console.log(this.count++); } }
let counter = new Counter(); counter.increment();
|
5. 私有属性与方法
在 JavaScript 中,私有属性并不是天然支持的。不过可以通过以下几种方法实现:
5.1 使用闭包
可以在构造函数中使用局部变量模拟私有属性:
1 2 3 4 5 6 7 8 9 10
| function SecretAgent(name) { let codeName = "Secret";
this.getName = function() { return `${name} is known as ${codeName}`; }; }
let agent = new SecretAgent("James Bond"); console.log(agent.getName());
|
5.2 ES2021 中的 #
符号
使用 #
定义私有属性,无法通过对象实例访问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class User { #password;
constructor(name, password) { this.name = name; this.#password = password; }
checkPassword(password) { return this.#password === password; } }
let user = new User("Alice", "secret123"); console.log(user.checkPassword("secret123"));
|