Javascript 编程基础(5)面向对象 | 5.1、构造函数实例化对象
文章目录
- 一、构造函数实例化对象
- 1、基本语法
- 2、构造函数与原型的关系
- 3、完整的原型链
- 4、构造函数的特点
- 5、`prototype`与`__proto__`属性
- 5.1、对象实例的`__proto__`属性
- 5.2、`prototype`属性仅存在于函数对象
- 5.3、实例与原型的关系
- 5.4、获取对象原型
- 6、注意事项
前言:
在 JavaScript 里,构造函数是创建对象实例的一种方式。构造函数本质上是普通的函数,不过有其特定的使用模式:要用
new
关键字来调用,这样才能创建对象实例。下面为详细介绍构造函数实例化对象的相关内容。
一、构造函数实例化对象
1、基本语法
使用构造函数创建对象实例,需要遵循以下步骤:
- 定义一个构造函数,函数名一般首字母大写(这是约定俗成的写法,并非强制要求)。
- 在构造函数内部,通过
this
关键字来设置对象的属性和方法。 - 使用
new
关键字调用构造函数,从而创建对象实例。
下面是一个简单的例子:
// 定义一个构造函数
function Person(name, age) {this.name = name;this.age = age;this.sayHello = function() {console.log(`你好,我是${this.name},今年${this.age}岁了。`);};
}// 使用new关键字创建对象实例
const person1 = new Person('张三', 25);
const person2 = new Person('李四', 30);// 调用对象的属性和方法
console.log(person1.name); // 输出: 张三
person2.sayHello(); // 输出: 你好,我是李四,今年30岁了。
2、构造函数与原型的关系
当使用
new
关键字调用构造函数时,会按照以下步骤执行:
- 首先创建一个新对象。
- 让这个新对象的
[[Prototype]]
(即原型)指向构造函数的prototype
属性。 - 将构造函数的
this
绑定到新创建的对象上。 - 执行构造函数内部的代码,这样就可以为新对象设置属性和方法。
- 如果构造函数返回了一个对象,那么就返回该对象;否则,返回新创建的对象。
3、完整的原型链
一个典型的原型链如下所示:
实例对象 -> 构造函数.prototype -> Object.prototype -> null
验证方法:
persona1.__proto__ === Person.prototype; // true
Person.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
4、构造函数的特点
- 属性和方法的复制:每次通过构造函数创建对象实例时,都会为每个实例复制一份属性和方法。就像上面例子中的
sayHello
方法,每个实例都有自己独立的副本。 - 原型链继承:所有通过同一个构造函数创建的对象实例,都会继承构造函数
prototype
属性上的方法和属性。
下面通过代码说明原型链继承:
function Car(make, model) {this.make = make;this.model = model;
}// 给构造函数的prototype添加方法
Car.prototype.getInfo = function() {return `这是一辆${this.make} ${this.model}。`;
};// 创建对象实例
const car1 = new Car('丰田', '卡罗拉');
const car2 = new Car('本田', '思域');// 调用原型上的方法
console.log(car1.getInfo()); // 输出: 这是一辆丰田 卡罗拉。
console.log(car2.getInfo()); // 输出: 这是一辆本田 思域。
5、prototype
与__proto__
属性
5.1、对象实例的__proto__
属性
在 JavaScript 中,对象实例本身没有
prototype
属性,但有__proto__
属性(非标准,对应内部的[[Prototype]]
)。以下是详细说明:
- __proto__(非标准):指向该对象的原型对象。
- [[Prototype]](标准):内部属性,实际决定原型链。
const obj = {};
console.log(obj.prototype); // undefined(实例没有prototype属性)
console.log(obj.__proto__ === Object.prototype); // true
5.2、prototype
属性仅存在于函数对象
每个函数默认有一个
prototype
属性,指向其原型对象:
function Person() {}
console.log(Person.prototype); // { constructor: ƒ Person() }// 验证函数也是对象,其原型是Function.prototype
console.log(Person.__proto__ === Function.prototype); // true
5.3、实例与原型的关系
当使用
new
创建对象时,实例的__proto__
指向构造函数的prototype
:
function Person() {}
const alice = new Person();console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
5.4、获取对象原型
推荐使用标准方法
Object.getPrototypeOf()
获取对象原型:
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
6、注意事项
- 忘记使用
new
关键字的问题:如果在调用构造函数时忘记使用new
关键字,this
会指向全局对象(在浏览器环境中是window
对象),这可能会导致意外的结果。为了避免这种情况,可以使用箭头函数或者在构造函数内部检查this
是否是当前构造函数的实例。 - 性能方面的考虑:如果构造函数内部定义了大量方法,每个对象实例都会拥有这些方法的独立副本,这会造成内存的浪费。通常的做法是将共享的方法定义在构造函数的
prototype
上。