文档章节

JS面向对象的程序设计

告别只是另一种体验
 告别只是另一种体验
发布于 2016/06/12 10:34
字数 2974
阅读 15
收藏 2
点赞 0
评论 0

一、理解对象:

     第一种:基于Object对象

var person = new Object(); person.name = 'My Name'; person.age = 18; person.getName = function(){ return this.name; } 第二种:对象字面量方式(比较清楚的查找对象包含的属性及方法)

var person = { name : 'My name', age : 18, getName : function(){ return this.name; } } JS的对象可以使用‘.’操作符动态的扩展其属性,可以使用’delete’操作符或将属性值设置为’undefined’来删除属性。如下:

person.newAtt=’new Attr’;//添加属性 alert(person.newAtt);//new Attr delete person.age; alert(person.age);//undefined(删除属性后值为undefined); 二、对象属性类型

  ECMA-262第5版定义了JS对象属性中特征(用于JS引擎,外部无法直接访问)。ECMAScript中有两种属性:数据属性和访问器属性

  1、数据属性:
  数据属性指包含一个数据值的位置,可在该位置读取或写入值,该属性有4个供述其行为的特性:

  [[configurable]]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;

  [[Enumberable]]:表示是否可通过for-in循环返回属性。默认true;

  [[Writable]]:表示是否可修改属性的值。默认true;

  [[Value]]:包含该属性的数据值。读取/写入都是该值。默认为undefined;如上面实例对象person中定义了name属性,其值为’My name’,对该值的修改都反正在这个位置

  要修改对象属性的默认特征(默认都为true),可调用Object.defineProperty()方法,它接收三个参数:属性所在对象,属性名和一个描述符对象(必须是:configurable、enumberable、writable和value,可设置一个或多个值)。

  如下:(浏览器支持:IE9+、Firefox 4+、Chrome、Safari5+)

var person = {}; Object.defineProperty(person, 'name', { configurable: false, writable: false, value: 'Jack' }); alert(person.name);//Jack delete person.name; person.name = 'lily'; alert(person.name);//Jack 可以看出,delete及重置person.name的值都没有生效,这就是因为调用defineProperty函数修改了对象属性的特征;值得注意的是一旦将configurable设置为false,则无法再使用defineProperty将其修改为true(执行会报错:can't redefine non-configurable property);

  2、访问器属性:

  它主要包括一对getter和setter函数,在读取访问器属性时,会调用getter返回有效值;写入访问器属性时,调用setter,写入新值;该属性有以下4个特征:

  [[Configurable]]:是否可通过delete操作符删除重新定义属性;

  [[Numberable]]:是否可通过for-in循环查找该属性;

  [[Get]]:读取属性时调用,默认:undefined;

  [[Set]]:写入属性时调用,默认:undefined;

  访问器属性不能直接定义,必须使用defineProperty()来定义,如下:

var person = { _age: 18 }; Object.defineProperty(person, 'isAdult', { get: function () { if (this._age >= 18) { return true; } else { return false; } } }); alert(person.isAdult?'成年':'未成年');//成年 从上面可知,定义访问器属性时getter与setter函数不是必须的,并且,在定义getter与setter时不能指定属性的configurable及writable特性;

  此外,ECMA-262(5)还提供了一个Object.defineProperties()方法,可以用来一次性定义多个属性的特性:

var person = {}; Object.defineProperties(person,{ _age:{ value:19 }, isAdult:{ get: function () { if (this._age >= 18) { return true; } else { return false; } } } }); alert(person.isAdult?'成年':'未成年');//成年

  上述代码使用Object.defineProperties()方法同时定义了_age及isAudlt两个属性的特性

  此外,使用Object.getOwnPropertyDescriptor()方法可以取得给定属性的特性:

var descriptor = Object.getOwnPropertyDescriptor(person,'_age'); alert(descriptor.value);//19 对于数据属性,可以取得:configurable,enumberable,writable和value;

对于访问器属性,可以取得:configurable,enumberable,get和set

三、创建对象

使用Object构造函数或对象字面量都可以创建对象,但缺点是创建多个对象时,会产生大量的重复代码,因此下面介绍可解决这个问题的创建对象的方法

 1、工厂模式

function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.getName = function () { return this.name; } return o;//使用return返回生成的对象实例 } var person = createPerson('Jack', 19, 'SoftWare Engineer'); 创建对象交给一个工厂方法来实现,可以传递参数,但主要缺点是无法识别对象类型,因为创建对象都是使用Object的原生构造函数来完成的。

 2、构造函数模式

function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.getName = function () { return this.name; } } var person1 = new Person('Jack', 19, 'SoftWare Engineer');

var person2 = new Person('Liye', 23, 'Mechanical Engineer');

 使用自定义的构造函数(与普通函数一样,只是用它来创建对象),定义对象类型(如:Person)的属性和方法。它与工厂方法区别在于:

没有显式地创建对象 直接将属性和方法赋值给this对象; 没有return语句; 此外,要创建Person的实例,必须使用new关键字,以Person函数为构造函数,传递参数完成对象创建;实际创建经过以下4个过程:

创建一个对象 将函数的作用域赋给新对象(因此this指向这个新对象,如:person1) 执行构造函数的代码 返回该对象 上述由Person构造函数生成的两个对象person1与person2都是Person的实例,因此可以使用instanceof判断,并且因为所有对象都继承Object,因此person1 instanceof Object也返回真:

alert(person1 instanceof Person);//true; alert(person2 instanceof Person);//true; alert(person1 instanceof Object);//true; alert(person1.constructor === person2.constructor);//ture; 虽然构造函数方式比较不错,但也存在缺点,那就是在创建对象时,特别针对对象的属性指向函数时,会重复的创建函数实例,以上述代码为基础,可以改写为:

function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.getName = new Function () {//改写后效果与原代码相同,不过是为了方便理解 return this.name; } } 上述代码,创建多个实例时,会重复调用new Function();创建多个函数实例,这些函数实例还不是一个作用域中,当然这一般不会有错,但这会造成内存浪费。当然,可以在函数中定义一个getName = getName的引用,而getName函数在Person外定义,这样可以解决重复创建函数实例问题,但在效果上并没有起到封装的效果,如下所示: function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.getName = getName; } function getName() {//到处是代码,看着乱!! return this.name; } 3、原型模式

 JS每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,它是所有通过new操作符使用函数创建的实例的原型对象。原型对象最大特点是,所有对象实例共享它所包含的属性和方法,也就是说,所有在原型对象中创建的属性或方法都直接被所有对象实例共享。

function Person(){ } Person.prototype.name = 'Jack';//使用原型来添加属性 Person.prototype.age = 29; Person.prototype.getName = function(){ return this.name; } var person1 = new Person(); alert(person1.getName());//Jack var person2 = new Person(); alert(person1.getName === person2.getName);//true;共享一个原型对象的方法 原型是指向原型对象的,这个原型对象与构造函数没有太大关系,唯一的关系是函数的prototype是指向这个原型对象!而基于构造函数创建的对象实例也包含一个内部指针为:[[prototype]]指向原型对象。

   实例属性或方法的访问过程是一次搜索过程:

首先从对象实例本身开始,如果找到属性就直接返回该属性值; 如果实例本身不存在要查找属性,就继续搜索指针指向的原型对象,在其中查找给定名字的属性,如果有就返回; 基于以上分析,原型模式创建的对象实例,其属性是共享原型对象的;但也可以自己实例中再进行定义,在查找时,就不从原型对象获取,而是根据搜索原则,得到本实例的返回;简单来说,就是实例中属性会屏蔽原型对象中的属性;

 原型与in操作符
 一句话:无论原型中属性,还是对象实例的属性,都可以使用in操作符访问到;要想判断是否是实例本身的属性可以使用object.hasOwnProperty(‘attr’)来判断;

 原生对象中原型
 原生对象中原型与普通对象的原型一样,可以添加/修改属性或方法,如以下代码为所有字符串对象添加去左右空白原型方法:

String.prototype.trim = function(){ return this.replace(/^\s+/,'').replace(/\s+$/,''); } var str = ' word space '; alert('!'+str.trim()+'!');//!word space! 原型模式的缺点,它省略了为构造函数传递初始化参数,这在一定程序带来不便;另外,最主要是当对象的属性是引用类型时,它的值是不变的,总是引用同一个外部对象,所有实例对该对象的操作都会其它实例:

function Person() { } Person.prototype.name = 'Jack'; Person.prototype.lessons = ['Math','Physics']; var person1 = new Person(); person1.lessons.push('Biology'); var person2 = new Person(); alert(person2.lessons);//Math,Physics,Biology,person1修改影响了person2 4、组合构造函数及原型模式

  目前最为常用的定义类型方式,是组合构造函数模式与原型模式。构造函数模式用于定义实例的属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方方法的引用,最大限度的节约内存。此外,组合模式还支持向构造函数传递参数,可谓是集两家之所长。

function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.lessons = ['Math', 'Physics']; } Person.prototype = { constructor: Person,//原型字面量方式会将对象的constructor变为Object,此外强制指回Person getName: function () { return this.name; } } var person1 = new Person('Jack', 19, 'SoftWare Engneer'); person1.lessons.push('Biology'); var person2 = new Person('Lily', 39, 'Mechanical Engneer'); alert(person1.lessons);//Math,Physics,Biology alert(person2.lessons);//Math,Physics alert(person1.getName === person2.getName);//true,//共享原型中定义方法

在所接触的JS库中,jQuery类型的封装就是使用组合模式来实例的!!!

5、动态原型模式
 组合模式中实例属性与共享方法(由原型定义)是分离的,这与纯面向对象语言不太一致;动态原型模式将所有构造信息都封装在构造函数中,又保持了组合的优点。其原理就是通过判断构造函数的原型中是否已经定义了共享的方法或属性,如果没有则定义,否则不再执行定义过程。该方式只原型上方法或属性只定义一次,且将所有构造过程都封装在构造函数中,对原型所做的修改能立即体现所有实例中:

function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.lessons = ['Math', 'Physics']; } if (typeof this.getName != 'function') {//通过判断实例封装   Person.prototype = {     constructor: Person,//原型字面量方式会将对象的constructor变为Object,此外强制指回Person     getName: function () {       return this.name;     }   } } var person1 = new Person('Jack', 19, 'SoftWare Engneer'); person1.lessons.push('Biology'); var person2 = new Person('Lily', 39, 'Mechanical Engneer'); alert(person1.lessons);//Math,Physics,Biology alert(person2.lessons);//Math,Physics alert(person1.getName === person2.getName);//true,//共享原型中定义方法 注:以上内容参考《JavaScript 高级程序设计》第3版

© 著作权归作者所有

共有 人打赏支持
告别只是另一种体验
粉丝 5
博文 29
码字总数 28415
作品 0
浦东
前端工程师
面向对象,更适合JavaScript

面向对象程序设计是软件开发中一个很庞大很复杂的话题,它并不是仅仅学会类、继承、封装、多态这些面向对象编程语法元素就表示掌握的,这些语法元素只是实现面向对象程序的工具, 就像砖块、...

陈宏鸿 ⋅ 05/07 ⋅ 0

AJAX基础之JavaScript基础与增强(一)

一、什么是JavaScript   JavaScript是一种基于对象(Object)和事件驱动(Event Driven)并具有安全性能的脚本语言。使用它的目的是与HTML超文本标记语言、Java 脚本语言(Java小程序)一起实现...

architect刘源源 ⋅ 05/08 ⋅ 0

PHP学习路线图 最全PHP自学指南

对于广大零基础的PHP自学者,往往不知道如何系统的学习PHP,导致平白浪费了很多时间。本文将为大家带来最详细的php学习路线图,同时还会附上相应的权威教程,让广大PHP自学者少走许多弯路。 ...

W3Cschool小编 ⋅ 04/24 ⋅ 0

开源书籍-JavaScript 编程精解

《JavaScript 编程精解》(Eloquent JavaScript)第三版,是由马尔奇·哈弗贝克(Marlin Haverbeke)JavaScript程序员编写的JS入门书籍,Marlin Haverbeke通晓多种编程语言,在Web开发方面积累...

marsdream ⋅ 06/04 ⋅ 0

第一章--JavaScript简介

1. JavaScript的构成 1.1. ECMAScript ECMAScript规定了核心语言的组成部分分别为:语法、类型、语句、关键字、保留字、操作符、对象。 宿主环境:Web浏览器、Node、Adobe Flash。 1.2. DOM...

lovewt ⋅ 06/05 ⋅ 0

JavaScript 编程精解 中文第三版 零、前言

零、前言 原文:Introduction 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《JavaScript 编程精解(第 2 版)》 We think we are creating the system for our own purp...

ApacheCN_飞龙 ⋅ 06/01 ⋅ 0

JavaScript 参考手册

JavaScript 参考手册 http://www.w3school.com.cn/jsref/index.asp 本部分提供完整的 JavaScript 参考手册: JavaScript 本地对象和内置对象 Browser 对象(BOM) HTML DOM 对象 JavaScript...

chenhao_asd ⋅ 05/25 ⋅ 0

JavaScript中的this指针 理论化this指针的定义

JavaScript现在应用之广泛,远超其他任何语言,只要是一个合格的网站应用,基本上多多少少都会有JS的存在。在JavaScript中,this的指向被不少Coder所不解,但其实JS中的this理解起来也是相当...

superwebmaster ⋅ 05/29 ⋅ 0

关于js的bind牌胶水,了解一下?

前言 今天聊一聊js中的bind方法,主要从三个维度来阐述:why——>what——>how。文章虽经个人多次校验,对语言表述、代码书写等进行了认真审核,但仍免不了有疏漏之处,如若发现,还望指出,...

hanmin ⋅ 05/14 ⋅ 0

从JS对象开始,谈一谈“不可变数据”和函数式编程

文章转载自:https://segmentfault.com/a/1190000008780076 作为前端开发者,你会感受到JS中对象(Object)这个概念的强大。我们说“JS中一切皆对象”。最核心的特性,例如从String,到数组,再...

朱先忠老师 ⋅ 05/20 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

【新功能】企业级Maven私有仓库服务结束公测,全面开放使用

摘要: 目前云效上线了企业级Maven私有仓库服务。用户可以一键开通Maven私有仓库服务,零配置实现私有二方库的上传和下载。 经过半个月的公测,云效中的企业级Maven私有仓库服务正式上线,全...

阿里云云栖社区 ⋅ 12分钟前 ⋅ 0

elasticsearch使用more_like_this实现基于内容的推荐

官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-mlt-query.html 基于内容的推荐通常是给定一篇文档信息,然后给用户推荐与该文档相识的文档。Lucene的a...

xiaomin0322 ⋅ 15分钟前 ⋅ 0

Spring Boot更改Banner

Spring Boot 1.0 中如何更换启动 Banner,其实都很简单,只需要在src/main/resources路径下新建一个banner.txt文件,banner.txt中填写好需要打印的字符串内容即可。 一般情况下,我们会借助第...

Clarence_D ⋅ 19分钟前 ⋅ 0

谷歌浏览器下,去掉input输入记录提示框

谷歌浏览器在记住密码后,在input获取焦点的时候就会有输入提示框,如: 有时候我们在输入用户名时,我们自己有ajax的下拉展示列表,那么此时的历史提示输入框就影响交互和用户体检,解决的方...

莫西摩西 ⋅ 21分钟前 ⋅ 0

dlna流媒体服务搭建

简介 DLNA的全称是DIGITAL LIVING NETWORK ALLIANCE(数字生活网络联盟), 其宗旨是Enjoy your music, photos and videos, anywhere anytime, DLNA(Digital Living Network Alliance) 由索尼......

啊哼哼 ⋅ 27分钟前 ⋅ 0

Python10大好用的集成开发环境简析

  Python IDE工具是每个Python工程师必须使用的开发工具,选择正确的编辑器对Python编程效率的影响是非常大的,因此选择合适的Python开发工具十分重要,以下是通过长期实践发掘的好用的Pyt...

老男孩Linux培训 ⋅ 28分钟前 ⋅ 0

happybase(TSocket read 0 bytes)

关于报错 happybase 是使用python连接hbase的一个第三方库,目前基于thrift1 。在使用过程中经常碰到报错 TTransportException(type=4, message='TSocket read 0 bytes') 即使使用thrift se...

zhnxin ⋅ 29分钟前 ⋅ 0

手写简单RPC

1. 获取接口对应的实现类 package com.rpc.server.util; import java.io.File; import java.net.URL; import com.alibaba.fastjson.JSON; public class ClassUtils { public static Object ......

徐志 ⋅ 29分钟前 ⋅ 0

nginx服务器的gzip压缩

四、服务器的gzip压缩 1.ngx_http_gzip_module模块处理的9个指令 在处理时实时压缩 1>gzip on|off 开启或关闭gzip功能 2>gzip_buffers number size 用于设置文件使用缓存...

余温灬未存 ⋅ 31分钟前 ⋅ 0

前端程序员:月薪 5K 到 5 万,我干了啥

高贵的前端程序猿们: 如何在前端开发这种高精尖的技术领域找到心仪的工作?实现在咖啡馆喝喝咖啡敲敲代码就能升职加薪、买房买车、迎娶白富美走上人生巅峰的职业梦想?这 篇《进化论:从 0 ...

Mr_zebra ⋅ 33分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部