JavaScript面向对象编程(对象创建)

本文详细解析了JavaScript中面向对象编程的多种创建对象模式,包括工厂模式、构造函数模式、原型模式、组合构造函数模式和原型模式、寄生构造函数模式。重点阐述了各模式的特点、区别及应用场景,特别是如何通过构造函数和原型模式实现对象的创建、属性赋值、方法定义及共享,以及如何避免模式间的缺点。

前言

在学面向对象(objetct-oriented,oo)编程之前,首先需要知道什么是对象,ECMA-262,将对象定义为无序属性的集合,其属性可以包含基本值、对象或者是函数JavaScript中有多种方式来创建对象,比如:工厂模式、构造函数模式、原型模式、组合构造函数模式和原型模式、寄生构造函数模式等等。

一、工厂模式

工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程。考虑到在ECMAScript 中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节。

function createStudent(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var student1= createStudent("xiaoming", 9, "student");
var student2 = createStudent("xiaowagn", 15, "student");



函数createStudent()能够根据接受的参数来构建一个包含所有必要信息的Student对象。可以无数次地调用这个函,而每次它都会返回一个包含三个属性一个方法的对象。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。随着JavaScript的发展,又一个新模式出现了。

二、构造函数模式

首先我们将前面的代码修改如下:

function Student(name,age){
      this.name=name;
      this.age=age;
      this.showname=function(){
      alert(this.name);
      }
}
var xiaoming =new Student("xiaoming",6);
var xiaogang =new Student("xiaogang",7);


与工厂模式区别:

 1.没有显示创建对象

  2.直接将属性赋值给了this对象

  3.没有Return语句。

要创建一个实例,需要使用new操作符。

创建对象步骤:

1.创建一个新的对象

2.将构造函数的作用域赋给新的对象(this就指向这个新的对象)

3.执行构造函数的代码,为这个对象添加属性

4.返回这个对象

 

alert(xiaoming.constructor==Student) //true;

对象的constructor属性最初是用来标识一个对象的类型的。检查一个对象类型,还是使用instanceof

alert(xiaoming instanceof Student) //true

alert(xiaoming instanceof Object) //true是因为所有对象均继承自Object

 

创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型;而这正是构造函数模式胜过工厂模式的地方。使用构造函数也是有缺点的。就是每个方法都要在每个实例上重新创建一遍。比如,xiaomingxiaogang都有一个showname()方法。但是那两个方法不是同一个Function的实例。ECMAScript中的函数是对象,因此,每定义一个函数,就是实例化了一个对象。从逻辑角度讲,此时构造函数也可以这样定义。

function student(name,age){

this.name=name;

this.showName=new Function(“alert(this.name)”);

}

可以看出,每个Student实例都包含一个不同的Function 实例。不同的实例上的同名函数是不相等的。以下代码可以证明这一点。

alert(xiaoming.showName==xiaogang.showname);//false

二、构造函数模式

我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。如果按照字面意思来理解,那么prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。

function Student(){

 

}

Student.property.name=”default name”;

Student.property.age=0;

Student.property.showName=funciton(){

alert(this.name);

}

Var xiaoming=new Student();

Var xiaogang=new Student();

与构造函数模式的不同时,新对象的这些属性和方法是由所有的实例共享的。换句话说xiaoming和xiaogang访问的都是同一组属性和同一个showName()函数。要理解原型模式的工作原理,必须先理解ECMAScript 中原型对象的性质。

1. 理解原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype

属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor

(构造函数)属性,这个属性包含一个指向prototype 属性所在函数的指针。就拿前面的例子来说,

Student.prototype. constructor 指向Student。而通过这个构造函数,我们还可继续为原型对象添加其他属性和方法.

 

JS中我们通过isPropertyOf()来判断,某个实例是否指向某个函数的的原型。

Eg

Student.property.isPropertyOf(xiaoming);//true

ECMAScript5中含增加了Object.getPropertyOf()方法来获取一个实例的原型

Eg

alert(Object.getPropertyOf(xiaoming)==Student.property);//true

alert(Object.getPropertyOf(xiaoming).name);//default name

此外,我们还可以通过hasOwnProperty()方法来检测一个属性是存在实例中还是存在原型中。alert(xiaoming.hasOwnProperty(“name”));//false

alert(xiaoming.property.hasOwnProperty(“name”));//true

原型模式也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便,但还不是原型的最大问题。原型模式的最大问题是由其共享的本性所导致的。原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒

也说得过去,毕竟(如前面的例子所示),通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,问题就比较突出.

四、组合使用构造函数模式和原型模式

创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。

function Student(name,age){

this.name=name;

this.age=age;

}

Student.property.showName=funciton(){alert(this.name);}

这种构造函数与原型混成的模式,是目前在ECMAScript 中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。

五、寄生构造函数模式

通常,在前述的几种模式都不适用的情况下,可以使用寄生(parasitic)构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。

funciton Student(name,age){

Var o=new Object();

o.name=name;

o.age=age;

o.showName=function(){alert(this.name);}

Reurn o;

关于寄生构造函数模式,有一点需要说明:首先,返回的对象与构造函数或者与构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。为此,不能依赖instanceof 操作符来确定对象类型。由于存在上述问题,我们建议在可以使用其他模式的情况下,不要使用这种模式。个人感觉这模式还是有点模仿工厂模式。

 


使用 IDEA 连接 MySQL 数据库时,如果出现 `Access denied for user 'root'@'localhost' (using password: YES)` 错误,通常涉及以下几个方面的配置或问题: 1. **MySQL 用户权限配置** MySQL 的用户权限管理较为严格,`root` 用户可能没有从本地连接的权限。可以通过以下命令检查并修改权限: ```sql -- 查看当前用户的权限 SELECT host, user FROM mysql.user; -- 授予 root 用户从 localhost 连接的权限 GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'your_password' WITH GRANT OPTION; FLUSH PRIVILEGES; ``` 如果需要允许从任意 IP 连接(不推荐用于生产环境),可以将 `localhost` 替换为 `%` [^2]。 2. **密码验证方式问题** 在 MySQL 8.0 及以上版本中,默认的身份验证插件已更改为 `caching_sha2_password`,而某些旧版本的 JDBC 驱动可能不支持该插件。可以通过以下方式解决此问题: - 修改用户的认证方式为 `mysql_native_password`: ```sql ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES; ``` - 或者更新 JDBC 驱动至兼容版本,以支持新的认证方式 [^5]。 3. **检查数据库连接配置** 确保在 IDEA 中配置的数据库连接信息正确无误,包括用户名、密码、主机名和端口号。默认情况下,MySQL 使用端口 `3306`。可以在 `application.properties` 或 `application.yml` 文件中检查相关配置: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ``` 4. **防火墙或端口占用问题** 检查系统防火墙设置是否阻止了 MySQL 的端口(通常是 `3306`)。此外,确保没有其他程序占用了该端口,导致 MySQL 无法正常监听连接请求 [^3]。 5. **MySQL 服务状态** 确认 MySQL 服务正在运行。可以通过命令行工具或操作系统的服务管理界面检查 MySQL 服务的状态。如果服务未启动,请尝试手动启动它 [^3]。 6. **JDBC 驱动版本问题** 确保使用JDBC 驱动与 MySQL 版本兼容。对于 MySQL 8.x,建议使用 `mysql-connector-java` 8.x 版本。可以在 `pom.xml` 中添加以下依赖项: ```xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> ``` 7. **日志分析** 查看 MySQL 的错误日志文件(通常位于 `/var/log/mysql/error.log` 或类似路径),寻找具体的错误信息,这有助于进一步诊断问题 [^4]。 通过上述步骤,应该能够解决 IDEA 连接 MySQL 时遇到的 `Access denied for user 'root'@'localhost' (using password: YES)` 错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值