了解JavaScript中的原型和原型继承

This article is going to look at object prototypes and how we can use constructor functions to extend prototypes in new objects.

本文将研究对象原型,以及如何使用构造函数扩展新对象中的原型。

JavaScript is a prototype-based language, which means object properties and methods can be shared through objects that have the ability to be cloned and extended. This is known as prototypal inheritance.

JavaScript是一种基于原型的语言 ,这意味着可以通过具有克隆和扩展功能的对象共享对象的属性和方法。 这被称为原型继承。

In my previous article, Understanding objects in JavaScript, I went over how to create an object, how to access object properties and how to modify them. Now we are going to learn how prototypes can be used to extend objects.

在上一篇文章“ 理解JavaScript中的对象”中 ,我介绍了如何创建对象,如何访问对象属性以及如何对其进行修改。 现在,我们将学习如何使用原型来扩展对象。

Nearly all objects in JavaScript are instances of Object which sit on the top of a prototype chain. This means they have an internal property called prototype. The prototype is a reference to another object and it gets used whenever JavaScript can’t find the property it is looking for on the current object.

JavaScript中几乎所有对象都是位于原型链顶部的Object实例。 这意味着它们具有一个称为prototype的内部属性。 prototype是对另一个对象的引用,当JavaScript在当前对象上找不到它要查找的属性时,就会使用该prototype

We can check this if we create a new, empty object.

如果我们创建一个新的空对象,我们可以检查一下。

const newObject = {};console.log(newObject);

If we look in the console we can see the __proto__ property which exposes the internal prototype of the object. This consists of several built-in properties and methods.

如果在控制台中查看,则可以看到__proto__属性,该属性公开了对象的内部prototype 。 这由几个内置的属性和方法组成。

{}
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

To get the prototype of this new object we use the getPrototypeOf() method.

为了获得这个新对象的prototype ,我们使用getPrototypeOf()方法

const newObject = {};const prototype = Object.create(newObject);console.log(Object.getPrototypeOf(prototype) === newObject); // true

Let’s look at a more detailed code example. We are going to create a Sandwich constructor. We will then create an instance of Sandwich and assign it to a new variable called mySandwich.

让我们看一个更详细的代码示例。 我们将创建一个Sandwich构造函数。 然后,我们将创建Sandwich的实例,并将其分配给名为mySandwich的新变量。

function Sandwich(fillings = [], customer, bread) {
this.fillings = fillings;
this.customer = customer;
this.bread = bread;
this.describe = function() {
return `This sandwich is for ${this.customer} with the toppings ${this.fillings.join(', ')} on ${this.bread} bread`;
}
}const mySandwich = new Sandwich(['cheese', 'ham', 'lettuce', 'tomato', 'cucumber'], 'Gemma', 'wholemeal');console.log(mySandwich.describe());// This sandwich is for Gemma with the toppings cheese, ham, lettuce, tomato, cucumber on wholemeal bread

If we look at mySandwich in the console we can see the describe function exists as an instance property.

如果在控制台中查看mySandwich ,我们可以看到describe函数作为实例属性存在。

mySandwich
Sandwich {fillings: Array(5), customer: "Gemma", bread: "wholemeal", describe: ƒ}
bread: "wholemeal"
customer: "Gemma"
describe: ƒ ()
fillings: (5) ["cheese", "ham", "lettuce", "tomato", "cucumber"]
__proto__: Object

Let’s create another instance of Sandwich using some different parameters.

让我们使用一些不同的参数创建另一个Sandwich实例。

const mySandwichVeggie = new Sandwich(['lettuce', 'tomato', 'onion', 'pickles', 'olives', 'capscicum', 'spinach', 'carrot'], 'Sam', 'white');console.log(mySandwichVeggie.describe());// This sandwich is for Sam with the toppings lettuce, tomato, onion, pickles, olives, capscicum, spinach, carrot on white bread

What happens if we directly compare our newly created sandwich describe() function with the original mySandwich describe method.

如果我们直接将新创建的mySandwich describe describe()函数与原始mySandwich describe方法进行比较,会发生什么情况。

mySandwich.describe === mySandwichVeggie.describe // false

They are not the same function; we are duplicating functionality. If we create 50 sandwiches we would have 50 copies of the same function which could potentially cause performance issues and make our code hard to maintain.

它们是不同的功能。 我们正在复制功能。 如果我们创建50个三明治,我们将有50个相同功能的副本,这可能会导致性能问题并使我们的代码难以维护。

To solve the duplication issue we can add this functionality to the prototype.

为了解决复制问题,我们可以将此功能添加到prototype

Sandwich.prototype.describe = function() {
return `This sandwich is for ${this.customer} with the toppings ${this.fillings.join(', ')} on ${this.bread} bread`;
}

Now if we look at mySandwich or mySandwichVeggie, describe() no longer exists as an instance property, it is, however, visible in the __proto__.

现在,如果我们查看mySandwichmySandwichVeggiedescribe()不再作为实例属性存在,但是它在__proto__可见。

mySandwich
Sandwich {fillings: Array(5), customer: "Gemma", bread: "wholemeal"}
bread: "wholemeal"
customer: "Gemma"
fillings: (5) ["cheese", "ham", "lettuce", "tomato", "cucumber"]
__proto__:
describe: ƒ ()
constructor: ƒ Sandwich(fillings = [], customer, bread)
__proto__: Object

This means that every time we create a new Sandwich we now have access to the describe() function.

这意味着,每次创建新的Sandwich ,现在都可以访问describe()函数。

JavaScript will check for a property on the instance first and if it doesn’t exist it will check the prototype.

JavaScript将首先在实例上检查属性,如果不存在,它将检查prototype

If we add a new instance property to the prototype and to the instance itself we can see this in action.

如果我们向prototype和实例本身添加新的实例属性,那么我们可以看到这一点。

function Sandwich(fillings = [], customer, bread) {
this.fillings = fillings;
this.customer = customer;
this.bread = bread;
this.price = '5.50';
}Sandwich.prototype.price = '4.00';mySandwich
Sandwich {fillings: Array(5), customer: "Gemma", bread: "wholemeal", price: "5.50"}
bread: "wholemeal"
customer: "Gemma"
fillings: (5) ["cheese", "ham", "lettuce", "tomato", "cucumber"]
price: "5.50"
__proto__: Object

The price of mySandwich is 5.50 because JavaScript doesn’t need to go to the prototype, the property exists on the instance.

mySandwich的价格为5.50因为JavaScript不需要进入prototype ,该属性存在于实例上。

Summary

摘要

  • JavaScript is a prototype-based language

    JavaScript是一种基于原型的语言
  • Prototypal inheritance means object properties and methods can be shared through objects that have the ability to be cloned and extended

    原型继承意味着可以通过具有克隆和扩展功能的对象共享对象属性和方法
  • Nearly all objects in JavaScript are instances of Object which sit on the top of a prototype chain which means they have an internal property called prototype

    JavaScript中几乎所有对象都是位于原型链顶部的Object实例,这意味着它们具有一个称为prototype的内部属性。

  • The prototype is a reference to another object and it gets used whenever JavaScript can’t find the property it is looking for on the current object

    prototype是对另一个对象的引用,当JavaScript在当前对象上找不到它要查找的属性时,就会使用该prototype

  • JavaScript will first check for a property on the instance then check the prototype

    JavaScript将首先检查实例上的属性,然后检查prototype

翻译自: https://medium.com/@gemma.stiles/understanding-prototypes-and-prototypal-inheritance-in-javascript-68c791df65dc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值