JavaScript中的面向对象编程–举例说明

JavaScript is not a class-based object-oriented language. But it still has ways of using object oriented programming (OOP).

JavaScript不是基于类的面向对象语言。 但是它仍然具有使用面向对象编程(OOP)的方式。

In this tutorial, I'll explain OOP and show you how to use it.

在本教程中,我将解释OOP并向您展示如何使用它。

According to Wikipedia, class-based programming is

根据维基百科 ,基于类的编程是

a style of Object-oriented programming (OOP) in which inheritance occurs via defining classes of objects, instead of inheritance occurring via the objects alone

一种面向对象编程(OOP)的方式,其中继承是通过定义对象的类发生的,而不是继承是仅通过对象发生的

The most popular model of OOP is class-based.

OOP最受欢迎的模型是基于类的。

But as I mentioned, JavaScript isn't a classed-based langauge – it's is a prototype-based langauge.

但是正如我提到的那样,JavaScript不是基于分类的语言,而是基于原型的语言。

According to Mozilla's documentaion:

根据Mozilla的文档:

A prototype-based language has the notion of a prototypical object, an object used as a template from which to get the initial properties for a new object.

基于原型的语言具有原型对象的概念,该对象用作模板,从模板获取新对象的初始属性。

Take a look at this code:

看一下这段代码:

let names = {
    fname: "Dillion",
    lname: "Megida"
}
console.log(names.fname);
console.log(names.hasOwnProperty("mname"));
// Expected Output
// Dillion
// false

The object variable names has only two properties - fname and lname . No methods at all.

对象变量names只有两个属性fnamelname 。 根本没有方法。

So where does hasOwnProperty come from?

那么hasOwnProperty是从哪里来的呢?

Well, it comes from the Object prototype.

好吧,它来自Object原型。

Try logging the contents of the variable to the console:

尝试将变量的内容记录到控制台:

console.log(names);

When you expand the results in the console, you'll get this:

在控制台中扩展结果时,将得到以下信息:

Notice the last property - __proto__? Try expanding it:

注意最后一个属性__proto__吗? 尝试扩展它:

You'll see a set of properties under the Object constructor. All these properties are coming from the global Object prototype. If you look closely, you'll also notice our hidden hasOwnProperty .

您将在Object构造函数下看到一组属性。 所有这些属性都来自全局Object原型。 如果仔细观察,您还会注意到我们隐藏的hasOwnProperty

In other words, all objects have access to the Object's prototype. They do not possess these properties, but are granted access to the properties in the prototype.

换句话说,所有对象都可以访问Object的原型。 它们不具有这些属性,但是被授予对原型中属性的访问权限。

__proto__属性 (The __proto__ property)

This points to the object which is used as a prototype.

这指向用作原型的对象。

This is the property on every object that gives it access to the Object prototype property.

这是每个对象上的属性,使它可以访问Object prototype属性。

Every object has this property by default, which refers to the Object Protoype except when configured otherwise (that is, when the object's __proto__ is pointed to another prototype).

默认情况下,每个对象都具有此属性,该属性引用Object Protoype除非另有配置(即,对象的__proto__指向另一个原型时)。

修改__proto__属性 (Modifying the __proto__ property)

This property can be modified by explicitly stating that it should refer to another prototype. The following methods are used to achieve this:

可以通过明确声明应引用另一个原型来修改此属性。 使用以下方法来实现此目的:

Object.create() (Object.create())

function DogObject(name, age) {
    let dog = Object.create(constructorObject);
    dog.name = name;
    dog.age = age;
    return dog;
}
let constructorObject = {
    speak: function(){
        return "I am a dog"
    }
}
let bingo = DogObject("Bingo", 54);
console.log(bingo);

In the console, this is what you'd have:

在控制台中,这就是您所拥有的:

Notice the __proto__ property and the speak method?

注意__proto__属性和speak方法吗?

Object.create uses the argument passed to it to become the prototype.

Object.create使用传递给它的参数成为原型。

new关键字 (new keyword)

function DogObject(name, age) {
    this.name = name;
    this.age = age;
}
DogObject.prototype.speak = function() {
    return "I am a dog";
}
let john = new DogObject("John", 45);

john's __proto__ property is directed to DogObject's prototype. But remember, DogObject's prototype is an object (key and value pair), hence it also has a __proto__ property which refers to the global Object protoype.

john__proto__属性指向DogObject的原型。 但是请记住, DogObject的原型是一个对象( 键和值对 ),因此它还具有__proto__属性,该属性引用全局Object原型。

This technique is referred to as PROTOTYPE CHAINING.

该技术称为原型链

Note that: the new keyword approach does the same thing as Object.create() but only makes it easier as it does some things automatically for you.

请注意: new关键字方法与Object.create()的功能相同,但由于它会自动为您执行某些操作,因此只会使其变得更容易。

所以... (And so...)

Every object in Javascript has access to the Object's prototype by default. If configured to use another prototype, say prototype2, then prototype2 would also have access to the Object's prototype by default, and so on.

默认情况下,Javascript中的每个对象都可以访问Object的原型。 如果配置为使用另一个原型(例如prototype2 ,则默认情况下prototype2也将有权访问Object的原型,依此类推。

对象+功能组合 (Object + Function Combination)

You are probably confused by the fact that DogObject is a function (function DogObject(){}) and it has properties accessed with a dot notation. This is referred to as a function object combination.

DogObject是一个函数( function DogObject(){} ),并且具有使用点符号访问的属性,这可能使您感到困惑。 这称为功能对象组合

When functions are declared, by default they are given a lot of properties attached to it. Remember that functions are also objects in JavaScript data types.

声明函数时,默认情况下会为它们提供很多附加属性。 请记住,函数也是JavaScript数据类型中的对象。

现在,上课 (Now, Class)

JavaScript introduced the class keyword in ECMAScript 2015. It makes JavaScript seem like an OOP language. But it is just syntatic sugar over the existing prototyping technique. It continues its prototyping in the background but makes the outer body look like OOP. We'll now look at how that's possible.

JavaScript在ECMAScript 2015中引入了class关键字。它使JavaScript看起来像是一种OOP语言。 但这只是现有原型技术上的合成糖。 它在后台继续其原型制作,但使外部主体看起来像OOP。 现在我们来看一下这是怎么可能的。

The following example is a general usage of a class in JavaScript:

以下示例是JavaScript中class的一般用法:

class Animals {
    constructor(name, specie) {
        this.name = name;
        this.specie = specie;
    }
    sing() {
        return `${this.name} can sing`;
    }
    dance() {
        return `${this.name} can dance`;
    }
}
let bingo = new Animals("Bingo", "Hairy");
console.log(bingo);

This is the result in the console:

这是控制台中的结果:

The __proto__ references the Animals prototype (which in turn references the Object prototype).

__proto__引用了Animals原型(后者又引用了Object原型)。

From this, we can see that the constructor defines the major features while everything outside the constructor (sing() and dance()) are the bonus features (prototypes).

由此可见,构造函数定义了主要功能,而构造函数之外的所有内容( sing()dance() )都是附加功能( 原型 )。

In the background, using the new keyword approach, the above translates to:

在后台,使用new关键字方法,以上内容转换为:

function Animals(name, specie) {
    this.name = name;
    this.specie = specie;
}
Animals.prototype.sing = function(){
    return `${this.name} can sing`;
}
Animals.prototype.dance = function() {
    return `${this.name} can dance`;
}
let Bingo = new Animals("Bingo", "Hairy");

子类化 (Subclassing)

This is a feature in OOP where a class inherits features from a parent class but possesses extra features which the parent doesn't.

这是OOP中的功能,其中类从父类继承功能,但拥有父不具备的其他功能。

The idea here is, for example, say you want to create a cats class. Instead of creating the class from scratch - stating the name, age and species property afresh, you'd inherit those properties from the parent animals class.

例如,这里的想法是说您要创建cats类。 您无需从头开始创建类-再次说明名称年龄物种属性,而是从父动物类继承这些属性。

This cats class can then have extra properties like color of whiskers.

然后,此类可以具有其他属性,例如晶须的颜色

Let's see how subclasses are done with class.

让我们看看class是如何完成子class

Here, we need a parent which the subclass inherits from. Examine the following code:

在这里,我们需要一个父类,该子类继承自该父类。 检查以下代码:

class Animals {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sing() {
        return `${this.name} can sing`;
    }
    dance() {
        return `${this.name} can dance`;
    }
} 
class Cats extends Animals {
    constructor(name, age, whiskerColor) {
        super(name, age);
        this.whiskerColor = whiskerColor;
    }
    whiskers() {
        return `I have ${this.whiskerColor} whiskers`;
    }
}
let clara = new Cats("Clara", 33, "indigo");

With the above, we get the following outputs:

通过以上操作,我们得到以下输出:

console.log(clara.sing());
console.log(clara.whiskers());
// Expected Output
// "Clara can sing"
// "I have indigo whiskers"

When you log the contents of clara out in the console, we have:

当您在控制台中注销clara的内容时,我们有:

You'll notice that clara has a __proto__ property which references the constructor Cats and gets access to the whiskers() method. This __proto__ property also has a __proto__ property which references the constructor Animals thereby getting access to sing() and dance(). name and age are properties that exist on every object created from this.

您会注意到clara具有__proto__属性,该属性引用构造函数Cats并可以访问whiskers()方法。 此__proto__属性还具有__proto__属性,该属性引用构造函数Animals从而可以访问sing()dance()nameage是在由此创建的每个对象上存在的属性。

Using the Object.create method approach, the above translates to:

使用Object.create方法,以上内容可转换为:

function Animals(name, age) {
    let newAnimal = Object.create(animalConstructor);
    newAnimal.name = name;
    newAnimal.age = age;
    return newAnimal;
}
let animalConstructor = {
    sing: function() {
        return `${this.name} can sing`;
    },
    dance: function() {
        return `${this.name} can dance`;
    }
}
function Cats(name, age, whiskerColor) {
    let newCat = Animals(name, age);
    Object.setPrototypeOf(newCat, catConstructor);
    newCat.whiskerColor = whiskerColor;
    return newCat;
}
let catConstructor = {
    whiskers() {
        return `I have ${this.whiskerColor} whiskers`;
    }
}
Object.setPrototypeOf(catConstructor, animalConstructor);
const clara = Cats("Clara", 33, "purple");
clara.sing();
clara.whiskers();
// Expected Output
// "Clara can sing"
// "I have purple whiskers"

Object.setPrototypeOf is a method which takes in two arguments - the object (first argument) and the desired prototype (second argument).

Object.setPrototypeOf是一个接受两个参数的方法-对象(第一个参数)和所需的原型(第二个参数)。

From the above, the Animals function returns an object with the animalConstructor as prototype. The Cats function returns an object with catConstructor as it's prototype. catConstructor on the other hand, is given a prototype of animalConstructor.

从上面的内容, Animals函数返回一个以animalConstructor作为原型的对象。 Cats函数返回带有catConstructor的对象作为原型。 catConstructor在另一方面,给出了一个原型的animalConstructor

Therefore, ordinary animals only have access to the animalConstructor but cats have access to the catConstructor and the animalConstructor.

因此,普通的动物只能访问animalConstructor而猫可以访问catConstructoranimalConstructor

结语 (Wrapping Up)

JavaScript leverages its prototype nature to welcome OOP developers to its ecosystem. It also provides easy ways to creating prototypes and organize related data.

JavaScript利用其原型性质来欢迎OOP开发人员加入其生态系统。 它还提供了创建原型和组织相关数据的简便方法。

True OOP languages do not perform prototyping in the background - just take note of that.

真正的OOP语言不会在后台执行原型制作-请注意。

A big thanks to Will Sentance's course on Frontend Masters - JavaScript: The Hard Parts of Object Oriented JavaScript. I learned everything you see in this article (plus a little extra research) from his course. You should check it out.

非常感谢Will Sentance开设的前端大师课程-JavaScript :面向对象JavaScript的硬性部分 。 我从他的课程中学到了您在本文中看到的所有内容(加上一些额外的研究)。 你应该检查一下。

You can hit me up on Twitter at iamdillion for any questions or contributions.

您可以在iamdillion上通过Twitter向提出任何问题或贡献。

Thanks for reading : )

谢谢阅读 : )

有用的资源 (Useful Resources)

翻译自: https://www.freecodecamp.org/news/how-javascript-implements-oop/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值