《JavaScript高级程序设计》第6章 面向对象程序设计
6.1 对象属性
6.1.1 属性类型
1. 数据属性
我们一般所说的属性就是数据属性,它用来将一个字符串名称映射到某个值上
数据属性的4个特性: configurable, enumerable, writable, value
要修改属性默认的特性,必须使用Object.defineProperty()方法
Object.defineProperty(对象,属性名,描述符对象)
var person = {};
Object.defineProperty(person, 'name', {
writable: false,
value: 'natsu'
});
console.log(person.name);
person.name = 'natsu12';
console.log(person.name); // 非严格模式下被忽略,严格模式下抛出错误
把configurable设置为false后,不能再修改除writable之外的特性
var person = {};
Object.defineProperty(person, 'name', {
configurable: false
});
Object.defineProperty(person, 'name', { // 抛出错误
configurable: true
});
2. 访问器属性
访问器属性不能直接定义,必须使用Object.defineProperty来定义,定义了get和set特性的属性即成为访问器属性。
在读取访问器属性的时候会调用getter函数,在写入访问器属性的时候会调用setter函数并传入新值。
访问器属性的4个特性: configurable, enumerable, get, set
只指定get函数意味着属性只能读不能写
/* 以下实例当修改访问器属性year时会导致数据属性_year和edition的变化 */
var book = {
_year: 2014,
edtion: 1
}; Object.defineProperty(book, 'year', {
get: function() {
return this._year;
},
set: function(newValue) {
if (newValue > 2014) {
this._year = newValue;
this.edtion = newValue - 2013;
}
}
}); console.log(book.year); // 读year的时候调用get函数,2014
book.year = 2015; // 写year的时候调用set函数
console.log(book.edtion); //
6.2 创建对象
6.2.1 工厂模式
这种模式抽象了创建具体对象的过程,虽然解决了创建多个相似对象的问题,却没有解决对象识别的问题(即怎样知道一个对象的类型)。
function createPerson (name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
console.log(this.name);
};
return o;
}
var person1 = createPerson('Nicholas', 29, 'Software Engineer');
person1.sayName(); // Nicholas
6.2.2 构造函数模式
要创建Person的新实例,必须使用new操作符,这种调用构造函数方式实际上经历以下四个步骤:
1.创建一个新对象;
2.将构造函数的作用域赋给新对象(因此this指向这个新对象)
3.执行构造函数中的代码(为这个新对象添加属性)
4.返回新对象
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
};
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');
/* 创造的对象都有一个constructor属性,指向构造函数 */
console.log(person1.constructor == Person); // true
/* 创建的对象既是Person的实例,也是Object的实例,因为所有对象均继承自Object */
console.log(person1 instanceof Person); // true
console.log(person1 instanceof Object); // true
创建自定义的构造函数意味这将来可以将它的实例标识为一种特定类型,而这正是构造函数模式胜过工厂模式的地方(工厂模式无法知道对象的类型)。
构造函数的的多重身份
构造函数也是函数,通过new操作符来调用,它就可以作为构造函数,如果不通过new来调用,则跟普通函数没有区别。
// 当作构造函数使用
var person = new Person('Nicholas', 29, 'Software Engineer');
person.sayName(); // "Nicholas"
// 当作普通函数使用
Person('Greg', 27, 'Doctor'); // 严格模式下会报错,非严格模式下this绑定到window对象
window.sayName(); // "Greg"
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, 'Kristen', 25, 'Nurse');
o.sayName(); // "Kistten"
构造函数模式的问题
构造函数模式的每个方法都要在每个实例上重新创建一遍,然而创建两个完成同样任务的函数实例是没有必要的(浪费空间)。
console.log(person1.sayName == person2.sayName); // false
// 说明不同实例上的同名函数是不相等的,但它们是完成同样任务的函数
6.2.3 原型模式
通过原型模式创建的实例,会共享原型对象中的所有属性和方法。
function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
console.log(this.name);
};
var person1 = new Person();
var person2 = new Person();
console.log(person1.sayName == person2.sayName); // true
只要创建了一个新函数,就会为该函数自动增加一个prototype属性,指向该函数的原型对象。
该原型对象拥有一个constructor属性,反指回这个新函数,初始时原型对象只取得constructor属性,其他方法从Object继承而来。
调用构造函数创建一个新实例后,会为该实例自动增加一个__proto__属性,指向构造函数的原型对象。
上面的例子中,两个person实例都不包含属性和方法,却可以调用sayName,是通过原型对象查找对象属性来实现的。
在读取某个对象的属性时,首先从对象实例本身开始搜索,然后继续搜索__proto__指向的原型对象。
如果我们在实例中添加一个同名属性,则该属性会屏蔽原型中的那个属性。
function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
console.log(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
person1.sayName(); // "Greg"——来自实例
person2.sayName(); // "Nicholas"——来自原型
使用hasOwnProperty()方法可以判断属性是不是实例属性,如果属性是对象自身的实例属性则返回true,如果是来自原型对象则返回false。
// 接上面的例子
console.log(person1.hasOwnProperty("name")); // true
console.log(person2.hasOwnProperty("name")); // false
delete person1.name;
person1.sayName(); // "Nicholas"——来自原型
console.log(person1.hasOwnProperty("name")); // false
in操作符(propertyName in object):只要通过对象能够访问到某个属性就返回true,无论是直接在对向上访问到的,还是通过原型访问到的。
for in:可以遍历所有通过对象访问的(包括实例和原型)、可枚举的属性。
原型的动态性:
可以随时为原型添加属性和方法,对原型对象所做的任何修改都能够立即从实例上反映出来。
请注意,重写原型对象会导致切断现有原型与之前任何已经存在的对象实例之间的联系。

原型对象的问题:当包含引用类型值的属性时,所有实例都被迫共享。
例如某个属性friends是数组,当调用person1.friends.push增加一个元素时,person2.friends也会跟着修改。
6.2.4 组合使用构造函数模式和原型模式
最常见的方式,构造函数模式用于定义实例属性(每个实例自己独有,不共享),而原型模式用于定义方法和共享的属性。
6.2.5 动态原型模式
将所有信息都封装在了构造函数中,在构造函数中初始化原型。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
if (typeof this.sayName != "functin") {
// 在sayName方法不存在的情况下,才将它添加到原型中
Person.prototype.sayName = function () {
console.log(this.name);
}
}
}
上面的代码中,给原型添加sayName方法只有在初次调用构造函数时才会执行。
《JavaScript高级程序设计》第6章 面向对象程序设计的更多相关文章
- JavaScript高级程序设计 第六章 面向对象程序设计
面向对象程序设计 ECMA-262将对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”严格来讲,这就相当于说对象是一组没有特定顺序的值.对象的每个属性和方法都有一个名字,而每个名字都 ...
- 零基础学Python--------第7章 面向对象程序设计
第7章 面向对象程序设计 7.1 面向对象概述 面向对象(Object Oriented)的英文缩写是OO,它是一种设计思想.从20世纪60年代提出面向对象的概念到现在,它已经发展成为一种比较成熟的编 ...
- 20175316 盛茂淞 2018-2019-2 《Java程序设计》实验二 面向对象程序设计 实验报告
20175316 盛茂淞 2018-2019-2 <Java程序设计>实验二 面向对象程序设计 实验报告 (一)单元测试 在 IDEA中我们把产品代码放在src目录中,把测试代码放在tes ...
- 20165222《Java程序设计》——实验二 面向对象程序设计
20165222<Java程序设计>——实验二 面向对象程序设计 提交点一.JUnit测试用例 知识点:这里就是了解测试代码的应用,测试代码的书写为:@Test assertEquals( ...
- C++ Primer 5th 第15章 面向对象程序设计
面向对象程序设计的核心思想是:数据抽象.继承和动态绑定. 数据抽象:将类的接口与实现分离: 继承:定义相似类型并对相似关系建模: 动态绑定:一定程度上上忽略相似类型间的区别,用同一方式使用它们. 1. ...
- [C++ Primer] : 第15章: 面向对象程序设计
OOP: 概述 面向对象程序设计的核心思想是数据抽象, 继承和动态绑定. 通过数据抽象, 我们可以实现类的接口与实现的分离; 使用继承, 可以定义相似的类型并对其相似关系建模; 使用动态绑定, 可以在 ...
- 【c++ Prime 学习笔记】第15章 面向对象程序设计
15.1 OOP:概述 面向对象程序设计(object-oriented programming)的核心思想是:数据抽象.继承.动态绑定 使用数据抽象,可将类的接口与实现分离 使用继承,可定义相似的类 ...
- Java程序设计 实验二 Java面向对象程序设计
北京电子科技学院(BESTI) 实 验 报 告 课程:Java程序设计 班级:1353 姓名:李海空 学号:20135329 成绩: 指导教师:娄嘉鹏 ...
- JavaScript高级程序设计学习笔记第六章--面向对象程序设计
1.ECMAScript没有类的概念,ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”,有点类似于散列表 2.ECMAScript 中有两种属性:数据属性和访问 ...
- JavaScript高级程序设计-第六章面向对象的程序设计
创建对象主要的两种形式,创建Object实例和创建对象字面量 对象包含属性和方法 数据 .属性有四个特性,特性是为了描述属性行为的,他们是: Configurable(可配置的)是否能删除或是否能修改 ...
随机推荐
- SQLServer附加数据库5120错误
装有MSSQL的电脑 需要附加的数据库文件(*.mdf)及其日志文件(*.ldf) 1. 打开SQL Server Management Studio,并连接上数据库.右键"数据库" ...
- Knockout.Js官网学习(text绑定)
前言 text 绑定到DOM元素上,使得该元素显示的文本值为你绑定的参数.该绑定在显示<span>或者<em>上非常有用,但是你可以用在任何元素上. 简单绑定 Today's ...
- Eruda——手机网页前端调试面板
前言 进行移动端网页开发时,想要查看手机浏览器信息从来都不是一件容易的事.特别是当目标环境为APP内置WebView,需要调用特定的JsBridge接口时,你根本都干不了什么,只能一遍又一遍地修改代码 ...
- nginx php 安装
.选定源码目录选定目录 /data/klj/ cd /data/klj/ 2.安装PCRE库cd /data/klj/wget ftp://ftp.csx.cam.ac.uk/pub/software ...
- char引发的血案
char cc = 'j';cc = (char)(cc -32); //注意下,自动转型了System.out.println(cc);
- windows7安装IE11点击图标没反应
可以通过修改 Windows 注册表的方式解决: Win+R 打开“运行”后输入 regedit 打开 注册表编辑器 打开注册表编辑器(regedit)以后,找到注册表项HKEY_CURRENT_US ...
- 百度 UEditor 简单安装调试和调用,网上其它的教程太官方了,不适合新手
对于新手来说,只要能实现功能即可,其它设置完全默认. 预览图: 1.首先 到官网下载,这个不多说.下载后解压到网站你想要的目录,我这里放到根目录下在你需要使用编辑器的地方,插入如下HTML代码: &l ...
- [下载] VS 2013 Update 4 & 社群版 (Visual Studio Community) & VS 2015 Preview预览版
这是我的备份,原文请看http://www.dotblogs.com.tw/mis2000lab/archive/2014/11/13/vs2013_update4_community_vs2015_ ...
- 【摘抄】Application.StartupPath和System.Environment.CurrentDirectory的区别
System.Environment.CurrentDirectory的含义是获取或设置当前工作路径,而Application.StartupPath是获取程序启动路径,表面上看二者没什么区别,但实际 ...
- Java4Android
变量 在计算机中存储信息需要声明变量的位置和所需的内存空间 boolean true false char ASCII字符集 计算机中所有数据都使用二进制表示 例如:a,b,c 适用七位二进制数进行表 ...