JavaScript 对象 之创建对象 学习笔记
假设我们有这样的一个需求:记录一个人的 名字和年龄,然后有个方法可以显示这个人的名字和年龄。
按照普通的方法,我们的代码应该是这样的:
var person1 = new Object() ,
person2 = new Object() ; person1.name = "TOM" ;
person1.age = 18 ;
person1.show = function () {
alert ("Name:" + this.name + " ; Age:" + this.age);
}
person2.name = "LiLei" ;
person2.age = 22 ;
person2.show = function () {
alert ("Name:" + this.name + " ; Age:" + this.age);
}
以上的写法虽然能解决了该需求,但是却很坑爹,因为出现了大量的重复代码。让码农处于一种毫无意义的重复工作中。
为了解决这些问题,人们开始了换一种新的方式去解决这个问题。
一、工厂模式
function createperson(name,age) {
o = new Object() ;
o.name = name ;
o.age = age ;
o.show = function(){
alert("Name:" + this.name + " ;Age:" +this.age);
}
return o;
}
var person1 = createperson("TOM",18);
var person2 = createperson("LiLei",20);
这个模式虽然解决了之前的创建多个对象所引发的重复代码的问题,但是没有解决对象识别的问题。即,这个对象的类型到底是啥。
二、构造函数模式
function Person(name,age){
this.name = name ;
this.age = age ;
this.show = function() {
alert("Name:" + this.name + " ;Age:" + this.age);
};
}
var person1 = new Person("Tom",18);
var person2 = new Person("LiLei",20);
构造函数 始终以 一个大写字母为开头 如 Person()。
创建的对象,可以使用 constructor 属性 可以发现该属性 指向 Person。
但是,这种方式并没有缺点。 person1 和 person2 都享有同样的方法,即 show(), 这里却 实例化 了两次。这对内存管理造成了极大的浪费。因此,我们可以稍微改动下该函数。
function Person(name,age) {
this.name = name ;
this.age = age;
this.show = show();
}
//创建一个全局函数
function show() {
alert("Name:" + this.name + " ;Age:" + this.age);
}
var person1 = new Person("Tom",18);
var person2 = new Person("LiLei",20);
这样,person1 和 person2 就可以享有同样的方法 show(), 而不需要实例化两次。
可是这样还是不够的,创建了全局函数,会导致别人可能在其他地方重写了这个功能,降低了对象的封装性。
三、原型模式
function Person() {
}
var friends = new Person();
Person.prototype.friends = ['Lucy'] ;
// 切断了构造函数和原型之间的联系。 所以 friends 访问不到这里面的值,也没有这些属性。
Person.prototype = {
name : "Tom",
age : 18,
show : function() {
alert("Name:" + this.name + " Age:" + this.age);
}
}
//只是在原型上添加了 friends 所以 friends 能访问到这个值
Person.prototype.friends = ['Lucy','Lily'] ;
var person1 = new Person();
var person2 = new Person();
person2.name = "LiLei"; // person2 的 name 为 LiLei
person1.name = "HanMei"; //person1的 name 为 HanMei
delete person1.name; //person1 的 name 又变为 prototype(原型) 里的 name 即 Tom
//以上可以解释 实例属性 和 原型属性 的关系
//即 当 有 实例属性时, 访问对象属性时,访问到的属性为实例,否则,访问原型里的属性。
alert( friends.friends ) //返回 ['Lucy'] ; 因为 已经为 Person 的原型 新增了 属性 friends。
alert( friends.name ) //返回 错误。 而之后的 原型 直接整个都被重写了,所以friends 不能访问到之后的属性。
person1.friends.push("Jim");
alert( person1.friends ); //返回 ['Lucy','Lily',"Jim"]
alert( person2.friends ); //返回 ['Lucy','Lily',"Jim"]
// 因为 Person 的原型 friends 指向 ['Lucy','Lily'] 该数组,
// Person1 也是同样指向该数组,对该数组操作, 会直接修改 该数组。
// 从而导致 Person2.friends 也会改变。
// 这并不是我们所需要的,所以这是一个错误!
原型模式 解决了构造函数模式 所不能解决的问题,但是也可能会出现像上述这种并不想看到的错误。因此出现了,我们可以把这两种模式组合起来,来满足我们的要求。
四、组合使用构造函数模式和原型模式
function Person(name,age) {
this.name = name ;
this.age = age ;
this.friends = [ "Lucy","Lily" ];
}
Person.prototype = {
constructor:Person,
show:function(){
alert( "Name:" + this.name + " ;Age:" + this.age );
}
}
var person1 = new Person("Tom",18);
var person2 = new Person("LiLei",20);
person1.friends.push("Jim");
alert(person1.friends); // 返回 ["Lucy","Lily","Jim"]
alert(person2.friends); // 返回 ["Lucy","Lily"]
将所有的实例属性都放在 构造函数 中声明,所有实例共享的属性 和 方法 都在原型中定义。
构造函数和原型模式的混合使用,是目前 使用最广泛、认同度最高的方法。
五、动态原型模式
function Person(name,age){
this.name = name;
this.age = age;
if (typeof this.show != "function") {
Person.prototype.show = function () {
alert("Name" + this.name + " ;Age:" + this.age);
}
}
}
var person1 = new Person("Tom",18);
// 当 Person 第一次 实例化的时候,函数内部自动执行生成了 原型 show()
var person2 = new Person("LiLei",20);
person2.show();
// 第一次实例化的时候已经生成 原型 show() 因此, person2 能直接调用;
这种可以把 所有的信息 (包括属性和方法) 全部都集中在一个构造函数里。
从视觉上看,可以一目了然,能在一个构造函数里 看到所有的属性和方法,方便以后修改等。。。
六、寄生构造函数模式
function Person(name,age) {
var o = new Object() ;
o.name = name ;
o.age = age ;
o.show = function () {
alert("Name:" + this.name + " ;Age:" + this.age) ;
};
return o;
}
function SpecialPerson(name,age) {
var o = new Person(name,age) ;
o.showage = function () {
alert (this.age);
};
return o;
}
var person1 = new Person("Tom",18);
var person2 = new Person("LiLei",20);
person1.showage() // 18
person2.showage() // ERROR
除了 最后的 new 外,剩下的几乎跟工厂模式一模一样!
当我们遇到一个不能直接修改的构造函数时, 可以创建另一个函数 去寄生到这个构造函数上,来添加原本没有的功能。
七、稳妥构造函数模式
function Person(name,age) {
var o = new Object() ;
o.show = function () {
alert("Name:" + name + " ;Age:" + age);
}
return o;
}
var person1 = Person("Tom",18);
person1.show();
当 当前的环境不允许使用 new 和 this. 只能通过 内定的几种方法来获取值。没有别的办法从外部将 值 传入 构造函数 里,提供了一种安全性。适合在安全环境下使用。
JavaScript 对象 之创建对象 学习笔记的更多相关文章
- 《零基础学JavaScript(全彩版)》学习笔记
<零基础学JavaScript(全彩版)>学习笔记 二〇一九年二月九日星期六0时9分 前期: 刚刚学完<零基础学HTML5+CSS3(全彩版)>,准备开始学习JavaScrip ...
- 《JavaScript语言精粹》学习笔记
一.in的用法 for...in 枚举一个对象的所有可枚举属性 检测DOM/BOM属性 if ("onclick" in elem) { // 元素支持onclick } if ( ...
- 《JavaScript权威指南》学习笔记 第六天 开始学习DOM了。
昨天学习了window对象的一些方法.window对象主要是针对当前视窗的操作.window对象提供了一些列API来帮助我们了解当前窗口的信息.例如history对象可以让我们获取浏览历史.nvaig ...
- 《JavaScript高级程序设计》学习笔记12篇
写在前面: 这12篇博文不是给人看的,而是用来查的,忘记了什么基础知识,点开页面Ctrl + F关键字就好了 P.S.如果在对应分类里没有找到,麻烦告诉我,以便尽快添上.当然,我也会时不时地添点遗漏的 ...
- JavaScript基础知识(学习笔记)
1. 在JavaScript中所有事物都是对象:字符串.数字.数组.日期等等2. 在JavaScript中,对象是拥有属性和方法的数据3. 属性是与对象相关的值,方法是能够在对象上执 ...
- 《Javascript权威指南》学习笔记之十二:数组、多维数组和符合数组(哈希映射)
Array(数组)是JavaScript中较为复杂的数据类型,同Java.C#.VB等程序语言的数组相比.Javascript数组中的元素不必为同样的数据类型,能够在数组每一个元素上混合使用数字.日期 ...
- 《JavaScript权威指南》学习笔记 第五天 window对象的方法。
前天和昨天大致浏览了犀牛书的函数.类与模块.正则表达式.JavaScript扩展.以及服务端的js.这些方面对于我目前的水平来说比较难,一些最基本的概念都不能领会.不过最复杂的知识占用平时使用的20% ...
- 《JavaScript权威指南》学习笔记 第三天 找个对象
现实生活中真的对象没有找到,在JavaScript 里左一个对象又一个对象,搞的我也是晕晕乎乎不知所云.人事复杂,人心难懂.我虽然是文科生,但是也不善于巧言.还是在js里面找找对象吧.那么我们今天就从 ...
- 《Javascript权威指南》学习笔记之十五:BOM之源---window对象
BOM是Browser Object Model的缩写,即浏览器对象模型,提供了独立于网页内容和浏览器窗体之间进行交互的APi.API由若干对象组成,因为浏览器是Javascript的宿主,因此,这些 ...
随机推荐
- 深入解析Javascript闭包
首先给个例子: function PfnOuter(){ var num=999; function PfnInner(){ alert(num); } return PfnInner; } var ...
- 怎样禁用或启用"最近使用的项目"
1.右击“任务栏”——属性——‘开始’菜单——自定义——高级——去掉“列出我最近打开的文档”的勾选——确定.2.通过“组策略”来修改开始——运行——gpedit.msc——用户配置——管理模板——任务 ...
- ANSI C中关于FILE流的一些
ANSI C只是一个定义,定义了一个借口与标准,具体实现将是不同的. 刚看到I/O的时候就对于Stream非常的迷惑,这是什么玩意.后面才明白,这只是一个抽象出来的概念而已.对于一个Stream,它具 ...
- Oracle建表添加数据
- CF 628C --- Bear and String Distance --- 简单贪心
CF 628C 题目大意:给定一个长度为n(n < 10^5)的只含小写字母的字符串,以及一个数d,定义字符的dis--dis(ch1, ch2)为两个字符之差, 两个串的dis为各个位置上字符 ...
- [cyber security][php]pfSense目录遍历漏洞分析
0×00 导言 pfSense是一个基于FreeBSD,专为防火墙和路由器功能定制的开源版本. 在本文中,我们将向大家介绍在pfSense的2.1.3以及更低版本中的CVE-2014-4690漏洞:对 ...
- 在Ext JS 6中添加本地化包
我在官方论坛发的帖子终于有人恢复了,也终于知道如何添加本地化包了.在Ext JS 6中,Ext JS属于经典工具包,而本地化是包含在经典工具包中,因而在app.json中,要添加本地化包,必须在cla ...
- thrift demo
基于上一篇博客,安装thrift complier之后,就需要进行跑跑程序,来看看是否如同预期的那种效果. 前面的thrift compiler的主要作用,其实就是为了IDL的,就是防止客户端和服务端 ...
- KVM虚拟机管理
#定义新的存储池 virsh pool-define-as spool4lj dir - - - - "/home/lj/spool4lj" virsh pool-build sp ...
- SQL Server复制需要有实际的服务器名称才能连接到服务器
服务器上安装的WIN2008 R2,然后没有在意机器名,安装了SQL2008 R2数据库之后,配置AD域的时候修改了机器名. 然后,开始配置数据库镜像同步的时候,先试了下数据库复制发布,结果提示“SQ ...