JS-原型&原型链

JS-原型&原型链

JavaScript 的对象模型是基于原型的,这句话意味着 JavaScript 中的对象不是通过类来定义和继承的(如 Java 或 C++),而是通过一个称为“原型”的机制来进行属性查找和行为(方法)共享的

在js中,任何函数在被new关键字修饰函数后,就成为构造函数了,所以任何函数都有成为构造函数的可能

在js中,函数本身即对象,所以prototype是函数特有的属性


prototype&_proto_

prototype是某一个构造函数实例化的所有对象可以找到公共的方法和属性,这个属性的设计之初,就是为了实现对象方法和属性的集成

__proto__属性是一个构造函数实例化成为对象后存在的属性

var Parent = function(){

}

var instance = new Parent();

Parent.prototype.name = "所有Parent的实例都可以读取到我";

let p1 = new Parent();
let p2 = new Parent();

p1.name //"所有Parent的实例都可以读取到我";
p2.name //"所有Parent的实例都可以读取到我";

在这里,Parent在实例化为p1对象之前,通过这个方法的属性prototype,增加了一个name属性(还可以增加其他的属性或者方法)

但实例化p1对象之后,p1对象存在一个属性_proto_,这个属性等于其构造函数的prototype属性

当p1.name被执行时,首先寻找p1对象中是否存在这个name属性,如果不存在则找到_proto_,也就是找到其构造函数的prototype属性(他也是一个对象)

从中寻找到被添加的name属性


原型链

每个对象都有一个内部链接([[Prototype]]),它指向另一个对象,这个被链接的对象就是我们所说的“原型”。当尝试访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript 引擎会沿着这条 [[Prototype]] 链向上查找,直到找到该属性或到达原型链的末端(即 null),因为 null 表示没有更多的原型可以访问。

构造函数与原型

当你使用构造函数创建对象时,构造函数有一个名为 prototype 的属性,它是一个对象,所有由该构造函数创建的实例都会将它们的内部 [[Prototype]] 指向这个 prototype 对象。因此,这些实例共享了原型上的属性和方法。

function Person(name) {
    this.name = name;
}

Person.prototype.sayHello = function() {
    console.log("Hello, " + this.name);
};

let person1 = new Person('Alice');
person1.sayHello();  // 输出: Hello, Alice

在这个例子中,person1[[Prototype]] 指向 Person.prototype,所以它可以访问 sayHello 方法,即使该方法并没有直接定义在 person1 上。

动态特性

由于原型链的存在,JavaScript 对象是动态的,这意味着你可以在运行时添加、修改或删除对象的属性和方法,甚至改变原型链。例如,你可以随时向原型添加新的方法,所有已经存在的实例也会立即获得这些新方法。

// 给原型添加一个新的方法
Person.prototype.sayGoodbye = function() {
    console.log("Goodbye, " + this.name);
};

person1.sayGoodbye();  // 输出: Goodbye, Alice