原型
前言
在JavaScript中,原型(prototype)是一个非常重要且独特的概念,它在对象创建和继承方面发挥着关键作用。理解原型及其相关的机制有助于更好地理解JavaScript的对象模型,以及如何设计和使用对象和继承。
原型
通常了解JavaScript 中的原型时,会将其分为两种类型:函数原型prototype(显示原型)和对象原型__proto__(隐式原型)
函数原型:
在 JavaScript 中,每个函数都有一个特殊的属性称为 prototype
,它是函数被创建时自动生成的一个对象。函数原型对象用于存储可以被函数的所有实例共享的属性和方法。
function Person(name) {
this.name = name;
}
// Person 函数的原型对象
Person.prototype.sayHello = function() {
console.log('Hello, my name is ' + this.name);
};
const person1 = new Person('Alice');
const person2 = new Person('Bob');
person1.sayHello(); // 输出:Hello, my name is Alice
person2.sayHello(); // 输出:Hello, my name is Bob
函数原型与其实例对象的关系
-
实例对象可以修改显示继承的属性和方法,但无法修改原型上的属性和方法(隐式继承的属性) :
实例对象通过原型链继承了函数原型上的属性和方法。这意味着,如果原型上的属性是可写的,实例对象是可以修改它们的值的,但是它们不能直接修改原型对象上的属性。如果尝试直接给原型对象上的属性赋值,实际上是在给实例对象新增一个同名的属性,而不是修改原型上的属性。
function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log('Hello, my name is ' + this.name); }; const person1 = new Person('Alice'); const person2 = new Person('Bob'); // 修改实例对象的属性值 person1.name = 'Charlie'; // 不能修改原型上的属性值 person1.sayHello = function() { console.log('Hi, I am ' + this.name); }; person1.sayHello(); // 输出:Hi, I am Charlie person2.sayHello(); // 输出:Hello, my name is Bob
-
实例对象无法给原型新增属性:
实例对象无法直接给原型对象新增属性。任何试图给实例对象的原型对象添加属性的尝试,都将在实例对象上创建一个新的属性,而不会影响到原型对象本身。
function Person(name) { this.name = name; } const person1 = new Person('Alice'); const person2 = new Person('Bob'); // 试图给实例对象的原型对象新增属性 person1.age = 30; // 但实际上在实例对象上创建了一个新的属性,而不是在原型上新增 console.log(person1.age); // 输出:30 console.log(person2.age);//underfined
-
实例对象无法删除原型上的属性:
实例对象无法直接删除原型对象上的属性。任何试图删除实例对象原型链上的属性的尝试,都将失败,因为删除操作只会影响到实例对象自身的属性。
function Person(name) { this.name = name; } Person.prototype.age = 30; const person1 = new Person('Alice'); const person2 = new Person('Bob'); // 试图删除原型对象上的属性 delete person1.name; // 但实际上只是删除了实例对象上的属性,原型对象上的属性并未受影响 console.log(person1.name); // underfined console.log(person2.name);//Bob
对象原型
每个对象都有一个特殊的内部属性 __proto__
,它指向该对象的原型。原型可以是另一个对象或者 null
。
let person1 = new Person('Alice');
console.log(person1.__proto__ ); // Person.prototype
函数原型与对象原型的关系
函数原型和对象原型之间有一个重要的关系:通过函数原型,我们可以在创建的对象之间共享方法和属性。
当你创建一个新的对象时,JavaScript 引擎会自动将对象的 __proto__
属性设置为该构造函数的 prototype
属性的值。
例如:
let person2 = new Person('Bob');
console.log(person2.__proto__ === Person.prototype); // true
constructor
属性
在原型链中,constructor
属性指的是指向创建对象的构造函数的引用。每个对象都有一个 constructor
属性,它引用了创建该对象的构造函数。
示例:
function Person(name) {
this.name = name;
}
const person1 = new Person('Alice');
// person1 的 constructor 属性指向 Person 构造函数
console.log(person1.constructor === Person); // 输出: true
综上所述如图:
原型链
什么是原型链?
原型链是 JavaScript 中用于实现继承和属性查找的一种机制。每个对象都有一个原型对象(prototype),通过原型对象可以实现属性和方法的继承。当访问一个对象的属性或方法时,如果对象本身不存在这个属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到相应的属性或方法或者到达原型链的顶端(Object.prototype)为止。
原型链的继承关系
在 JavaScript 中,对象之间的继承关系通过原型链来实现。例如:
javascriptCopy Code
// 定义一个动物类
function Animal(name) {
this.name = name;
}
// 在动物类的原型上添加方法
Animal.prototype.sleep = function() {
console.log(this.name + " is sleeping");
};
// 定义一个狗类
function Dog(name, breed) {
Animal.call(this, name); // 调用父类的构造函数
this.breed = breed;
}
// 继承动物类的原型
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 在狗类的原型上添加方法
Dog.prototype.bark = function() {
console.log("Woof! Woof!");
};
// 创建一个狗的实例
var dog1 = new Dog("Buddy", "Labrador");
// 调用狗的方法
dog1.sleep(); // 输出: Buddy is sleeping
dog1.bark(); // 输出: Woof! Woof!
在这个例子中,Dog
类继承了 Animal
类的属性和方法,通过原型链的方式实现了继承关系。
属性查找过程
当访问对象的属性或方法时,JavaScript 引擎会沿着原型链向上查找,直到找到相应的属性或方法或者到达原型链的顶端。如果找不到相应的属性或方法,则返回 undefined
。
所有对象都有原型嘛(考点)
这个答案肯定是不对的!
除了Object 本身之外,所有对象都有原型
-
Object 的实例:通过 new Object() 创建的对象,以及通过对象字面量创建的对象(如
{}
),其原型是 Object.prototype。示例:
const obj = {}; console.log(obj.__proto__ === Object.prototype); // 输出: true
-
函数的实例:函数也是对象,通过 new Function() 创建的函数对象,其原型是 Function.prototype。
示例:
function myFunction() {} console.log(myFunction.__proto__ === Function.prototype); // 输出: true
-
数组的实例:通过 new Array()创建的数组对象,其原型是 Array.prototype。
示例:
const arr = []; console.log(arr.__proto__ === Array.prototype); // 输出: true
-
其他内置对象:例如 Date、RegExp、Error 等对象的实例,它们的原型分别是 Date.prototype、RegExp.prototype、Error.prototype。
示例:
const date = new Date(); console.log(date.__proto__ === Date.prototype); // 输出: true
Object.prototype 是原型链的顶端
-
Object.prototype 是原型链的顶端对象,它的原型是 null。
示例:
console.log(Object.prototype.__proto__); // 输出: null
使用 Object.create() 创建没有原型的对象(重点)
-
如果你想创建一个没有原型的对象,可以使用
Object.create(null)
。示例:
const noProtoObj = Object.create(null); console.log(noProtoObj.__proto__); // 输出: undefined
最后
搞懂原型,好好学习,天天向上!