JavaScript知识总结--对象的相关概念
一、定义
无序属性的集合。
说白了就是一个容器,可以容纳【基本值、对象或者函数】,这些东西都叫做属性。每个属性都有一个名字,每个名字都映射一个值(可以是基本类型的值,也可以是引用类型的值)。从以上描述上来看很像Java里面的Map,但形似神不似,它有它的特点。
二、对象的属性特点
1、 属性类型
a) 数据属性
数据属性包含一个数据值得位置,在这个位置可以读取和写入值,这类属性有四个描述符描述其特性
① 、Configurable:顾名思义是否可配置(通过delete删除属性,能否该变其为访问器属性),默认true。
② 、Enumerable:表示能否通过for-in循环返回属性,默认true
③ 、Writable:能否修改属性的值,默认true
④ 、Value:包含这个属性的数据值。读取属性的时候,从这个位置读,写入时把新值保存在这个位置。默认undefined。
以上可以理解为数据属性的数据结构,可以通过Object.defineProperty()方法来修改属性默认的特性,具体方法参照API。
b) 访问器属性
访问器属性不包含数据值,他们包含一对儿getter(读)和setter(写)函数(非必须)。特性也有4个,前两个跟数据属性一致,另外两个是
① 、Get:读取属性时调用的函数。默认undefined
② 、Set:写入属性时调用的函数。默认undefined
访问器属性只能通过Object.defineProperty()来定义,它长用于访问一些只能通过访问器属性访问的属性,通常这类属性以下划线’_’开头。
2、 Object.defineProperties()方法可以同时定义多个属性的特性。
3、 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。
通过以上介绍,实现一个遍历对象属性以及属性特性描述符的功能就没什么问题了。
三、创建对象的方法
1、 简单方法
a) 构造函数定义后再追个追加属性var person = new Object();person.name=’xxx’;
b) 对象字面量定义 var person = {name:’xxxx’;};
优点:直观
缺点:如果我要创建很多相同的对象,会产生大量的重复代码。
2、 工厂模式
为解决1中的缺点产生的一种创建对象的方法
Function createPerson(name){
Var o = new Object();
o.name=name;
return o;
}
Var person1 = createPerson(‘xxxxx’);
Var person2 = createPerson(‘xxxxxxxxxx’);
这种模式解决了重复代码的问题,其实还有问题没有解决掉:实际应用中拿到变量很可能需要判断这个变量是哪一种变量的类型,然后再进行不同的处理逻辑。注意这里:变量的类型不要单纯的理解为ECMASript规定的6几种变量类型,要把它理解的更广义一点,向上面的代码其实就是想创建一种person的数据类型。
3、 构造函数模式
理解函数与构造函数的区别,不要想太多,直接从字面上去理解,构造函数也是一种函数,它本质上也是Object类型。当表达式中用【new 构造函数名(参数)】这种形式来使用这个函数时,他会返回一个新的对象,这个对象中的属性就是函数中定义的各种属性的镜像(除了prototype)。
Function Person(name){
This.name=name;
This.helloWold= function(){console.log(this.name)};
}
Var person1 = new Person(‘xxx’);
Var person2 = new Person(‘111’);
通常构造函数名首字母大写以区别于普通的函数。
Person1、person2分别保存着Person的一个不同的实例,那么问题来了person1与person2是怎么和Person关联的呢?其实person1,person2中有一个constructor属性,是一个引用类型指向Person。
缺点:通过构造函数创建的对象都是不同的对象,这些对象中包含了代码相同函数,也就是说在每一个对象中都定义了逻辑相同的方法。这似乎有点冗余的赶脚。
4、 原型模式
a) 原型对象的特点
每一个函数都有一个prototype(原型)属性,它是一个引用类型,指向一个对象,这个对象的的特点是:包含了一些属性和方法,这些属性和方法属于某个类型的所有并且可以为类型的所有实例共用。是不是很像Java中类的静态变量,静态方法的意思啊?
Function Person(){};
Person.prototype.name=’xxxx’;
Person.prototype.hellworld= function(){console.log(this.name)};
Var p1 = new Person();
Var p2 = new Person();
Alert(p1.name);alert(p2.name);
神奇的发现通过prototype所有Person的实例共享了prototype上的属性。
在默认情况下所有原型对象都会自动获得一个constructor属性,这个属性包含一个执行prototype属性所在函数的指针。当调用构造函数创建一个实例后,该实例内部也会有一个prototype属性,该属性指向构造函数的原型对象。机:Person.prototype==person1.prototype==person2.prototype。
可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。
ECMAScript5增加了一个新方法:Objec.getPrototypeOf()可以取得一个对象的原型。
HasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,这个方法只在给定属性存在于实例中时,才会返回true。这个方法与in操作符有区别,in操作符是只要能够通过实例访问到给定的属性时都返回ture,无论属性实在实例中还是在原型中。
For in与Object.keys()都可以取得对象上所有可枚举的属性,前者包含了实例对象+原型对象上的属性,后者仅仅是实例对象属性。
Object.getOwnPropertyNames()方法可以得到对象的所有属性,无论属性是否可枚举。
b) 通过对象字面量设置对象的prototype。
通过对象字面量的方法设置prototype(本质上是重写默认的prototype对象)会切断prototype与对象之间的联系,即:constructor属性不再指向对象了。但是可以通过显示指定的方式建立这种连接(即在对象字面量中定义一个constructor属性指向对象)。
c) 缺点:
原型中所有的属性都是被很多实例共享的,这种共享对于函数比较合适,对于那些只包含基本值得属性也OK,然而对于包含引用类型(比如数组)的属性来说,某一个实例修改了这个原型属性,所有的实例都会受到影响。这恐怕在大多数应用中都是不想看到的,因为,实例一般都是要有属于自己的全部属性。
5、 组合使用构造函数和原型模式
这种模式解决了上面所说的问题,通过构造函数模式定义实例属性,而原型模式用于定义方法和共享属性。这样每个实例都会有自己的一份实例属性的副本,同时又共享着对方法的引用,最大限度地节省了内存。
6、 动态原型模式
这种方式只是写法上与5不同,它将prototype的定义写在了构造函数内部,完成了对prototype的内部封装。
7、 寄生构造函数模式
这其实是一种适配器模式,在一个构造函数内部再次封装了对象。
8、 稳妥构造函数模式
所谓稳妥构造指构造函数内部没有公共的属性,而且其方法也不引用this的对象。与寄生构造模式类型,使用稳妥构造函数模式创建的对象与构造函数之间也没有什么关系,使用instanceof操作符对这种对象也没有什么意义。
四、对象的继承
继承是OO程序设计中一个基本的概念,一般通过接口继承和实现继承,接口继承只继承方法签名,而实现继承则继承实际的方法。
ECMAScript中没有方法签名(没有返回值类型,参数统一用arguments表示),所以只支持实现继承,依靠原型链来实现。
1、 原型链
a) 概念:
构造函数与实例之间的关系是,每个实例都有一个属性prototype指向构造函数的prototype对象。
如果构造函数的prototype对象指向另一个类型的实例对象,此时会发生什么现象?
① 构造函数的prototype对象与构造函数之间切断联系;
② 构造函数的prototype对象包含了一个指向另一个类型的原型对象
通过这种prototype的指向我们可以一直延伸下去,这样就构成了一条原型链条,这就是原型链的概念。
b) 缺点:
① 、在通过原型来实现继承时,原型实际上会变成另一个类型的实例,于是,原先的实例属性也就变成了现在的原型属性了。这样新创建的所有实例可能会共享一些不应该共享的属性。与原型模式创建对象的问题一样。
② 在创建对象的实例时,没有办法再不影响所有对象实例的前提下向父对象的构造函数传递参数
2、 Constructor stealing
为解决上述问题,使用的一种技术手段,即在子对象的构造函数内部调用父对象的构造函数(通过使用apply()和call()方法,函数只不过是在特定环境中执行代码的对象,这个认识很强大)
Function SuperType(){this.colors=[‘aa’,’bb’,’cc’]};
Function SubType(){SuperType.call(this)};
Var instance1 = new SubType();
Instance1.colors.push(‘dd’);
Console.log(instance1.colors);// ‘aa’,’bb’,’cc’,’dd’
Var instance2 = new SubType();
Console.log(instance2.colors);// ‘aa’,’bb’,’cc’
但是如何解决构造函数带来的代码重复的问题?目前父对象原型中定义的方法对子对象是不可见的。
3、 构造函数+原型链模式(combination inheritance)
很自然的就想到通过这种方式来解决问题,通过原型链来实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。
问题:子对象实例和原型上都存在父对象的实例属性,实例方法。
4、 寄生组合式继承
3中出现问题的原因是执行了两次父对象的构造函数,即:子对象构造函数中调用一次,子对象prototype赋值又一次,两次重复部分就是父对象实例属性与实例方法。
原因清除了,解决起来就不是很难了,在子对象原型赋值的时候赋一个父对象原型的实例就可以了。
Function inheritPrototype(subType, superType){
Var prototype = Object(superType.prototype);//创建父对象原型的实例
Prototype.constructor = subType;//构造器指向子对象
SubType.prototype=prototype;//制定子对象原型指向包装后的父对象原型
}
这段代码是不是很优雅啊~~~
本文属于个人读书总结,转载请注明出处
JavaScript知识总结--对象的相关概念的更多相关文章
- JavaScript基础知识(对象、函数与对象)
17.对象 属性:描述对象的信息 方法:描述对象的行为 封装:只关心输入和输出(不管过程如何实现) ü 对象的分类: 内置对象(原生对象): 就是JavaScript语言预定义的对象(如Strin ...
- (转)javascript中的对象查找
本文转自:http://otakustay.com/object-lookup-in-javascript/ ---很棒的一篇文章,作者的其他文章还暂时没读,但相信作者是一个谦虚 谨慎的好工程师 近 ...
- Javascript中的对象和原型(3)
在Javascript中的对象和原型(二)中我们提到,用构造函数创建的对象里面,每个对象之间都是独立的,这样就会降低系统资源的利用率,解决这样问题,我们就要用到下面提到的原型对象. 一 原型对象 原型 ...
- 【原文】前端程序员必须知道的高性能Javascript知识
原文:前端程序员必须知道的高性能Javascript知识 想必大家都知道,JavaScrip是全栈开发语言,浏览器,手机,服务器端都可以看到JS的身影. 本文会分享一些高效的JavaScript的最佳 ...
- 《jQuery风暴》第2章 必须知道的JavaScript知识
第2章 必须知道的JavaScript知识 JavaScript是jQuery应用的基础,掌握JavaScript这门语言是使用jQuery的基础条件.本章不会全面细致的讲解JavaScript的全部 ...
- Javascript知识——事件
O(∩_∩)O~~又是新的一周开始了,今天还是在继续学习Javascript知识,今天主要讲了事件的知识.现在就总结下吧. 事件 事件一般是用于浏览器和用户操作进行交互.最早是 IE 和 Netsca ...
- Javascript知识四(DOM)
[箴 10:4] 手懒的,要受贫穷:手勤的,却要富足. He becometh poor that dealeth with a slack hand: but the hand of the di ...
- 第一百一十三节,JavaScript文档对象,DOM基础
JavaScript文档对象,DOM基础 学习要点: 1.DOM介绍 2.查找元素 3.DOM节点 4.节点操作 DOM(Document Object Model)即文档对象模型,针对HTML和XM ...
- javascript 之Function对象的apply(),call(),bind(),方法和arguments,caller,length属性
注:这篇文章原文:http://www.jb51.net/article/30883.htm 自己作为学习,重新写写. 一.写在前面的话 前端javascript编程还只是略懂皮毛,DOM知道一点,j ...
随机推荐
- times(NULL) Segmentation fault
****************************************************************************** * times(NULL) Segment ...
- Java IO,io,文件操作,删除文件,删除文件夹,获取文件父级目录
Java IO,io,文件操作,删除文件,删除文件夹,获取文件父级目录 这里先简单的贴下常用的方法: File.separator //当前系统文件分隔符 File.pathSeparator // ...
- BZOJ3675 Apio2014 序列分割 【斜率优化】
Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...
- Sprint第一个冲刺(第三天)
一.Sprint介绍 今天我们完成了简单登录界面及美化的任务,完成了此次整个Sprint的百分之十五. 下面是实验截图: 二.Sprint周期 看板: 燃尽图:
- ballerina 学习五 使用composer管理ballerina 项目
1. 启动 composer 备注: 因为这个命名和php的一个包管理工具重名了,所以可能需要使用决定路径 比如我的mac系统使用:Library/Ballerina/ballerina-0.970. ...
- mix deps HEX_HTTP_CONCURRENCY=1 HEX_HTTP_TIMEOUT=120 timeout
mix deps.get timeout 问题: If this happens consistently, adjust your concurrency and timeout setting ...
- Bootstrap树控件(Tree控件组件)使用经验分享
前言:很多时候我们在项目中需要用到树,有些树仅仅是展示层级关系,有些树是为了展示和编辑层级关系,还有些树是为了选中项然后其他地方调用选中项.不管怎么样,树控件都是很多项目里面不可或缺的组件之一.今天, ...
- filter敏感词替换
1.properties文件的应用 在<filter>写入配置 <filter> <filter-name>myFilter</filter-name> ...
- 嵌入式linux问题杂锦
tftp 在开发板上不能获取共享文件,出现: Permission denied tftp: can't open 'myTcpTest': Permission denied 是因为,我在/sys目 ...
- 在AWS EMR上运行Map Reduce的Java示例程序 及 操作小计
下面的代码中AffairClient类中包含了三个内之类,分别对应于Hadoop Mapreduce程序运行所需的Mapper类,Reducer类,和主类.AffairClient类中其余方法用于配置 ...