博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一步步学习javascript基础篇(4):面向对象设计之创建对象(工厂、原型和构造函数等模式)...
阅读量:5282 次
发布时间:2019-06-14

本文共 6134 字,大约阅读时间需要 20 分钟。

前面我们介绍了可以通过Object构造函数或对象字面量都可以用来创建单个对象,但是如果需要创建多个对象的话,显然很多冗余代码。

接下来介绍几种模式来创建对象。不过在此之前,我们还是先来了解下 typeof和instanceof 。

typeof和instanceof 

//typeof主要用了检查值类型数据,如:alert(typeof (1) + " " + typeof ("1") + " " + typeof (false) + " " + typeof (undefined));//instanceof主要用了检查对象,如:var arr = new Array();alert((arr instanceof Object) + " " + (arr instanceof Array) + " " + (arr instanceof Number));//既是Object也是array,但不是Number

例:

//typeof主要用了检查值类型数据,如: alert(typeof (1) + " " + typeof ("1") + " " + typeof (false) + " " + typeof (undefined)); //instanceof主要用了检查对象,如: var arr = new Array(); alert((arr instanceof Object) + " " + (arr instanceof Array) + " " + (arr instanceof Number));//既是Object也是array,但不是Number

下面我们接着介绍数种创建对象的方式。

一、 工厂模式:

function createPerson(name) {    var o = new Object();    o.name = name;    o.sayName = function () {        alert(this.name);    };    return o;}var obj = createPerson("张三");var obj2 = createPerson("李四");alert(obj instanceof Object);alert(obj instanceof createPerson)

由上可知,工厂模式简单、思路清晰、容易理解,也可以创建对象,不过有个缺点不能确定对象类型。因为它总是一个object类型,而不能判定是createPerson类型。

例1:

function createPerson(name) { var o = new Object(); o.name = name; o.sayName = function () { alert(this.name); }; return o; } var obj = createPerson("张三"); var obj2 = createPerson("李四"); alert(obj instanceof Object); alert(obj instanceof createPerson)

二、构造函数模式 

var obj = { name: "李四" };function Person(name) {    this.name = name;    this.sayName = function () {        alert(this.name);    };}var per = new Person("张三");per.sayName();//张三var per2 = new Person("李四");alert(per.sayName==per2.sayName);//false

 

其实,构造函数模式我们在上篇博文就简单介绍过了。同样,构造函数模式也不完美,因为每个实例化出来的对象所拥有的方法都是独立的,而一个对象类型的方法完全是可以同享引用来节省内存空间。

例2:

var obj = { name: "李四" }; function Person(name) { this.name = name; this.sayName = function () { alert(this.name); }; } var per = new Person("张三"); per.sayName();//张三 var per2 = new Person("李四"); alert(per.sayName==per2.sayName);//false alert(per instanceof Person)//与上面的工厂模式不同,这里通过构造函数创建的方法,可以直接判断对象类型了。

由例2可以看出,第二次弹出消息为false,证明了每个实例对象中的方法都是独立的。 第三次弹出消息为true,与上面的工厂模式不同,这里通过构造函数创建的方法,可以直接判断对象类型了。

我们说实例对象的方法应该是共享的,那么我们可以用接下来的模式实现。

三、原型模式

1.0在使用原型模式之前,我们首先需要了解什么是原型。我的理解就是,原始对象类型的模型。每个对象都有一个属性(prototype)指向对象的原型。

function Person() {    this.sayHi1 = function () { }}Person.prototype.sayHi2 = function () { };var per1 = new Person();var per2 = new Person();alert(per1.sayHi1 === per2.sayHi1);//每个实例化出来的对象所独有的,所以为falsealert(per1.sayHi2 === per2.sayHi2);//因为是同一个引用,所以为true//我们再次证明了构造函数中的属性(或是方法、对象)是实例化对象独有的,原型中的属性(或是方法、对象)是共享的。

第一个比较是对象的属性,所以每个实例对象拥有独立的方法,而第二个比较是原型方法,就算是实例对象,它们直接也是引用共享的。

例3:

function Person() { this.sayHi1 = function () { } } Person.prototype.sayHi2 = function () { }; var per1 = new Person(); var per2 = new Person(); alert(per1.sayHi1 === per2.sayHi1);//每个实例化出来的对象所独有的,所以为false alert(per1.sayHi2 === per2.sayHi2);//因为是同一个引用,所以为true

我们看到了 per1.sayHi2 === per2.sayHi2  比较是true。(===是全等的意思,不仅比较值,还比较类型。)

 

我们看到了 __proto__ 指向的就是我们所谓的原型(只有Firefox、 Safari 和 Chrome浏览器有此属性)。还有一个 constructor 指向我们的构造函数。

1.1 __proto__ 和原型 prototype 的关系(其实__proto__并不是一个js语言中规定的对象属性,只是某些浏览器实现了

function Person() {    this.name1 = "张三",    this.sayHi1 = function () { }}Person.prototype.sayHi2 = function () { };var per1 = new Person();var per2 = new Person();alert(per1.constructor);//constructor指向了构造函数alert(per1.constructor.prototype);//constructor.prototype 指向了构造函数的原型alert(per1.constructor.prototype === per1.__proto__);//true 由此看出__proto__和原型的关系。(指向了构造函数的原型)

例:

function Person() { this.name1 = "张三", this.sayHi1 = function () { } } Person.prototype.sayHi2 = function () { }; var per1 = new Person(); var per2 = new Person(); alert(per1.constructor);//constructor指向了构造函数 alert(per1.constructor.prototype);//constructor.prototype 指向了构造函数的原型 alert(per1.constructor.prototype === per1.__proto__);//true 由此看出__proto__和原型的关系。(指向了构造函数的原型)

1.2如果原型中的属性和构造函数中的属性重名,会优先访问构造函数中的属性 

function Person(name) {    this.name1 = name;};Person.prototype.name1 = "test1";Person.prototype.name2 = "test2";var per1 = new Person("name1");alert(per1.name1);//访问到的是实例对象中的name1属性“name1”delete per1.name1;//删除实例对象中的name1属性alert(per1.name1);//访问类型原型中的name1属性“test1”alert(per1.name2);//访问原型属性“name2”per1.name2 = "name2";//这里并不是修改了原型属性“name2”的值,而是为实例对象动态添加了一个“name2”的属性,并赋值。alert(per1.name2);//访问实例属性“name2”delete per1.name2;alert(per1.name2);//访问原型属性“name2”

例:

function Person(name) { this.name1 = name; }; Person.prototype.name1 = "test1"; Person.prototype.name2 = "test2"; var per1 = new Person("name1"); alert(per1.name1);//访问到的是实例对象中的name1属性“name1” delete per1.name1;//删除实例对象中的name1属性 alert(per1.name1);//访问类型原型中的name1属性“test1” alert(per1.name2);//访问原型属性“name2” per1.name2 = "name2";//这里并不是修改了原型属性“name2”的值,而是为实例对象动态添加了一个“name2”的属性,并赋值。 alert(per1.name2);//访问实例属性“name2” delete per1.name2; alert(per1.name2);//访问原型属性“name2”

如图:

 

1.3使用字面量表示法为原型统一添加方法和属性

我们上面看到定义原型的属性和方法都是一个个定义的,看上去明显感觉杂乱。其实我们也可以通过字面量的方式为原型添加属性或方法,如:

function Person() { }Person.prototype = {    name1: "张三",    age: 23,    sayHi: function () {        alert(this.name1);    }}var per1 = new Person();per1.name1 = "李四"per1.sayHi()

 

缺点:这样的定义,相当与重写了对象类型的prototype属性,也就是我们再也访问不到 constructor 属性了。

当然,我也可以手动设置,如:

function Person() { }Person.prototype = {    constructor: Person,//手动设置constructor赋值Person    name1: "张三",    age: 23,    sayHi: function () {        alert(this.name1);    }}var per1 = new Person();per1.name1 = "李四"per1.sayHi()

 

我们通过在构造函数中定义属性,在原型中通过字面量表示法定义方法已经可以很好的创建对象了。唯一的缺点就是分为两个步骤,那么我们下面试着全部封装到构造函数中。如: 

function Person(str1, str2, str3) {    this.name1 = str1;    this.name2 = str2;    this.age = str3;    //方法    if (typeof this.sayName != "function") {
//只用判断一个就可以了,第一次构造的时候是不能有sayName方法的。 //在构造函数里面貌似不能通过字面量来为prototype统一赋值 Person.prototype.sayName = function () { alert(this.name1); }; Person.prototype.sayHi = function () { alert(this.name2); }; }}var per1 = new Person("张三","李四","12");per1.sayName();

 

我们平时常用的一些创建对象的方式就介绍到这里了。

下一篇继续分析对象的继承,欢迎大家继续关注。

这是学习记录,不是教程。文中错误难免,您可以指出错误,但请不要言辞刻薄。

原文链接:

本文已同步至目录索引:

欢迎上海“程序猿/媛”、"攻城狮"入群:【沪猿】 

欢迎对个人博客感兴趣的道友加入群:【嗨-博客】 

如果您觉得文章对您有那么一点点帮助,那么麻烦您轻轻的点个赞,以资鼓励。

 

转载于:https://www.cnblogs.com/zhaopei/p/5013288.html

你可能感兴趣的文章
ie6解决png图片透明问题
查看>>
瞬间的永恒
查看>>
2019-8-5 考试总结
查看>>
JS中实现字符串和数组的相互转化
查看>>
web service和ejb的区别
查看>>
Windows Azure Cloud Service (29) 在Windows Azure发送邮件(下)
查看>>
微信上传素材返回 '{"errcode":41005,"errmsg":"media data missing"}',php5.6返回
查看>>
div或者p标签单行和多行超出显示省略号
查看>>
Elasticsearch 滚动重启 必读
查看>>
Hadoop基本概念
查看>>
java.util.zip压缩打包文件总结一:压缩文件及文件下面的文件夹
查看>>
浅说 apache setenvif_module模块
查看>>
MySQL--数据插入
查看>>
重新学习python系列(二)? WTF?
查看>>
shell脚本统计文件中单词的个数
查看>>
SPCE061A学习笔记
查看>>
sql 函数
查看>>
hdu 2807 The Shortest Path 矩阵
查看>>
熟悉项目需求,要知道产品增删修改了哪些内容,才会更快更准确的在该项目入手。...
查看>>
JavaScript 变量
查看>>