原型链:揭开JavaScript背后的神秘面纱

news/2024/11/14 13:26:54/

在这里插入图片描述

文章目录

    • 1. 对象
    • 2. 原型(prototype)
    • 3. 原型链(prototype chain)
    • 4. 构造函数(constructor)
    • 5. prototype 属性
    • 6. 实例(instance)
    • 7. 原型继承(prototype inheritance)
    • 8. this 关键字
    • 9. Object.create() 方法

JavaScript 中的原型链是 [实现对象继承] 的一种机制。

1. 对象

JavaScript 中的所有值都是对象,包括基本数据类型的值。每个对象都有一个原型(prototype)。

在JavaScript中,对象是一种复合数据类型,用于存储和组织相关数据和功能。
对象可以包含属性和方法,这些属性和方法可以通过点运算符或方括号来访问。

以下是一个简单的JavaScript对象的代码示例:

// 创建一个空对象
var person = {};// 设置对象的属性
person.name = "John";
person.age = 30;
person.gender = "male";// 定义对象的方法
person.sayHello = function() {console.log("Hello, my name is " + this.name);
};// 访问对象的属性和方法
console.log(person.name);       // 输出: "John"
console.log(person.age);        // 输出: 30
console.log(person.gender);     // 输出: "male"
person.sayHello();              // 输出: "Hello, my name is John"

在上面的例子中,我们首先创建了一个空对象 person,然后通过赋值语句给这个对象添加了几个属性 nameagegender,并为对象定义了一个方法 sayHello

要访问对象的属性和方法,我们可以使用点运算符(例如 person.name)或方括号运算符(例如 person["name"])。方法 sayHello 中的 this 关键字指向当前对象,这里就是 person 对象。

除了使用字面量创建对象,还可以使用构造函数或类来创建对象。

下面是一个用构造函数创建对象的示例:

// 构造函数
function Person(name, age, gender) {this.name = name;this.age = age;this.gender = gender;this.sayHello = function() {console.log("Hello, my name is " + this.name);};
}// 创建对象实例
var person1 = new Person("John", 30, "male");
var person2 = new Person("Jane", 25, "female");// 访问对象属性和调用方法
console.log(person1.name);      // 输出: "John"
console.log(person2.age);       // 输出: 25
person1.sayHello();             // 输出: "Hello, my name is John"
person2.sayHello();             // 输出: "Hello, my name is Jane"

在上述例子中,我们通过构造函数 Person 定义了一个可以用于创建多个相似对象的蓝图。每次使用 new 关键字调用构造函数时,都会创建一个新的对象实例,并且该实例拥有构造函数中定义的属性和方法。

这只是JavaScript对象的基础概念和使用方式,你可以根据具体需求将对象扩展为更复杂和功能丰富的实体。

2. 原型(prototype)

每个对象都有一个原型,它可以是另一个对象或者 null
原型对象也可以有自己的原型,因此形成了一个原型链。

JavaScript 中的原型(prototype)是每个对象特有的属性,它允许对象继承另一个对象的属性和方法。每个对象都有一个原型,可以通过 __proto__ 属性来访问。原型对象本身也可以有自己的原型,从而形成一个原型链。

以下是关于 JavaScript 原型的详细解释和示例代码:

JavaScript 中的每个函数都有一个特殊的属性 prototype,它是一个普通的对象。当使用 new 关键字调用函数作为构造函数创建对象时,新创建的对象会自动获得该构造函数的 prototype 属性作为自己的原型,将其与构造函数建立联系。

// 构造函数
function Person(name, age) {this.name = name;this.age = age;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person1 = new Person("John", 30);
var person2 = new Person("Jane", 25);person1.sayHello();  // 输出: "Hello, my name is John"
person2.sayHello();  // 输出: "Hello, my name is Jane"

在上述例子中,我们将 sayHello 方法定义在 Person 构造函数的 prototype 属性上。这意味着该方法被所有由 Person 构造函数创建的对象共享。通过原型链的机制,对象实例 person1person2 可以访问和调用原型中定义的方法。

当我们调用 person1.sayHello() 时,JavaScript 引擎首先在 person1 对象上查找 sayHello 方法,但找不到,然后会沿着原型链向上查找,最终在 Person.prototype 上找到并执行该方法。

除了继承方法,通过原型还可以继承属性。当我们尝试访问一个对象的属性时,如果对象本身没有该属性,JavaScript 引擎也会沿着原型链向上查找,直到找到该属性或原型链结束。

console.log(person1.age);  // 输出: 30
console.log(person2.name); // 输出: "Jane"

在上述代码中,我们可以直接通过实例对象 person1person2 访问构造函数 Person 的原型中定义的属性。

需要注意的是,使用 __proto__ 属性直接访问原型是不推荐的,因为它是非标准的,不适用于所有 JavaScript 环境。应该尽量使用 Object.getPrototypeOf(obj)obj.constructor.prototype 来访问对象的原型。

通过原型链继承属性和方法可以减少内存消耗,并使对象之间共享方法,提高代码的效率和可维护性。原型链是 JavaScript 中实现继承的基础机制之一。

3. 原型链(prototype chain)

原型链是由一系列对象组成的链表结构,每个对象都有一个指向其原型的引用。当访问一个对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法,或者到达链的末尾(即原型为 null)。

JavaScript 的原型链(prototype chain)是一种对象之间通过原型继承关联起来的机制。每个对象都有一个原型,而原型本身也是一个对象,它可以拥有自己的原型,从而形成一个原型链。

当我们访问一个对象的属性或方法时,JavaScript 引擎首先在该对象本身中查找,如果找不到则会沿着原型链向上查找,直到找到对应的属性或方法,或者到达原型链的末尾。

以下是关于 JavaScript 原型链的详细解释和示例代码:

// 构造函数
function Person(name) {this.name = name;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person1 = new Person("John");person1.sayHello();  // 输出: "Hello, my name is John"// 通过原型链访问 Object 对象的 toString 方法
console.log(person1.toString());  // 输出: "[object Object]"

在上述例子中,Person 构造函数的原型对象上定义了一个 sayHello 方法。创建的 person1 对象实例可以直接访问和调用这个方法,因为它通过原型链与 Person 的原型对象关联起来。

此外,在访问 person1.toString() 时,虽然 person1 对象本身没有定义 toString 方法,但 JavaScript 引擎会沿着原型链向上查找。因为 person1 对象的原型是 Person.prototype,而 Person.prototype 的原型是 Object.prototype,所以最终能够找到 Object.prototype 上的 toString 方法并调用。

这就是基于原型链的继承机制,它允许对象通过原型链关联和继承其他对象的属性和方法。在 JavaScript 中,所有对象默认都继承自基础对象 Object.prototype,这是原型链的顶端。通过原型链,JavaScript 中的对象形成了一个层级结构,可以沿着原型链向上查找和访问属性和方法。

需要注意的是,原型链并不是无限深度的,当到达原型链的末尾(即 null)时,如果仍然没有找到对应的属性或方法,则认为该属性或方法不存在。

总结起来,JavaScript 的原型链机制提供了一种灵活且高效的继承方式,通过原型链,对象可以共享和继承其他对象的属性和方法,实现代码的复用和扩展。

4. 构造函数(constructor)

构造函数是用于创建对象的特殊函数。构造函数可以通过 new 关键字来调用,并且在创建对象时,会将对象的原型指向构造函数的 prototype 属性。

在 JavaScript 中,构造函数(constructor)是一种特殊的函数,用于创建和初始化对象。构造函数通常与 new 关键字一起使用,以创建新的对象实例。

以下是关于 JavaScript 构造函数的详细解释和示例代码:

// 构造函数
function Person(name, age) {this.name = name;this.age = age;
}// 创建对象实例
var person1 = new Person("John", 30);
var person2 = new Person("Jane", 25);console.log(person1.name);  // 输出: "John"
console.log(person2.age);   // 输出: 25

在上述例子中,Person 就是一个构造函数。它可以接受参数,并在新创建的对象实例上设置属性。构造函数中使用的 this 关键字是指向正在创建的对象的当前实例。

通过使用 new 关键字调用构造函数,我们可以创建对象的新实例。在创建实例时,JavaScript 引擎会执行以下操作:

  1. 创建一个空对象。
  2. 将该对象的原型指向构造函数的 prototype 属性。
  3. 将构造函数的 this 关键字绑定到该对象。
  4. 执行构造函数内部的代码,即初始化对象的属性。
  5. 返回该新创建的对象实例。

因此,通过 new Person("John", 30) 创建的 person1 对象实例会拥有 nameage 两个属性,并且这些属性的值是根据传入的参数进行初始化的。

需要注意的是,构造函数的命名约定通常以大写字母开头,以便与普通函数区分开来。这只是一种约定,并不是 JavaScript 强制要求的规则。但是,遵循这个约定有助于代码的可读性和理解。

构造函数可以定义自己的属性和方法,以供实例对象使用。例如,我们可以在构造函数的 prototype 属性上定义方法,这些方法会被所有由该构造函数创建的对象实例共享。

// 构造函数
function Person(name, age) {this.name = name;this.age = age;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person1 = new Person("John", 30);
var person2 = new Person("Jane", 25);person1.sayHello();  // 输出: "Hello, my name is John"
person2.sayHello();  // 输出: "Hello, my name is Jane"

在上述例子中,我们将 sayHello 方法定义在 Person 构造函数的 prototype 属性上。通过 person1.sayHello()person2.sayHello(),我们可以调用所有由 Person 构造函数创建的对象实例所共享的方法。

通过构造函数,可以轻松地创建具有相同属性和方法的多个对象实例。这样可以提高代码的复用性和可维护性,并且可以根据需要定制对象的属性和行为。

5. prototype 属性

每个函数对象都有一个 prototype 属性,它是一个普通的对象。构造函数的 prototype 属性被用作新对象的原型。

在 JavaScript 中,每个函数都有一个特殊的属性 prototypeprototype 是一个对象,它包含了由该函数创建的所有对象实例共享的属性和方法。

以下是关于 JavaScript 的 prototype 属性的详细解释和示例代码:

// 构造函数
function Person(name) {this.name = name;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person1 = new Person("John");
var person2 = new Person("Jane");person1.sayHello();  // 输出: "Hello, my name is John"
person2.sayHello();  // 输出: "Hello, my name is Jane"

在上述例子中,我们定义了一个 Person 构造函数,并在构造函数的 prototype 属性上添加了方法 sayHello。这意味着通过 Person 构造函数创建的所有对象实例都会继承并共享这个方法。

使用 prototype 对象的好处是,在创建多个对象实例时,不会重复定义相同的方法,而是将方法定义在 prototype 上,使每个对象实例都可以访问该方法。这样可以节省内存空间,并提高代码的执行效率。

可以通过 new 关键字创建的对象实例会自动拥有原型对象(即 prototype)中的属性和方法。当访问对象的属性或调用方法时,如果对象本身没有找到对应的属性或方法,JavaScript 引擎会通过原型链向上查找。

// 构造函数
function Person(name) {this.name = name;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person = new Person("John");console.log(person.name);  // 输出: "John"
person.sayHello();         // 输出: "Hello, my name is John"

在上述例子中,我们在 Person 构造函数的 prototype 上定义了一个 sayHello 方法。通过对象实例 person 访问该方法时,JavaScript 引擎会先查找 person 对象本身是否有 sayHello 方法,如果没有,则沿着原型链查找并找到 Person.prototype 上的 sayHello 方法并执行。

需要注意的是,每个对象实例都有一个特殊的 __proto__ 属性,它指向创建该实例的构造函数的 prototype 对象。通过该属性,我们可以直接访问对象实例的原型对象。

// 构造函数
function Person(name) {this.name = name;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person = new Person("John");console.log(person.__proto__ === Person.prototype);  // 输出: true

在上述例子中,person.__proto__ 引用了 Person.prototype 对象。这意味着通过 person.__proto__ 可以访问和修改原型对象的属性和方法。

总结起来,JavaScript 中的 prototype 属性是一个特殊属性,它包含了由构造函数创建的所有对象实例共享的属性和方法。通过在 prototype 上定义属性和方法,可以实现对象之间的属性和行为共享,并提高代码的复用性。

6. 实例(instance)

通过构造函数创建的对象称为实例,它继承了构造函数的 prototype 属性。

在 JavaScript 中,实例(instance)是通过构造函数创建的对象。每当使用 new 关键字调用一个构造函数时,就会创建一个新的对象实例。

以下是关于 JavaScript 实例的详细解释和示例代码:

// 构造函数
function Person(name, age) {this.name = name;this.age = age;
}// 创建对象实例
var person1 = new Person("John", 25);
var person2 = new Person("Jane", 30);console.log(person1); // 输出: Person { name: 'John', age: 25 }
console.log(person2); // 输出: Person { name: 'Jane', age: 30 }

在上述例子中,我们定义了一个 Person 构造函数,并通过 new 关键字创建了两个对象实例 person1person2。每个对象实例都有自己的属性 nameage,并且这些属性的值通过构造函数的参数初始化。

通过实例,我们可以访问和修改其属性,以及调用实例上的方法。

// 构造函数
function Person(name, age) {this.name = name;this.age = age;
}// 在构造函数的 prototype 属性上定义方法
Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 创建对象实例
var person = new Person("John", 25);console.log(person.name);      // 输出: "John"
console.log(person.age);       // 输出: 25
person.sayHello();             // 输出: "Hello, my name is John"

在上述例子中,我们在 Person 构造函数的 prototype 上定义了一个 sayHello 方法。通过对象实例 person 可以访问其属性 nameage,并调用 sayHello 方法。

每个对象实例都是独立的,它们之间的属性和方法是相互独立的。当通过构造函数创建多个对象实例时,每个实例都有自己的属性值。

// 构造函数
function Person(name) {this.name = name;
}// 创建对象实例
var person1 = new Person("John");
var person2 = new Person("Jane");console.log(person1.name);    // 输出: "John"
console.log(person2.name);    // 输出: "Jane"person1.name = "Bob";
console.log(person1.name);    // 输出: "Bob"
console.log(person2.name);    // 输出: "Jane"

在上述例子中,我们创建了 person1person2 两个对象实例,并给它们的 name 属性分别赋了不同的值。即使两个实例都是通过同一个构造函数创建的,但它们的属性值是相互独立的,互不影响。

总结起来,JavaScript 中的实例是通过构造函数创建的对象。每个实例都有自己的属性和方法,并且是相互独立的。通过实例,我们可以访问和修改其属性,以及调用实例上的方法。

7. 原型继承(prototype inheritance)

当一个对象的原型为另一个对象时,它会继承原型对象的属性和方法。这样可以实现对象之间的继承关系。

在 JavaScript 中,原型继承(prototype inheritance)是一种实现对象之间属性和行为共享的机制。通过原型链,一个对象可以继承另一个对象的属性和方法。

以下是关于 JavaScript 原型继承的详细解释和示例代码:

// 父类构造函数
function Animal(name) {this.name = name;
}// 父类原型定义方法
Animal.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
}// 子类构造函数
function Dog(name, breed) {Animal.call(this, name);this.breed = breed;
}// 使用 Object.create() 方法设置子类原型
Dog.prototype = Object.create(Animal.prototype);// 修正子类构造函数的指向
Dog.prototype.constructor = Dog;// 子类原型定义方法
Dog.prototype.bark = function() {console.log("Woof!");
}// 创建子类实例
var dog = new Dog("Max", "Labrador");console.log(dog.name);         // 输出: "Max"
console.log(dog.breed);        // 输出: "Labrador"
dog.sayHello();                // 输出: "Hello, my name is Max"
dog.bark();                    // 输出: "Woof!"

在上述例子中,我们定义了一个父类 Animal 和一个子类 Dog。通过原型继承,Dog 类继承了 Animal 类的属性和方法。

首先,我们定义了父类构造函数 Animal,并在其原型上定义了一个方法 sayHello。然后,我们定义了子类构造函数 Dog,在其中调用了父类的构造函数 Animal.call(this, name),以便在子类实例中初始化父类的属性。

接下来,我们使用 Object.create() 方法将子类的原型对象设置为父类的原型对象,从而实现原型链的继承关系。通过这样的设置,子类的实例可以访问和继承父类原型中的属性和方法。

最后,我们在子类的原型上定义了一个新的方法 bark

通过创建子类实例 dog,我们可以访问其继承自父类和子类原型的属性和方法。即使子类没有直接定义 sayHello 方法,也可以通过原型链找到父类原型中的方法并调用。

需要注意的是,通过原型继承可以实现属性和方法的共享,即多个对象实例共享同一个原型对象。这样可以节省内存空间,并提高代码的复用性和执行效率。

总结起来,JavaScript 中的原型继承是一种实现对象之间属性和行为共享的机制。通过原型链,子类可以继承父类的属性和方法。通过设置子类的原型对象为父类的原型对象,实现了原型继承关系。这种继承方式可以实现属性和方法的共享,并提高代码的复用性。

8. this 关键字

this 关键字在 JavaScript 中表示当前函数的执行上下文。在构造函数中,this 指向正在创建的实例。

9. Object.create() 方法

Object.create() 是一个静态方法,用于创建一个新对象,并将该对象的原型指向指定的原型对象。

以上是原型链的相关概念,理解原型链对于深入理解 JavaScript 中的对象和继承非常重要。


http://www.ppmy.cn/news/900887.html

相关文章

4-1 Working with images

4-Real-world data representation using tensors How do we take a piece of data, a video, or a line of text, and represent it with a tensor in a way that is appropriate for training a deep learning model? This is what we’ll learn in this chapter. We menti…

android 向上滑动home,滑动Home键

你是否感覺你的Home鍵很難按?是否感覺你的Home鍵快要壞掉了?是否覺得你的通知欄太遠? 滑動Home鍵是一個改變你操縱手機方式的革命性的工具。 它用滑動收拾提供了5個最實用的功能。 不再需要Home鍵,不必再去下拉遙遠的通知欄。 你現…

苹果home键在哪里设置_五毛特效?苹果X的Home键又回来了!

习惯是个很可怕的东西,一旦适应了就很难再变回去。这一句话对于苹果用户来说,算是恰得其所。iPhone X设计的思维跨度过大,以至于很长一段时间,用户都难以适应新手机的操作,开始怀念曾有有Home键、有耳机接口的日子了。…

苹果手机home键在哪里_苹果手机为什么没有返回键?原来隐藏着更好的方法,涨知识了...

手机主要分为苹果和安卓两种,安卓手机的用户,如果突然换用了苹果手机,就会发现很难适应。没有返回键、后台键的手机,仅为一个Home键就可以操作全部。 一、不用返回键原因 苹果发布的第一代产品就没有设计返回键,仅在屏…

mac下的insert键

mac下的insert键 (2009-03-27 14:46:56) 标签: 杂谈 分类: MSN搬家 用过mac pro的人都知道,keyboard里是没有insert键的。但是可以通过 fn command enter实现哦。

mac外接键盘HOME,END键问题

转载自:https://www.icode9.com/content-4-838111.html mac老用户应该都知道, MAC自带的键盘的 cmd左/右箭头 快捷键实际上就对应的是 HOME 和 END; 但是如果外接了自带 HOME 和 END 键的键盘, 就会发生不幸的事情, 你会发现HOME和END根本无法使用, 因为mac系统本身…

1.18 什么是架构

文章目录 什么是架构软件架构与系统架构架构的重要性常见的架构模式结论 什么是架构 架构(Architecture)在计算机领域中是指系统或应用程序的设计和组织方式。它描述了系统的整体结构、组件之间的关系、数据流和交互方式。架构不仅仅涉及技术方面&#…

ADAS专栏系列说明

ADAS专栏系列说明 1.前言2.本专栏主要内容 1.前言 ADAS的全称是Advanced Driving Assistance System,即高级驾驶辅助系统,其旨在通过在车辆上安装一系列传感器(相机、激光雷达、毫米波雷达等)和执行器完成驾驶辅助功能&#xff0…