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 ...
随机推荐
- css 问题
问题1:使得在div中的图片自适应于Div的大小 图片放在DIV中是为了更好地管理,那么如果图片不能自适应与div的大小,则此事的初衷就会变质. 怎样自适应呢,有一个很简单的办法: img{ widt ...
- Uoj 22 外星人
Uoj 22 外星人 注意到一个数只有 \(\%\) 了小于等于自己的数时,才可能有变化,否则可以随意安排,不会对最后最优解造成影响. 用 \(f[x]\) 表示给一个数 \(x\) ,仅用 \(a[ ...
- PowerDesigner生成Oracle表名带有引号的解决方法
PowerDesigner生成表名带有引号,如下: /*==============================================================*/ /* Tabl ...
- DML操纵语句
--在新增数据的时候,如果在表名之后没有跟 列名,那么values()必须写全--顺序必须不能改变,这个顺序就是表中列的顺序insert into dept values(70,'20','哈哈') ...
- (高级篇)jQuery学习之jQuery Ajax用法详解
jQuery Ajax在web应用开发中很常用,它主要包括有ajax,get,post,load,getscript等等这几种常用无刷新操作方法,下面我来给各位同学介绍介绍. 我们先从最简单的方法看起 ...
- dwr的A request has been denied as a potential CSRF attack.错误
虽然DWR是个很早就出现的Ajax框架,但一直都没去使用过,今天正好没事就看了一下并参照文档照做了个demo, 在其中碰到一个问题: 后台打印出错误信息:“严重: A request has been ...
- Ubuntu下手动安装Nvidia显卡驱动
1. 下载最新版的nVidia驱动. http://www.nvidia.com/page/drivers.html 2.编辑blacklist.conf. sudo gedit /etc/modpr ...
- 转发,重定向以及区别和简单的session对象
1.转发 作用:在多个页面交互过程中实现请求数据的共享. 过程:Web服务器内部将一个request请求的处理权交给另外一个资源,属于同一个访问请求和响应过程,所以request对象的 ...
- RK3288 USB触摸屏无法使用,需要添加PID和VID
RK3288 Android5.1 现象:USB 接口触摸屏插到板子上,触摸屏无法使用,有可能出现更奇葩的,同一套代码,有的板子可以用,有的板子不能用. 1.打开串口调试,插上触摸屏,读取触摸屏的 ...
- printf()_scanf()_取余运算符与取模运算符
基本的输入和输出函数的用法 printf();四种用法 1.printf("字符串\n"); 2.printf("输出控制符",输出参数); 3.printf( ...