Javascript 编程基础(5)面向对象 | 5.1、构造函数实例化对象

文章目录

前言:

在 JavaScript 里,构造函数是创建对象实例的一种方式。构造函数本质上是普通的函数,不过有其特定的使用模式:要用 new 关键字来调用,这样才能创建对象实例。下面为详细介绍构造函数实例化对象的相关内容。

一、构造函数实例化对象

1、基本语法

使用构造函数创建对象实例,需要遵循以下步骤:

  • 定义一个构造函数,函数名一般首字母大写(这是约定俗成的写法,并非强制要求)。
  • 在构造函数内部,通过 this 关键字来设置对象的属性和方法。
  • 使用 new 关键字调用构造函数,从而创建对象实例。

下面是一个简单的例子:

javascript 复制代码
// 定义一个构造函数
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、完整的原型链

一个典型的原型链如下所示:

cpp 复制代码
实例对象 -> 构造函数.prototype -> Object.prototype -> null

验证方法:

javascript 复制代码
persona1.__proto__ === Person.prototype; // true
Person.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true

4、构造函数的特点

  • 属性和方法的复制 :每次通过构造函数创建对象实例时,都会为每个实例复制一份属性和方法。就像上面例子中的 sayHello 方法,每个实例都有自己独立的副本。
  • 原型链继承 :所有通过同一个构造函数创建的对象实例,都会继承构造函数 prototype 属性上的方法和属性。

下面通过代码说明原型链继承:

javascript 复制代码
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](标准):内部属性,实际决定原型链。
javascript 复制代码
const obj = {};
console.log(obj.prototype); // undefined(实例没有prototype属性)
console.log(obj.__proto__ === Object.prototype); // true

5.2、prototype属性仅存在于函数对象

每个函数 默认有一个prototype属性,指向其原型对象:

javascript 复制代码
function Person() {}
console.log(Person.prototype); // { constructor: ƒ Person() }

// 验证函数也是对象,其原型是Function.prototype
console.log(Person.__proto__ === Function.prototype); // true

5.3、实例与原型的关系

当使用new创建对象时,实例的__proto__指向构造函数的prototype

javascript 复制代码
function Person() {}
const alice = new Person();

console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true

5.4、获取对象原型

推荐使用标准方法Object.getPrototypeOf()获取对象原型:

javascript 复制代码
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true

6、注意事项

  • 忘记使用 new 关键字的问题 :如果在调用构造函数时忘记使用 new 关键字,this 会指向全局对象(在浏览器环境中是 window 对象),这可能会导致意外的结果。为了避免这种情况,可以使用箭头函数或者在构造函数内部检查 this 是否是当前构造函数的实例。
  • 性能方面的考虑 :如果构造函数内部定义了大量方法,每个对象实例都会拥有这些方法的独立副本,这会造成内存的浪费。通常的做法是将共享的方法定义在构造函数的 prototype 上。
相关推荐
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
伞伞悦读2 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
C语言小火车2 天前
C/C++ 为什么需要编译器?
开发语言·c++
李少兄2 天前
JavaScript 隐式全局变量解析
javascript
霍霍的袁2 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
孙启超2 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int2 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++
沙蒿同学2 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端