大家好,我是睡个好jo,今天要给大家分享的是js中的原型。
在JavaScript中,原型(Prototype)机制是实现对象继承和属性共享的核心概念。这篇文章将会带着大家去了解并掌握原型的相关知识
每个函数在JavaScript中都自带一个特殊的属性——prototype。这个属性是一个对象,用于定义通过该构造函数创建的所有实例所共享的属性和方法。简而言之,构造函数的prototype对象就是其所有实例对象的公共祖先。
当然,让我们通过一个具体的例子来说明prototype的工作原理。假设我们要创建一个表示动物的构造函数,特别是创建一个猫的类,我们可以这样做:
function Cat(name, color) { this.name = name; this.color = color;}// 给Cat构造函数的prototype添加一个方法Cat.prototype.meow = function() { console.log(this.name + ", the " + this.color + " cat, says 'Meow!'");}
在这个例子中,Cat是一个构造函数,用于生成猫的实例。我们通过Cat.prototype给所有的猫实例添加了一个共享的方法meow()。这意味着,所有通过new Cat()创建的对象都将能够访问到meow方法,而不需要在每个实例中单独定义。
接下来,我们创建两个猫的实例并调用它们的meow方法:
let kitty1 = new Cat("Whiskers", "gray");let kitty2 = new Cat("Snowball", "white");kitty1.meow(); // 输出: Whiskers, the gray cat, says 'Meow!'kitty2.meow(); // 输出: Snowball, the white cat, says 'Meow!'
尽管meow方法是在Cat.prototype上定义的,但kitty1和kitty2都能够访问到它,因为它们的原型链(__proto__)指向了Cat.prototype。这样,meow方法就成为了所有由Cat构造函数创建的对象所共享的功能,节省了内存并体现了面向对象编程中“继承”的概念。
以下内容需要先了解new,请先看你news什么new,stanley(是单例)
当通过构造函数(使用new关键字)创建一个对象时,该对象会自动获得一个内部属性[[Prototype]](可通过__proto__访问,尽管非标准)。这个内部属性指向构造函数的prototype对象,使得实例能访问原型上的属性和方法。这些属性虽然对实例可见,但修改它们实际上会影响所有通过该构造函数创建的实例,因为它们是共享的。
但是实例不能改变原型对象上的属性和方法:
假设我们有一个构造函数Person,并在其原型上定义了一个属性gender。
function Person(name) { this.name = name;}Person.prototype.gender = "unknown"; // 在原型上定义gender属性
放在浏览器上访问:
现在,我们创建两个Person的实例person1和person2。
let person1 = new Person("Alice");let person2 = new Person("Bob");
访问原型属性: 当我们访问person1.gender或person2.gender时,由于实例自身没有定义gender属性,JavaScript会沿着原型链找到Person.prototype.gender,因此两个实例都会显示"unknown"。
修改实例属性: 如果我们直接修改person1的gender属性,这实际上是在person1实例上新增了一个名为gender的属性,覆盖了从原型链上继承来的同名属性,但不影响person2或Person.prototype。
person1.gender = "female";console.log(person1.gender); // 输出:"female"console.log(person2.gender); // 输出:"unknown",未受影响console.log(Person.prototype.gender); // 输出:"unknown",原型属性未变
总结
原型链是JavaScript实现对象属性查找的机制。当访问一个对象的属性时,如果该对象自身没有这个属性,JavaScript引擎会继续在其[[Prototype]](即隐式原型)所指向的对象中查找。这一过程会持续进行,沿着原型链逐级向上查找,直到找到该属性或到达原型链的末端(null)。
我们来根据以下图片来分析:
并非所有JavaScript对象都有原型。使用Object.create(null)可以创建一个没有原型的对象,即该对象的__proto__为null,这样的对象不继承任何属性或方法,是真正的“纯净”对象。
// 定义Car构造函数,为其原型添加属性Car.prototype.name = 'su7'; // 品牌Car.prototype.lang = 5000; // 长度Car.prototype.height = 1400; // 高度 function Car(color, owner) { this.color = color; this.owner = owner; }// 创建Car实例let car1 = new Car('pink', 'ii');let car2 = new Car('orange', 'jj');let car3 = new Car();// 输出验证console.log(car1.name); // 输出: su7console.log(car1.lang); // 输出: 5000console.log(Car); // 输出: [Function: Car]console.log(Car.prototype === Car.__proto__); // 输出: false
在上述示例中,我们定义了一个Car构造函数,并通过其prototype属性为所有Car实例添加了共享属性。通过new Car()创建的每个实例都能访问这些共享属性。最后一行输出false是因为Car.prototype是Car函数的原型对象,而Car.__proto__实际上是Function.prototype,它们指向不同的对象。
通过这些概念和示例,我们可以更深刻地理解JavaScript的原型机制,它是实现面向对象编程、实现继承和属性复用的重要基石。
文章转自:
https://juejin.cn/post/7376690981859655714