前言
不管是哪门语言,千变万化不离其宗,深入理解其本质,方能应用自如。对应到js,闭包,原型,函数,对象等是需要花费大功夫思考、理解的。本文穿插了js原型和函数的相关知识,讨论了批量创建对象的几种方式以及它们的优缺点。
正文
说起创建对象,最容易想到的便是通过对象字面量方式直接定义一个对象吧,但这种方式只能创建少量,单独且相互间无联系的对象。若要批量创建对象,该如何?
工厂模式
工厂模式非常直观,将创建对象的过程抽象为一个函数,用函数封装以特定接口创建对象的细节。如下所示:
function createStudent(name,sex,grade){ var o = new Object(); o.name = name; o.sex = sex; o.grade = grade; o.sayName = function(){ console.log(this.name); } return o; } var s1 = createStudent('Claiyre','famale',1);
通俗地讲,工厂模式就是将创建对象的语句放在一个函数里,通过传入参数来创建特定对象,最后返回创建的对象。
工厂模式虽然可以创建多个相似的对象,但却不能解决对象标识的问题,即怎样知道一个对象的类型。构造函数模式应运而生。
构造函数模式
构造函数模式是java语言创建对象的通用方式。两种语言用构造函数创建对象的方式略有不同,注意区别。
在JavaScript中没有类的概念,函数即为一等公民,因此,不必显式声明某个类,直接创建构造函数即可,类的方法和属性在构造函数中(或原型对象上)处理。构造函数模式的示例代码如下:
function Student(name,sex,grade){ this.name = name; this.sex = sex; this.grade = grade; this.sayName = function(){ console.log(this.name); } } var s2 = new Student('孙悟空','male',2);
细心的朋友一定发现了构造函数的函数名首字母是大写的,而普通函数首字母则是小写,这是众多OO语言约定俗成的规定,虽然大多数情况下不大写也不会报错,但是为了代码的规范性和可读性,还是应该将构造函数的首字母大写,与普通函数区别开。
与工厂模式相比,用构造模式创建对象有以下几点不同:
- 没有显示地创建对象
- 直接将属性和方法赋给this对象
- 没有return语句
此外,还应注意到要创建Student的实例,必须要使用new操作符,创建的实例对象将有一个constructor(构造器)属性,指向Person构造函数。调用构造函数创建对象经过了以下几个过程:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码
- 返回新对象(不需要显式返回)
构造函数虽好用,但也不是没有缺点。使用构造函数的主要问题是:每个方法都要在每个实例上创建一遍。在ECMAScript中,函数即对象,因此每定义一个函数,也就是实例化了一个对象。下面的例子证明了这个缺点。
var s3 = new Student('唐僧','male',3); var s4 = new Student('白骨精','female',4); s3.sayName(); s4.sayName(); console.log(s3.sayName == s4.sayName);
运行结果:
也就是说通过构造函数实例化的多个对象的方法,是多个不同的方法,但它们内部的代码以及实现的功能是相同的,这就造成了一定的资源浪费。
幸运的是,这个问题可以用原型模式来解决。
原型模式
js中,每个函数都有一个prototype属性,它是一个指针,指向一个对象,叫做原型对象,原型对象包含了可以由特定类型的所有实例对象共享的属性和方法。此外,这个对象有一个与生自来的属性constructor,指向创建对象的构造方法。
使用原型模式可以让所有的实例共享原型对象中的属性和方法,也就是说,不必再构造函数中定义对象实例的信息。用代码表示如下:
function Student_1(){ } Student_1.prototype.name = 'Claiyre'; Student_1.prototype.sex = 'female'; Student_1.prototype.class = 5; Student_1.prototype.sayName = function (){ console.log(this.name); } var s5 = new Student_1(); s5.sayName(); //Claiyre var s6 = new Student_1(); s6.sayName(); //Claiyre
一张图胜过千言万语,下图清楚地阐释了各个对象和原型对象间的关系:
了解过原型后,可以继续在实例对象上增添属性或方法:
s6.name = 'John'; s6.sayName(); //John
当要读取某个对象的属性时,都会执行一次搜索,搜索首先从对象实例本身开始,如果在实例中找到了这个属性,则搜索结束,返回实例属性的值;若实例上没有找到,则继续向对象的原型对象延伸,搜索对象的原型对象,若在原型对象上找到了,则返回原型上相应属性的值,若没有找到,则返回undefined。因此,实例对象属性会覆盖原型对象上的同名属性,所以上面第二行代码输出的是John。
- Object.getPrototypeOf(object)方法返回参数对象的原型对象。
- Object.keys(object)方法返回对象上课枚举的实例属性。
原型中的所有属性都是被所有实例所共享的,这种共享对于函数来说非常合适,对于包含基本值的属性也说的过去(实例属性会覆盖原型同名属性),但对于那些包含引用类型的属性,可有大麻烦了
Student_1.prototype.friends = ['aa','bb']; console.log('s6的朋友' + s6.friends); s5.friends.push('cc'); console.log('s5的朋友' + s5.friends); console.log('s6的朋友' + s6.friends);
运行结果:
问题来了,我们只想改变s5的朋友列表,但由于原型模式的共享本质,s6的朋友列表也随之改变了。
因此,很少单独使用原型模式。
组合使用构造函数和原型模式
构造函数模式用于定义实例属性,原型模式则用于定义方法和共享的属性。这种混合模式不仅支持向构造函数传入参数,还最大限度地节约了内存,可谓是集两模式之长。示例代码如下:
function Student(name,sex,grade){ this.name = name; this.sex = sex; this.grade = grade; } Student.prototype.sayName = function(){ console.log(this.name); } Student.prototype.school = 'Joooh school';
其他模式
除了以上几种常见的模式外,批量创建对象的方式还有
- 动态原型模式:仅在第一次调用构造函数时,将方法赋给原型对象的相应属性,其他示例的处理方式同构造函数模式
- 寄生构造函数模式:仅仅封装创建对象的代码,然后再返回新创建的对象,仍使用new操作符调用
- 稳妥构造函数模式:没有公共属性,只有私有变量和方法,以及一些get/set方法,用以处理私有变量。
结语
每种模式都有各自的优缺点,具体要使用哪种,还需结合实际场景,深入理解,灵活运用。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]