js原型继承和构造继承_js原型和继承

js原型继承和构造继承

Javascript is a prototype-based language, meaning objects properties and methods can be shared through generalized objects that have the ability to be cloned and extended. This is known as prototypical inheritance and differs from class inheritance. Among popular object oriented programming languages, JavaScript is relatively unique, as other prominent languages such as PHP, Python and Java are class based -languages which instead define classes as blueprints for other objects.

Javascript是一种基于原型的语言,这意味着可以通过具有克隆和扩展能力的通用对象来共享对象的属性和方法。 这称为原型继承,与类继承不同。 在流行的面向对象的编程语言中,JavaScript是相对独特的,因为其他著名的语言(如PHP,Python和Java)都是基于类的语言,而是将类定义为其他对象的蓝图。

JavaScript原型 (JavaScript Prototypes)

In Understanding Objects in Javascript, we went over the object data type, how to create an object, and to access and modify object properties. Now we will learn how prototypes can used to extend objects.

在理解Java语言中的对象中,我们介绍了对象数据类型,如何创建对象以及访问和修改对象属性。 现在,我们将学习原型如何用于扩展对象。

Every object in JavaScript has an internal property called [[Prototype]]. We can demonstrate this by creating a new empty object.

JavaScript中的每个对象都有一个称为[[Prototype]]的内部属性。 我们可以通过创建一个新的空对象来演示这一点。

let x = {};

令x = {};

This is the way we would normally create an object, but note that another way to accomplish this is with object constructor: let x = new Object().

这是我们通常创建对象的方式,但是请注意,完成此操作的另一种方法是使用对象构造函数:let x = new Object()。

The double square brackets that enclose [[Prototype]] signify that it is an internal property, and cannot accessed directly in code.

包含[[Prototype]]的双方括号表示它是一个内部属性,不能直接在代码中访问。

To find the [[Prototype]] of this newly created object, we will use the getPrototype() method.

为了找到这个新创建对象的[[Prototype]],我们将使用getPrototype()方法。

Object.getPrototypeOf(x);

Object.getPrototypeOf(x);

The output will consist of several built-in properties and methods.

输出将包含几个内置的属性和方法。

{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}

Another way to find the [[Prototype]] is through the __proto__ property. __proto__ is a property that exposes the internal [[Prototype]] of an object.

查找[[Prototype]]的另一种方法是通过__proto__属性。 __proto__是公开对象内部[[Prototype]]的属性。

It is important to note that .__proto__ is a legacy feature and should not be used in production code, and it is not present in every modern browser. However, we can use it throughout this article for demonstrative purposes.

重要的是要注意.__ proto__是一个遗留功能,不应在生产代码中使用,并且并非在每个现代浏览器中都存在。 但是,我们可以在整篇文章中使用它进行演示。

x.__proto__;

x .__ proto__;

The output will be the same as if you had used getPrototypeOf().

输出将与您使用getPrototypeOf()相同。

{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}

It is important that every object in JavaScript has a [[Prototype]] as it creates a way for any two or more onjects to be linked.

JavaScript中的每个对象都必须具有[[Prototype]],这一点很重要,因为它为链接两个或多个对象提供了一种方法。

Objects that you create have a [[Protoype]], as do built-in objects, such as Date and Array. A reference can be made to this internal property from one object to another via the prototype property, as we will see later

您创建的对象与内置对象(如Date和Array)一样,具有[[Protoype]]。 可以通过prototype属性从一个对象到另一个对象对该内部属性进行引用,我们将在后面看到

原型继承 (Prototype Inheritance)

When you attempt to access a property or method of an object, JavaScript will first search on the object itself and if it is not found, it will search the objects [[Prototype]]. If after consulting both the object and its [[Prototype]] still no match is found, JavaScript will check the prototype of linked object, an d continue searching until the end of the prototype chain is reached.

当您尝试访问对象的属性或方法时,JavaScript首先会搜索对象本身,如果找不到,它将搜索对象[[Prototype]]。 如果在查询了对象及其[[Prototype]]后仍然找不到匹配项,JavaScript将检查链接对象的原型,然后继续搜索直到到达原型链的末尾。

At the end of the prototype chain is Object.prototype. All objects inherits the properties and methods of Object. Any attempt to search beyond the end of the chain results in null.

原型链的末尾是Object.prototype。 所有对象都继承对象的属性和方法。 超出链末尾进行搜索的任何尝试均将导致null。

In our example, x is an empty object that inherits from Object. x can use any property or method that Object has, such as toString().

在我们的示例中,x是一个从Object继承的空对象。 x可以使用Object具有的任何属性或方法,例如toString()。

x.toString();

x.toString();

[object, Object]

[对象,对象]

This property chain is only one link long. x ->. Object. We know this, because if we try to chain two [[Prototype]] properties together, it will be null.

此属性链只有一个链接。 x->。 目的。 我们知道这一点,因为如果我们尝试将两个[[Prototype]]属性链接在一起,则它将为null。

x.__proto__.__proto__;

x .__ proto __.__ proto__;

null

空值

Let’s look at another type of object. If you have experience Working with Arrays in JavaScript, you know they have many built-in methods such as pop() and push(). The reason you have access to these methods when you create a new array is because any array you create has access to the properties and methods on the Array.prototype

让我们看另一种对象。 如果您有使用JavaScript处理数组的经验,则知道它们具有许多内置方法,例如pop()和push()。 创建新数组时可以访问这些方法的原因是,您创建的任何数组都可以访问Array.prototype上的属性和方法。

We can test this by creating a new array.

我们可以通过创建一个新的数组进行测试。

let y= [];

令y = [];

Keep in mind that we could also write it as an array constructor, let y = new Array().

请记住,我们也可以将其编写为数组构造函数,让y = new Array()。

If we take a look at the [[Prototype]] of the new y array, we will see that it has more properties and methods than the x object. It has inherited everything from Array.protoype

如果我们看一下新y数组的[[Prototype]],我们会发现它比x对象具有更多的属性和方法。 它继承了Array.protoype的所有内容

y.__proto__;

y .__ proto__;

[constructor: ƒ, concat: ƒ, pop: ƒ, push: ƒ, …]

You will notice a constructor property on the prototype that is set to Array(). The constructor property returns the constructor function of an object, which is mechanism used to construct objects from functions.

您会注意到原型上的构造函数属性设置为Array()。 Constructor属性返回对象的构造函数,该函数是用于从函数构造对象的机制。

We can chain two protoypes together, since our prototype chain is longer in this case. It looks like y -> Array -> Object.

我们可以将两个原型链接在一起,因为在这种情况下原型链更长。 看起来像y-> Array-> Object。

y.__proto__.__proto__;

y .__ proto __.__ proto__;

{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}

This chain is now referring to Object.prototype. We can test the internal [[Prototype]] against the prototype. property of the constructor function to see that they are referring to the same thing.

现在,此链指的是Object.prototype。 我们可以针对原型测试内部[[Prototype]]。 构造函数的属性,以查看它们所指的是同一事物。

y.__proto__ === Array.prototype; //true
y.__proto__.__proto__ === Object.prototype //true

We can use the instanceof operatior to test whether the prototype property of. constructor appears anywhere within an object’s prototype chain.

我们可以使用instanceof操作符来测试是否具有prototype属性。 构造函数出现在对象原型链中的任何位置。

y instanceof Array; // true

To summarize, all JavaScript objects have a hidden internal [[Prototype]] property (which may be exposed through __proto__ in some browsers). Objects can be extended and will inherit the properties and methods on [[Prototype]] of their constructor.

总而言之,所有JavaScript对象都有一个隐藏的内部[[Prototype]]属性(在某些浏览器中可能会通过__proto__公开)。 可以扩展对象,并将继承其构造函数的[[Prototype]]上的属性和方法。

These prototypes can be chained, and each additional object will inherit everything thoughout the chain. The chain ends with the Object.prototype.

这些原型可以被链接,每个附加对象将继承链中的所有内容。 链以Object.prototype结尾。

构造函数 (Constructor Functions)

Constructor functions are functions that are used to construct new objects. The new operator is used to create new instances based off a constructor function. We have seen some built-in JavaScript constructors, such as new Array() and new Date(), but we can also create our own custom template from which to build new objects.

构造函数是用于构造新对象的函数。 new运算符用于基于构造函数创建新实例。 我们已经看到了一些内置JavaScript构造函数,例如new Array()和new Date(),但是我们还可以创建自己的自定义模板,从中构建新对象。

As an example, lets say we are creating a very simple, text based role-playin game. A user can select a character and then choose what character class they will have such as warrior, healer, thief and so on.

例如,假设我们正在创建一个非常简单的基于文本的角色扮演游戏。 用户可以选择一个角色,然后选择他们将拥有的角色类别,例如战士,治疗者,小偷等等。

Since each character will share many characteristics, such as having a name, a level and hit points it makes sense to create a constructor as a template. Hoever, since each character class may have vastly different abilities, we want to make sure each character only has access to their own abilities. Let’s take a look at how we can accomplish this with the prototype inheritance and constructors.

由于每个角色将共享许多特征,例如具有名称,级别和生命值,因此有必要将构造函数创建为模板。 但是,由于每个角色类别可能具有截然不同的能力,因此我们要确保每个角色只能使用自己的能力。 让我们看一下如何通过原型继承和构造函数来完成此任务。

To begin, a constructor funtion is just a regular function. It becomes a constructor when it is a called on by an instance with the new keyword. In JavaScript, we capitalize the first letter of a constructor function by convention.

首先,构造函数只是一个常规函数。 当实例使用new关键字调用它时,它将成为构造函数。 在JavaScript中,我们按约定将构造函数的首字母大写。

function Hero(name, level){
this.name = name;
this.level = level;
}

We have created a constructor function called Hero with two parameters: name and level. Since every character will have a name and a level, it makes sense for each new character The this keyword will refer to the new instance that is created, so setting this.name to the name parameter ensures the new object will have a name property set.

我们创建了一个名为Hero的构造函数,它带有两个参数:name和level。 由于每个字符都有一个名称和一个级别,因此对于每个新字符都有意义。此关键字将引用创建的新实例,因此将this.name设置为name参数可确保新对象具有name属性集。

Now we can create a new instance with new.

现在,我们可以使用new创建一个新实例。

let hero1 = new Hero(‘Bjorn’, 1)

If we console out hero1, we will see a new object has been created with the new properties set as expected.

如果我们调出hero1,我们将看到已经按照预期设置了新属性的情况下创建了一个新对象。

Hero{name: "Bjorn", level:1}

Now if we get the [[Prototype]] of hero1, we will be able to see the constructor as Hero(). (remember, thi has the same input as hero1.__proto__, but is the proper method to use.)

现在,如果获得hero1的[[Prototype]],我们将能够看到构造函数为Hero()。 (请记住,此输入与hero1 .__ proto__相同,但这是使用的正确方法。)

Object.getPrototypeOF(hero1)//constructor: ƒ Hero(name, level)

You may notice that we’ve only defined properties and not methods in the constructor. It is a common practice in JavaScript to define methods on the prototype for increases efficiency and code readability.

您可能会注意到,我们仅在构造函数中定义了属性,而没有定义方法。 在JavaScript中,通常的做法是在原型上定义方法以提高效率和代码可读性。

We can add method to Hero using prototype. We’ll create a greet() method.

我们可以使用原型向Hero添加方法。 我们将创建一个greet()方法。

//Add greet method to the Herp prototype
Hero.prototype.greet = function() {
return `${this.name} says hello.`;
}

Since greet() is in the prototype of Hero, and hero1 is an instance of Hero, the method is available to hero1.

由于greet()在Hero的原型中,而hero1是Hero的实例,因此该方法可用于hero1。

hero1.greet()//"Bjorn says hello."

If you inspect [[Prototype]] of Hero, you will see greet() as an available option now.

如果检查Hero的[[Prototype]],现在将把greet()作为可用选项。

This is good, but now we want to create character classes for the heroes to use. It wouldn’t make sense to put all the abilities for every class into Hero constructor, because different classes will have different abilities. We want to create new constructor functions, but we also want them to be connected to the original Hero.

很好,但是现在我们要创建角色类供英雄使用。 将每个类的所有功能都放入Hero构造函数中是没有意义的,因为不同的类将具有不同的功能。 我们想要创建新的构造函数,但我们也希望将它们连接到原始Hero。

We can use the call() method to copy over properties from one constructor into another constructor. Let’s create a Warrior and a Healer constructor.

我们可以使用call()方法将属性从一个构造函数复制到另一个构造函数。 让我们创建一个Warrior和Healer构造函数。

//Intialize Warrior constructor 
function Warrior(name, level, weapon){
//Chain constructor with call
Hero.call(this, name, level) //Add a new property
this.weapon = weapon;
}//Initialize Healer constructor
function Healer(name, level, spell){
Hero.call(this, name, level)
this.spell = spell
}

Both new constructors now have the properties of Hero and a few unique ones. We’ll add the attack() method to Warrior, and the heal() method to Healer.

这两个新的构造函数现在都具有Hero属性和一些独特的属性。 我们将Attack()方法添加到Warrior,将heal()方法添加到Healer。

Warrior.prototype.attack = function(){
return `${this.name} attacks with the ${this.weapon}.`
}Healer.prototype.heal = function() {
return `${this.name} casts ${this.spell}.`
}

At this point, we’ll create our characters with the two new character classes available.

此时,我们将使用两个可用的新字符类来创建字符。

const hero1 = new Warrior('Bjorn', 1, 'axe')
const hero2 = new Healer('Kanin', 1, 'cure')

hero1 is now recognized as a Warrior with the new properties.

现在使用新属性将hero1确认为“战士”。

Warrior {name: "Bjorn", level: 1, weapon: "axe"}

We can use the new methods we set on the Warrior prototype.

我们可以使用在Warrior原型上设置的新方法。

hero1.attack();//Bjorn attacks with the axe

But what happens if we try use methods further down the prototype chain?

但是,如果我们尝试在原型链的更深处使用方法,会发生什么?

hero1.greet()//Uncaught TypeError: hero1.greet is not a function

Prototype properties and methods are not automatically linked when you use call() to chain constructors. We will use Object.create() to link the prototypes, making sure to put it before any additional methods are created and added to the prototype.

当您使用call()链接构造函数时,原型属性和方法不会自动链接。 我们将使用Object.create()链接原型,确保在创建任何其他方法并将其添加到原型之前将其放置。

Warrior.prototype = Object.create(Hero.prototype)
Healer.prototype = Object.create(Hero.prototype)

Now we can successfully use the prototype methods from Hero on an instance of a Warrior or Healer.

现在,我们可以在Warrior或Healer实例上成功使用Hero中的原型方法。

hero1.greet()//"Bjorn say hellp"

Hero is the full code

英雄是完整的代码

//Initialize constructor functions 
function Hero(name, level){
this.name = name;
this.level = level;
}function Warrior(name, level, weapon){
Hero.call(this, name, level)
this.weapon = weapon
}function Healer(name, level, spell){
Hero.call(this, name, level)
this.spell
}//Link prototypes and add prototype methods
Warrior.prototype = Object.create(hero.prototype)
Healer.prototype = Object.create(Hero.prototype)Hero.prototype.greet = () => {
return `${this.name} says hello`
}Warrior.prototype.attack = () => {
return `${this.name} attacks with the ${this.weapon}.`
}Healer.prototype.heal = () => {
return `${this.name} casts ${this.spell}.`
}//Initialize individual character instances
const hero1 = new Warrior('Bjorn', 1, 'axe')
const hero2 = new Healer('Kanin', 1, 'cure')

With this code we’ve created our Hero class with base properties, created two character classes called Warrior and Healer from the original constructor, added methods to the prototypes and created individual character instances.

使用此代码,我们创建了具有基本属性的Hero类,从原始构造函数创建了两个称为Warrior和Healer的字符类,向原型添加了方法,并创建了单个字符实例。

翻译自: https://medium.com/@kudzanayi/js-prototypes-and-inheritance-cd0c96799d5b

js原型继承和构造继承

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值