javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

2023-08-21 0 4,971 百度已收录

序言

当你想到JavaScript时,你不得不提到艰难的原型链。近年来,对于JSers,我认为很少有人真正使用原型进行编程。为什么?由于JavaScript充满了对象javascript面向对象编程指南,因此面向对象的设计自然而然地与它一起工作。大流行库,如 React,包含面向对象的设计思想。

自从 ES6 “class” 语法糖的出现,以及 Typescript 的一些改进的句型(如公共、私有关键字)以来,它已经为我们蒙上了一层面纱,明天我们将揭开这层面纱,和大家谈谈 JavaScript 的面向对象设计,以及另一个替代编程模型——行为委托模型。

过程编程

VS 面向对象编程面向过程编程

在 C 这样的语言中,没有类和对象的概念,完成一个函数的重复代码块可以定义为函数,在头文件中可以声明具有一类函数的函数,可以在不同的头文件中声明不同类型的函数,方便更好的管理和调用函数。

之所以叫面向过程编程,是因为编程的过程是一个循序渐进的函数调用过程,而C语言有一个main函数,main函数调用其他函数就是这样实现程序函数的。

面向对象编程

因为Java、C++等语言都支持类和对象,所以用这种语言编程也叫面向对象编程,这种语言又叫面向对象编程语言。我们可以使用类来创建和维护对象来组织此数据结构。在Java中,完成一个功能的代码

块可以定义为一种方式,具有类似功能的方法可以在一个类中定义,即在源文件中(因为源文件只能包含一个公共类),多个源文件可以位于一个文件夹中,该文件夹具有特定的敬称, 称为包。

面向对象编程在软件执行效率方面绝对没有优势,其主要目的是方便程序员组织和管理代码,快速梳理编程思路,带来编程思想的创新。面向

对象编程是指“封装”、“继承”和“多态性”,这两者都被称为面向对象的三个特征。

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

数据和与数据相关的操作被打包到对象(严格来说“类”)中,每个对象都是相对完整和独立的。对象可以有派生类型(继承),派生类型可以覆盖(或重载)现有操作(多态),从而实现更好的内聚,即一个对象做了一件好事(或一类相关)的事情,对象内部的细节不被外界关心或看到(封装)。并减少耦合,即不同种类物体的相互依赖性尽可能低。所有这些都有助于实现一个崇高的目标,即可重用性。

类是结构体的升级

类可以被认为是结构体的升级,因为C语言的长辈们听说了结构体的缺点,试图改进它们,继承了结构体的思想,并对其进行了升级,以使程序员更容易开发或扩展大大小小的项目。

让我们看一下结构和类。

结构是一种构造的数据类型,可以包含不同的成员(变量),每个成员的数据类型可以不同;结构变量可以由结构定义,每个结构都具有相同的属性。C 代码如下所示:

#include  
int main(){
    // 定义结构体 Student 
    struct Student {
        // 结构体包含的变量 
        char *name;
        int age;
        float score;
    };
    // 通过结构体来定义变量
    struct Student stu1;
    // 操作结构体的成员
    stu1.name = "小明";
    stu1.age = 15;
    stu1.score = 92.5;
    // 运行结果:小明的年龄是 15,成绩是 92.500000
    printf("%s的年龄是 %d,成绩是 %fn", stu1.name, stu1.age, stu1.score); 
    return 0;
}

Java 中的类也是一种构造数据类型,通过一些扩展,类的成员不仅可以是变量,还可以是函数,例如 Student 定义:

// 通过class关键字类定义类
pubic class Student { 
    // 类包含的变量
    String name; 
    int age; 
    float score; 
    // 类包含的函数 
    void say() {
        System.out.println(name + "的年龄是 " + age + ",成绩是 " + score);
    }
}

通过类定义的变量也具有特定的敬语标题,称为“对象”。根据学生测试类的定义:

public class StudentTest {
    public static void main(String[] args) {
        Student stu1 = new Student(); // 必须使用new关键字 
        stu1.name = "小明";
        stu1.age = 15;
        stu1.score = 92.5f;
        stu1.say(); // 运行结果:小明的年龄是 15,成绩是 92.500000
    }
}

在C语言中,可以通过结构名完成结构变量的定义,并可以分配内存空间;而在 Java 中,仅仅通过类定义变量是不分配内存空间的,必须使用 new 关键字来完成内存空间的分配。

JavaScript 实现面向对象编程

介绍原始概念,让我们来看看 JavaScript 是如何进行面向对象编程的。

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

ES6 曾经

在 ES6 中,没有“类”的概念,但 JavaScript 充满了对象,这些对象通过原型链接在一起。聪明的JSers想出了很多方法来进行面向对象编程。下面来看看 JavaScript 如何实现三个面向对象的特性:“封装”、“继承”和“多态性”。

封装的实现

我们知道 JavaScript 对象上的属性是可访问的,因此没有“私有”的概念。当我们查看一些开源代码时,我们会发现一些属性名称带有 ton 符号来表示它是“私有的”,但这并不安全,而且这些表示是基于社区约定,而不是 JavaScript 规范。

那么 ES6 的原始 JavaScript 是如何实现真正的私有属性的呢?使用闭合!

function Person(name) {
    let _name = name;
    this.getName = function() {
        return 'My name is ' + _name;
    }
}
var p = new Person('tianzhich');
console.log(p.getName()); // My name is tianzhich

实施继承

JS继承对象有很多种方式,我们来看看最常用的,也是比较完美的继承,小红书叫:寄生组合继承(Parasitic Combined Inheritance)。

我们先拆解一下概念:组合继承和寄生继承。

组合继承

是纯粹的原型链继承和借用的构造函数继承。纯原型链继承是指泛型原型指向父类的实例对象;另一方面,借用构造函数继承是指对父类的构造函数进行泛型借用以创建对象。为此javascript面向对象编程指南,不难发现组合继承具有以下缺点:父类

的构造函数被调用两次,泛型原型对象包含父类实例对象的所有属性,我们在必要时重新绘制

让我们看看寄生遗传。寄生继承仅用于继承单个对象文本,而不用于继承构造函数。这个想法是使用鞋厂函数来封装继承过程。在函数中使用 Object.create(parent) 创建一个通用对象并向其添加一些唯一属性。他有以下缺点:

它仅用于继承单个对象文字,每次创建新的泛型对象并调用鞋厂函数时,都不会完成函数重用

最后,将它们组合以实现寄生组合:

// 寄生式继承优点:工厂函数封装继承过程
// 同时避免组合式继承缺点:只继承prototype而不是实例
function inherit(subType, superType) {
    var prototype = Object.create(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
function Person(name) {
    this.name = name;
}
Person.prototype.showName = function() {
    return this.name;
}
function Boy(name, age) {
    // 组合式继承优点:借用构造函数
    Person.call(this, name);
    this.age = age;
}
inherit(Boy, SuperType);
// 避免寄生式继承缺点:避免函数重复声明
Boy.prototype.showAge = function() {
    return this.age
}

多态性的实现

根据我们的概念,多态性是派生类型可以重写(或重载)原始类型的方式。对于覆盖方法,实现起来是很好的,因为通过原型链,底层派生对象属性可以“屏蔽”高级属性以实现覆盖。而且 JavaScript 不支持重载,所以我们需要另外实现它:

// 还是使用上面的例子,我们增加一个sayHi的方法
Person.prototype.sayHi = function() {
    console.log('Hi, ' + 'my name is ' + this.name);
}
// 在子类中"重载"这个方法,增加参数toPerson和参数showAge
Boy.prototype.sayHi = function(toPerson, showAge) {
    if (toPerson) {
        console.log('Hi, ' + toPerson.showName() + 'my name is ' + this.name + showAge ? (' and I am ' + this.age + ' years old') : '');
    } else {
        // 伪多态
        Person.sayHi.call(this);
        if (showAge) {
            console.log('and I am ' + this.age + 'years old');
        }
    }
}

如您所见,要实现复杂的“重载”方法,我们需要做一些额外的参数判别。同时,如果在泛型中调用父类模式,则只能显式调用,这是一种伪多态性。在“类”句子糖中,我们可以看到一个相对多态性,使用超级关键字。

ES6 “类”句法糖

让我们从定义开始:

JavaScriptclasses,在ECMAScript2015中引入,主要是syntacticalsugaroverJavaScript'sexistingprototype-basedinheritance。Theclasssyntaxnotintroduceanewobject-oriented inheritancemodeltoJavaScript.

类是事实上的“特殊函数”,和justasyoucandefinefunctionexpressionsandfunctiondeclarations,theclasssyntaxhastwocomponents:classexpressionsandclassdeclarations。

可以了解到,“类”只是 ES6 引入的一句话糖,它的本质还是我们之前介绍的基于原型的继承实现,并没有引入新的面向对象继承模型。同时,Class 是一个特殊的函数,函数“class”声明和“class”表达式也有两种使用方式。但是值得注意的是,类声明并没有改进,无论是声明还是表达式,以后都要用到,否则会报错:ReferenceError。

然后我们使用“class”来实现上面描述的继承模型:

class Person {
    constructor(name) {
        this.name = name;
    }
    showName() {
        return this.name;
    }
    sayHi() {
        console.log('Hi, ' + 'my name is ' + this.name);
    }
}
class Boy extends Person {
    constructor(name, age) {
        super(name);
        this.age = age;
    }
    showAge() {
        return this.age;
    }
    sayHi(toPerson, showAge) {
        if (toPerson == undefined && showAge == undefined) {
            super.sayHi();
        } else if (toPerson) {
            console.log('Hi, ' + toPerson.showName() + 'my name is ' + this.name + showAge ? (' and I am ' + this.age + ' years old') : '');
        } else {
            super.sayHi();
            console.log('and I am ' + this.age + 'years old');
        }
    }
}

这里的例子没有提到封装,其实以后我们可能会在类的属性和技巧名前加上“#”,以表明属性或方法是私有的。该法案目前处于第三阶段。

如果使用 Typescript,则可以使用公共和私有关键字来实现与 Java 相同的目的。

“类”语法糖封装了我们很多,尽管本质上是原型。我们能用更崇高的句型来实现它吗?

JavaScript 是一种面向对象的编程语言吗?

这个问题显然不好问,我们先参考一下:

JavaScriptcanfunctionasbothaproceduralandanobjectoriented language.ObjectsarecreatedprogrammatallyinJavaScript, byattachingmethodsandpropertiestoelseemptyobjectsatruntime,asopposedtothesyntacticclassdefinitionscommonincompiledlanguageslikeC++andJava.Onceanobjecthasbeenconstructeditcanbeusedasablueprint(orprototype)forcreateatingsimilarobjects.

我们已经了解到JavaScript支持面向对象和面向过程的设计。我认为这取决于你如何使用函数,如果你使用构造函数来创建对象,你可以实现面向对象的设计;如果你像C一样编写函数调用,你可以实现面向过程的设计。

JavaScript 是一种灵活的语言,可以动态添加属性以及对象如何运行程序,也可以用作创建多个对象的新蓝图。我们还应该意识到这与C++和Java不同,后者提供“类”语法支持,一旦定义了类,就很难动态修改。

可以说,如果你理解了JavaScript实现面向对象设计的本质,你可以把它看作是一种面向对象的语言。而如果你不理解它的本质,只是认为他有“类”的概念,认为他是一个面向对象的语言,我认为这还不够。

行为委派模式

看完 JavaScript 实现继承,我们也明白它的本质是一个原型链。那么,我们为什么要如此执着,必须使用继承呢?上面我们提到寄生继承提到了 ObjectLiteral,即直接创建一个 JavaScript 对象。我们可以直接基于普通对象设计和开发编程吗?

下面我将提供一个设计模式,让你达到与以前相同的功效,称为BehaviorDelegate,来自YouDon'tKnowJS:this和ObjectPrototypes。

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

var Person = {
    setName: function(name) {
        this.name = name;
    },
    showName: function() {
        return this.name;
    },
    sayHi: function() {
        console.log('Hi, ' + 'my name is ' + this.name);
    }
}
var Boy = Object.create(Person);
Boy.init = function(name, age) {
    this.setName(name);
    this.age = age;
}
Boy.showAge = function() {
    return this.age;
}
Boy.sayHiToPerson = function(toPerson, showAge) {
    console.log('Hi, ' + toPerson.showName() + 'my name is ' + this.name + showAge ? (' and I am ' + this.age + ' years old') : '');
}
Boy.sayHiWithAge = function() {
    this.sayHi();
    console.log('and I am ' + this.age + 'years old');
}

行为委托模式具有以下特征(请注意,我在这里使用术语底层和顶层,而不是泛型和父类):

指示的编码方法是“委托”,这是一种OLOO(ObjectLinktoOtherObject)形式,它是实现这些连接的原型链。底层想要实现一个功能,可以直接在底层“委托”顶层帮助实现数据属性,顶层只是“委托”赋值的方式,属性委托模式建议使用更准确的命名方式,但为了避免底层的方式“覆盖”顶层的方式, 这两种方法不能具有相同的名称。所以这里不用多态性,越来越精确的命名也有助于开发者理解代码有意委托模式来指出直接使用对象文字,所以函数闭包不能用来实现真正的“私有”属性,只能依靠社区约定,也就是我们在其中使用的 ton 形式, 如:_variable这些模式

看起来很难实现面向对象的三个特征,但是很多时候,非常多的 ES6 已经,我们真的不需要实现复杂的继承,我们可以使用行为委托来设计和编码,但是这些模式可以让你越来越深入地理解 JavaScript 强大的原型生态。您还可以在设计阶段更好地定义代码。

最后,我们来看看两者原型链结构的对比:

“类”继承

行为委派

是不是简单多了?

总结

正如我们所说,一些软件设计和想法在软件执行效率方面可能没有优势。而对于软件开发者而不是机器来说,我们需要做的是在开发阶段快速梳理出编程思路,同时考虑代码的维护成本。这样,选择你喜欢的开发模式并编码!

见你不知道JS-1st版

JavaScript有几种简单的方法来定义对象

1.构造函数形式,对象的所有属性和方式都定义在构造函数之上

优点:动态传递参数

缺点:每个创建的对象都会以相同的方式创建一个函数对象,占用大量视频内存

function User1(name, password) {
	this.name = name;
	this.password = password;
	this.login = function(name,password){
		if(this.name == name && this.password == password) {
			return true;
		}else {
			return false;
		}
	};
}

2.原型方法,在对象的原型上编写对象属性和方法定义

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

优点:每次创建对象时,在原型中使用相同的方法,不占用重复的视频内存

缺点:无法动态传递构造参数

function User2() {
}
User2.prototype.name = "prototype name";
User2.prototype.password = "prototype password";
User2.prototype.login = function(name,password){
	if(this.name == name && this.password == password) {
		return true;
	} else {
		return false;
	}
};

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

3.构造和原型混合方法,在构造函数上编写属性定义javascript定义对象,在原型上编写方法

优点:结合构造和原型方法的优点,可以动态传递构造参数,并且只创建单向函数对象

缺点:函数写在对象之外javascript定义对象,不太符合面向对象的思想

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

function User3(name,password) {
	this.name = name;
	this.password = password;
}
User3.prototype.login = function(name,password) {
	if(this.name == name && this.password == password) {
		return true;
	} else {
		return false;
	}
};

4.动态原型方法:添加判别属性,判断对象是否已经创建,如果已经创建,则方式不成立

优点:在对象定义之上编写原型函数

javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗?

缺点: 不支持继承

function User4(name,password) {
	this.name = name;
	this.password = password;
	if(typeof User4.__initialized == "undefined") {
		User4.prototype.login = function(name,password){
			if(this.name == name && this.password == password) {
				return true;
			} else {
				return false;
			}
		};
		User4.__initialized = true;
	}
}

在 JavaScript 中定义对象的主要方法是以上四种,可以满足大部分需求。希望这对JavaScript的初学者有所帮助。同时,附件包含简单的示例,供初学者直接运行。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 javascript javascript面向对象编程指南-JavaScript 面向对象,你真的明白吗?我必须使用“类”来编程吗? https://www.wkzy.net/game/129689.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务