✊不积跬步,无以至千里;不积小流,无以成江海。
自制一个构造函数
当想要创建一个自定义的构造函数时,可以按照以下步骤进行:
- 使用
function
关键字定义构造函数,并为构造函数选择一个合适的名称。构造函数名称通常以大写字母开头,以与普通函数区分开来。 - 在构造函数内部,可以定义属性和方法,这些属性和方法将成为构造函数创建的对象的特征和行为。
- 使用
this
关键字来引用当前正在创建的对象,以便设置对象的属性。 - 可以在构造函数的原型上定义共享的方法,这样创建的每个对象都可以访问这些方法,从而实现方法的复用。
下面是一个示例,演示如何创建一个名为Person
的构造函数,用于创建具有姓名和年龄属性的人对象:
javascript
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name + " and I am " + this.age + " years old.");
};
// 创建 Person 对象的实例
var person1 = new Person("Alice", 25);
var person2 = new Person("Bob", 30);
// 调用实例的方法
person1.sayHello(); // 输出: Hello, my name is Alice and I am 25 years old.
person2.sayHello(); // 输出: Hello, my name is Bob and I am 30 years old.
在上面的示例中,Person
构造函数接受两个参数 name
和 age
,并使用this
关键字将它们赋值给正在创建的对象的属性。然后,我们在构造函数的原型上定义了一个名为sayHello
的方法,它可以在每个Person
对象上被调用。通过new
关键字,我们可以创建Person
构造函数的实例,然后调用实例的方法。
在构造函数内部定义多个属性和方法
构造函数作为一个特殊的函数,用于创建对象,并可以在其中定义对象的初始属性和方法。
下面是一个示例,展示了构造函数内部定义多个属性和方法的方式:
javascript
function Person(name, age) {
this.name = name;
this.age = age;
// 定义构造函数内部的方法
this.sayHello = function() {
console.log("Hello, my name is " + this.name + " and I am " + this.age + " years old.");
};
// 定义构造函数内部的属性
var country = "USA";
this.getCountry = function() {
return country;
};
}
// 创建 Person 对象的实例
var person = new Person("Alice", 25);
// 调用实例的方法
person.sayHello(); // 输出: Hello, my name is Alice and I am 25 years old.
// 获取实例的属性
console.log(person.getCountry()); // 输出: USA
在上面的示例中,构造函数Person
内部定义了两个属性:name
和age
,以及两个方法:sayHello
和getCountry
。sayHello
方法用于在控制台打印问候语,getCountry
方法用于返回内部变量country
的值。
在构造函数内部 定义的属性和方法将成为每个通过构造函数创建的对象的实例属性和方法。每个对象都将有自己的属性副本 ,但是方法将是共享的,因为它们都定义在构造函数的原型上。
由于属性和方法是在构造函数内部定义的,每次创建对象时都会重新定义它们。这可能会占用更多的内存,尤其是当创建大量对象时。如果这些属性和方法对每个对象都是相同的 ,更好的做法是将它们定义在构造函数的原型上,以实现方法的共享和节省内存。
隐藏属性和共有属性
隐藏属性是在构造函数内部定义的变量,无法直接通过对象实例访问。它们被称为隐藏属性,因为它们只在构造函数的作用域内可见。通常使用闭包的方式来创建隐藏属性,以提供对象的私有性。
共有属性是通过构造函数内部使用this
关键字定义的属性,可以通过对象实例访问和修改。它们被称为共有属性,因为它们对于每个通过构造函数创建的对象都是可见和共享的。
下面是一个示例,展示了构造函数的隐藏属性和共有属性的不同:
javascript
function Person(name, age) {
// 隐藏属性
var country = "USA";
// 共有属性
this.name = name;
this.age = age;
// 共有方法
this.sayHello = function() {
console.log("Hello, my name is " + this.name + " and I am " + this.age + " years old.");
};
// 隐藏方法
function getCountry() {
return country;
}
// 公共接口暴露隐藏方法
this.getCountry = function() {
return getCountry();
};
}
// 创建 Person 对象的实例
var person = new Person("Alice", 25);
// 访问共有属性
console.log(person.name); // 输出: Alice
console.log(person.age); // 输出: 25
// 调用共有方法
person.sayHello(); // 输出: Hello, my name is Alice and I am 25 years old.
// 访问隐藏属性(无法直接访问)
console.log(person.country); // 输出: undefined
// 调用通过公共接口暴露的隐藏方法
console.log(person.getCountry()); // 输出: USA
在上面的示例中,构造函数Person
内部定义了一个隐藏属性country
,它无法直接通过对象实例访问。同时,构造函数通过this
关键字定义了共有属性name
和age
,以及共有方法sayHello
。隐藏方法getCountry
被定义在构造函数内部,通过公共接口getCountry
暴露给外部访问。
通过这种方式,隐藏属性和方法只能在构造函数的作用域 内使用,而共有属性和方法可以通过对象实例访问。这样可以实现数据的封装和隐藏,将对象的内部状态保护起来,并提供公共接口来访问和操作对象的属性和方法。
构造函数标准写法箭头函数不能当构造函数
箭头函数不能用作构造函数。箭头函数具有词法作用域绑定 ,不会创建自己的this
值,而是继承外部作用域的this
值。这导致箭头函数无法正确地使用new
关键字创建对象。
构造函数需要使用this
关键字来引用正在创建的对象,并在对象上设置属性和方法。由于箭头函数没有自己的this
值,它无法正确地执行这些操作。
以下是一个示例,展示了箭头函数不能用作构造函数的情况:
ini
// 错误的示例,箭头函数作为构造函数使用
const Person = (name, age) => {
this.name = name; // 错误:箭头函数没有自己的this值
this.age = age;
};
// 使用箭头函数作为构造函数创建对象
const person = new Person("Alice", 25); // 错误:TypeError: Person is not a constructor
在上面的示例中,尝试使用箭头函数Person
作为构造函数来创建对象。但是,由于箭头函数没有自己的this
值,this.name
和this.age
都无法正确地引用正在创建的对象。因此,在使用new
关键字创建对象时,会抛出TypeError: Person is not a constructor
错误。
如果您需要创建一个构造函数,应该使用普通的函数声明或函数表达式,而不是箭头函数。这样可以确保构造函数正确地创建对象并设置属性和方法。
class语法
使用 class
语法可以更方便地定义构造函数和原型方法,它提供了一种更简洁、易读的方式来创建对象和定义类的行为。
下面是使用 class
语法定义构造函数和原型方法的示例:
javascript
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// 创建 Person 类的实例
const person = new Person("Alice", 25);
// 调用实例的方法
person.sayHello(); // 输出: Hello, my name is Alice and I am 25 years old.
在上面的示例中,我们使用 class
关键字定义了一个名为 Person
的类。constructor
方法是一个特殊的方法,用于在创建对象时初始化对象的属性。在 constructor
方法内部,我们使用 this
关键字来引用正在创建的对象,并设置 name
和 age
属性。
类中的其他方法(如 sayHello
)将被添加到类的原型上,因此所有实例都可以通过原型链继承和共享这些方法。
使用 class
语法还可以方便地定义静态方法和使用继承创建子类。以下是一个示例:
scala
class Animal {
constructor(name) {
this.name = name;
}
static info() {
console.log("This is an animal.");
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
const dog = new Dog("Fido");
dog.bark(); // 输出: Woof!
Dog.info(); // 输出: This is an animal.
在上面的示例中,我们定义了一个 Animal
类和一个 Dog
类作为 Animal
的子类。Animal
类的 constructor
方法设置了 name
属性,而 Dog
类添加了一个 bark
方法。
我们还在 Animal
类上定义了一个静态方法 info
,可以直接通过类调用,而不需要创建实例。
静态方法
静态方法是定义在类本身上,而不是类的实例上的方法。它们在类级别上执行操作,而不依赖于特定的实例。静态方法可以通过类直接调用,而不需要创建类的实例。
以下是一个示例,展示了如何定义和使用静态方法:
javascript
class MathUtils {
static add(a, b) {
return a + b;
}
static subtract(a, b) {
return a - b;
}
}
// 调用静态方法
console.log(MathUtils.add(5, 3)); // 输出: 8
console.log(MathUtils.subtract(10, 4)); // 输出: 6
在上面的示例中,我们定义了一个 MathUtils
类,并在其中定义了两个静态方法:add
和 subtract
。这些静态方法可以直接通过类名进行调用,而不需要创建 MathUtils
类的实例。
静态方法通常用于执行与类相关的操作,例如提供实用函数、进行数据验证或执行类级别的计算 等。它们不依赖于类的实例状态或属性,因此可以在不创建实例的情况下使用。
需要注意的是,静态方法不能访问实例属性或方法,因为它们不在特定实例的上下文中执行。静态方法只能访问静态属性和其他静态方法。