文章目录
- 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
,然后通过赋值语句给这个对象添加了几个属性 name
、age
、gender
,并为对象定义了一个方法 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
构造函数创建的对象共享。通过原型链的机制,对象实例 person1
和 person2
可以访问和调用原型中定义的方法。
当我们调用 person1.sayHello()
时,JavaScript 引擎首先在 person1
对象上查找 sayHello
方法,但找不到,然后会沿着原型链向上查找,最终在 Person.prototype
上找到并执行该方法。
除了继承方法,通过原型还可以继承属性。当我们尝试访问一个对象的属性时,如果对象本身没有该属性,JavaScript 引擎也会沿着原型链向上查找,直到找到该属性或原型链结束。
console.log(person1.age); // 输出: 30
console.log(person2.name); // 输出: "Jane"
在上述代码中,我们可以直接通过实例对象 person1
和 person2
访问构造函数 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 引擎会执行以下操作:
- 创建一个空对象。
- 将该对象的原型指向构造函数的
prototype
属性。 - 将构造函数的
this
关键字绑定到该对象。 - 执行构造函数内部的代码,即初始化对象的属性。
- 返回该新创建的对象实例。
因此,通过 new Person("John", 30)
创建的 person1
对象实例会拥有 name
和 age
两个属性,并且这些属性的值是根据传入的参数进行初始化的。
需要注意的是,构造函数的命名约定通常以大写字母开头,以便与普通函数区分开来。这只是一种约定,并不是 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 中,每个函数都有一个特殊的属性 prototype
。prototype
是一个对象,它包含了由该函数创建的所有对象实例共享的属性和方法。
以下是关于 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
关键字创建了两个对象实例 person1
和 person2
。每个对象实例都有自己的属性 name
和 age
,并且这些属性的值通过构造函数的参数初始化。
通过实例,我们可以访问和修改其属性,以及调用实例上的方法。
// 构造函数
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
可以访问其属性 name
和 age
,并调用 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"
在上述例子中,我们创建了 person1
和 person2
两个对象实例,并给它们的 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 中的对象和继承非常重要。