2016 - 2024

感恩一路有你

js创建对象的方法及其优缺点 JavaScript是面向对象还是基于对象?

浏览量:1081 时间:2023-07-08 08:27:56 作者:采采

JavaScript是面向对象还是基于对象?

什么是面向对象在编程的世界里,有一种思想非常重要,那就是面向对象的思维。掌握了这个思路,就意味着你不再是一个程序员新手,开始向开发者的目标迈进了。

那么,到底什么是面向对象的思维呢?说到这,我可以告诉你这个东西的来历。以前的编程是面向过程的。那么什么是面向过程的呢?之前在网上看到一句话,觉得形容的很好。让我借一下。

一般来说,如果现在有人让你把大象放进冰箱,我们如何用面向过程的方法来做?我们可以把它分成以下几个步骤:

1.打开冰箱门。

2.把大象放进冰箱。

3.关上冰箱门。

我们程序员会把这三个步骤写成三个函数:

()

2.putElephantIntoFridge()

()

然后我们可以依次调用这些函数。嗯,你以为可以下班了,但是过几天,你会发现这种需求会演变成很多奇怪的趋势,比如:

请把狮子放进冰箱。

请把大象放进微波炉里。

请把猴子放在微波炉里。

把其他动物放在冰箱里,但是不要放。;不要关门。

5.……

诸如此类。这时,要以面向过程的实现这些需求,就需要重新定义实现这些需求的功能。这无疑是一件令人抓狂的事情。但是老板和客户出钱了,你就得做!所以你必须加班,所以你牺牲了你的工作...

所以,为了你的生活,你必须想出一个方法,不。;不需要每次需要时都重新定义实现的功能,也就是说,面向对象。

我们的想法是:如果每次我们想改变需求,我们不要 不要自己去做这些过程,而是指导别人去做,不是吗?;没关系吗?所以我们面向对象思维的第一个转变就是做一个执行者,成为一个指挥者。

如果用定向思维来完成把大象放进冰箱的需求。我们的方法变成这样:

1.找到冰箱,命令冰箱自己打开冰箱门。

2.找到大象,命令它自己进入冰箱。

命令冰箱再次自行关门。

所以实现这个需求需要的实体是:大象和冰箱。我们把出现在实现需求中的实体称为对象。大象要能自己进入冰箱,冰箱要能自己开关门。进入冰箱、开门和关门的能力,我们称之为对象,通常用编程方法来表达。

所以总结一下:

1.面向过程是实现需求的第一步,任何工作都需要自己去做。

2.面向对象意味着把一切都交给能做的人。

所以现在的问题是,如果有必要,当求变变成上面说的那些,如何解决面向对象的问题?我们现在要做的是分析需求中出现的对象(实体),然后赋予它们相应的能力。

在新的需求中,大象、狮子和猴子应该被放进冰箱和微波炉。这时,这里出现的物体(实体)是:动物和容器。动物需要的方法(能力)是进入容器,容器需要的方法(能力)是开关门。

因此,上述所有要求都可能变成:

1.[集装箱]开门。

2.[动物]进入[容器]。

3.关闭[容器](或者如果需要关门,可以省略这一步)

所以这样一来,我们就不 不需要重复定义函数来实现这些需求。甚至在未来,需求变成了把动物从容器里拿出来,我们只要在动物物体上拓展把动物从容器里拿出来的方法,就可以快速完成需求。这个时候,你牺牲工作的几率就小多了。

如何实现面向对象

说了这么多,大家大概也能明白什么是面向对象了。那么如何用js写代码实现面向对象呢?

在JavaScript中,我们使用构造函数来创建对象。

函数大象(){

}

大象会有一些独特的数据,比如它的体重、品种、年龄等等。我们称这些独特的数据为:属性。每头大象 的数据就不一样了。这种差异在代码中是如何体现的?

功能象(年龄、体重、类型){

}

我们将每个数据作为形式参数传入构造函数,然后在创建时决定每个大象的实际数据。最终的构造函数被写成:

功能象(年龄、体重、类型){

年龄

这个重量重量

这种类型

}

现在,如果我们想要一头大象,我们只需要用new的创建这个对象。

//这是一头2岁重200kg的非洲象。

Var ele1新象(2,200kg,非洲象)

//这是一头3岁的美国大象,体重250kg。

Var ele2新象(3,250kg,美国象)

现在大象有了,我们应该教大象进入容器的能力。这是方法。主要的编写方法是将这些方法编写到构造函数中。

功能象(年龄、体重、类型){

年龄

这个重量重量

这种类型

this.enterContainer函数(){}}

大象造好了,接下来要做的就是把冰箱变成一个物体。我们还为冰箱写了一个构造函数。

功能冰箱(){

}

同样,冰箱这个对象也有其独特的属性(数据),比如冰箱的高度和宽度。我们还将这些属性写入构造函数。

功能冰箱(宽、高){

宽度宽度

这个高度高度

}

现在根据需求,冰箱应该有开关门的方法,我们也写在构造函数上。

功能冰箱(宽、高){

宽度宽度

这个高度高度

函数(){}

函数(){}

}

此时,我们需要下面的代码来完成 "把大象放进冰箱 "

// 1找一个冰箱物体,这个物体的宽度和高度足以把大象放进去。

var冰箱贴新款冰箱贴(4m,4m)

// 2给冰箱一个开门指令。

()

// 3找到一个大象对象。

Var大象新象(2,200kg,非洲象)

// 4给大象下达指令进入冰箱。

elephant.enterContainer()

// 5向冰箱发出关闭指令。

()

但是这个时候,我们要实现把狮子放进冰箱的需求,就要写一段代码,描述狮子的属性和方法。而这个代码几乎和描述大象的代码一模一样。

功能狮子(年龄、体重、类型){

年龄

这个重量重量

这种类型

this.enterContainer函数(){}

}

这时我们分析,无论大象、狮子、猴子的属性(年龄、体重、各种类型)和方法(进入容器)是否相同,这些都是我们需要的动物,所以让 让我们直接写一个描述动物的代码。

功能动物(年龄、体重、类型){

年龄

这个重量重量

这种类型

this.enterContainer函数(){}

}

当我们想把大象放进冰箱时:

Var ele新动物(2,250kg,非洲象)

ele.enterContainer()

当我们想把狮子放进冰箱时:

定义变量狮子新动物(2250公斤,美洲狮)

lion.enterContainer()

此时,不需要重复编写代码来达到类似的要求。但这时有同学想说,动物中猴子会爬树,大象会 如果要求猴子爬树,can 为什么我们不在动物构造器中增加一个爬树的方法呢?这显然是合理的!

当然不是!在解决这个同学之前 的问题,让 让我们做个总结。只是为了解决我们国家把动物放进冰箱的问题,我们把面向过程的方法改成了面向对象的方法。我们在上面的代码中只使用了面向对象思想的第一个特性:封装。所谓封装,就是把对象(需求中的实体)的属性(特征)和方法(能力)抽象出来,形成一个又一个的分类。在js中,es6之前没有类的概念,所以我们用构造函数来表示每个分类。抽象对象,只要你想用,就用构造函数里的new操作,新建一个。

继承

接下来解决猴子爬树的问题。当然,要解决这个问题,我们需要利用面向对象思维的另一个特性:继承。继承意味着子类可以享受父类的属性和方法(从这里开始不再解释类似的属性基本概念)。那么什么是子类和超类呢?为了解决把动物放入冰箱的问题,我们定义了一个动物构造器,我们理解为父类,然后提出这个问题:不是所有的动物都有相同的方法。猴子会爬树,但大象会。;t .这个时候我们需要重新定义猴子的构造函数。我们把这种猴子理解为一个子类。

功能猴(年龄、体重、类型){

年龄

这个重量重量

这种类型

函数(){}

this.enterContain:原型。让 ■首先在控制台中输出一个构造函数:

console.dir(数组)

此时,在控制台中,我们可以看到数组构造函数有一个prototype属性。这个属性就是我们所说的原型。

通过扩展这个原型属性,我们发现通常使用的数组的方法都是从这个原型派生出来的。换句话说,原型方法可以由实例对象共享。

然后我们会用原型来解决猴子代码重复太多的问题。我们发现动物构造函数和猴子构造函数都需要一个函数来进入enterContainer。为了去掉这个重复的代码,我们在Animal这个相当父类的构造函数中声明,将Monkey的原型指向Animal的一个实例。

功能动物(年龄、体重、类型){

年龄

这个重量重量

这种类型

this.enterContainer函数(){

Console.log(进入容器)

}

}

功能猴(年龄、体重、类型){

年龄

这个重量重量

这种类型

函数(){}

}

新动物()

此时,我们新建了一个Monkey实例,并发现这个实例可以调用容器方法。

Var猴新猴(2,25kg,金丝猴)

monkey.enterContainer()

此时,进入容器的方法enterContainer就可以共享了。然而,这种写作有一个缺点。我们写的方法都是写在构造函数里的,每次新建对象都会在内存里声明一个函数,而且这个函数的代码每次都是一样的。这是非常不必要的。

Var m1新款猴子(1,15kg,长臂猴子)

Var m2新猴(2,25kg,猕猴)

console.log(m1,m2)

我们模仿原生js的,在原型上写方法来解决这个问题。

功能动物(年龄、体重、类型){

年龄

这个重量重量

这种类型

}

函数(){

Console.log(进入容器)

}功能猴(年龄、体重、类型){

年龄

这个重量重量

这种类型

}

新动物()

函数(){

Console.log(小猴子正在爬树)

}

首先从内存分析,对象上没有对象方法。

然后从控制台观察。

Var m1新款猴子(1,15kg,长臂猴子)

Var m2新猴(2,25kg,猕猴)

console.log(m1,m2)

()

()

这是因为我们在原型上写方法,原型上的方法可以被实例共享。M1和m2都是猴子的实例,可以调用爬树的方法。

利用构造函数实现属性继承

到目前为止,我们已经解决了一些代码的重用问题。我们发现有些代码还是重复的,这部分代码是对象的属性。

在js中,我们可以使用借用构造函数来实现属性的继承。

什么是借款?这其实是一个所有函数都可以调用的方法:call方法。另一个功能是在函数执行时修改这个点。举个简单的例子:

函数fn(){

console.log(this)

}

fn()

这段代码在正常情况下的结果是输出窗口对象。

但是如果我们用借用的方法:

函数fn(){

consol:小明})

控制台中的输出是:我们正在使用call方法的第一个参数。利用这个特性,我们可以借用构造函数。

具体代码如下

功能动物(年龄、体重、类型){

年龄

这个重量重量

这种类型

}

功能猴(年龄、体重、类型){

(这个,年龄,体重,类型)

}

至此,Monkey中重复的属性代码没有了。那么让我们 让我们试试Monkey的一个实例是否会有这些属性。

Var m1新款猴子(1,15kg,长臂猴子)

Var m2新猴(2,25kg,猕猴)

console.log(m1,m2)

所以最后,我们的代码是这样写的

功能动物(年龄、体重、类型){

年龄

这.魏重量轻

这种类型

}

函数(){

Console.log(进入容器)

}

功能猴(年龄、体重、类型){

(这个,年龄,体重,类型)

}

新动物()

函数(){

Console.log(小猴子正在爬树)

}

这个时候,如果是所有动物的方法,我们只需要回到世间。如果是猴子 我们将把它写在世界上。这就是js中实现定向的过程。我们把以上两种实现继承的称为:组合继承。

更简单的语法实现面向对象

上面写的是我们在es5标准下的面向对象过程。这个过程有点麻烦。在es6的新标准下,我们有了更简单的语法来实现面向对象。

类别关键字

首先,让我们 让我们理解es6中的一个新关键字:class,它允许我们快速定义类。语法如下:

类别类别名称{

}

然后在里面写这个类的构造函数。

类别类别名称{

构造函数(){

}

}

例如,我们定义一个动物类。

动物类{

建造者(年龄、体重、类型){

年龄

这个重量重量

这种类型

}

}

当我想要一个动物实例时,我只需要新的。

Var a1新动物(2,200kg,非洲象)

console.log(a1)

这个语法的本质也是利用函数和原型来实现的,所以我想实现前面的动物和冰箱的问题,如果在这个新的语法中实现会更快。

扩展关键字

在新语法的情况下,如果我们想实现继承,我们只需要使用一个新的关键字 "扩展 "。语法如下:

类子类扩展父类{

构造函数(){}

}

但重要的是,在这种新语法下实现的继承,必须先在子类的构造函数中调用父类的构造函数。

类子类扩展父类{

构造函数(){

超级()

}

}

所以现在要认识到Mokey 从动物的遗传,我们不得不这样写。

动物类{

建造者(年龄、体重、类型){

年龄

这个重量重量

这种类型

}

enterContainer(){

Console.log(进入容器)

}

}

类Mokey扩展动物{

建造者(年龄、体重、类型){

超级(年龄、体重、类型)

}

climbingTree(){

Consol

javascript怎么实现像其他语言一样,一个类一个文件?应该注意哪些问题?

我不 不知道有没有学过java,就每个类写一个文件,单独介绍一下。建议看看JavaScript面向对象编程。网上有很多专门介绍的文章,很全面,所以我赢了 不要在这里张贴代码。

方法 动物 构造函数 代码 冰箱

版权声明:本文内容由互联网用户自发贡献,本站不承担相关法律责任.如有侵权/违法内容,本站将立刻删除。