JAVASCRIPT高程笔记-------第六章 面向对象的程序设计
理解对象的概念 js中的对象与其他 编程语言中的类不一样 ECMAscript 没有类的概念 ECMA-262 把对象定义为 “无序属性的集合,其属性可以包含基本值,对象或者函数” 也就是键值对 可以理解成散列表 示例简单的创建一个对象
var person = new Object();
person.name = "zhangsan"
person.age = 20;
person.sayhi = function (){
return "myName is "+this.name;
}
alert(person.sayhi()); // myName is zhangsan
6.1 属性类型 ---ECMAscript包含两种属性: 数据属性和访问器属性
6.1.1数据属性 ---简单来理解就是 描述对象属性的属性 相当于java中的元数据信息
[[Configgurable]] 表示属性是否可以通过delete 删除属性 从而重新定义属性 或者能否将属性修改为访问器属性 示例中定义的person对象的name、age以及sayhi()方法 默认都是为true
[[Enumerable]] 表示对象的该属性是否可以通过 for-in循环返回该属性 示例中 定义的person对象的name、age以及sayhi()方法 默认都是为true
[[Waitable]] 表示能否修改 该对象的属性的值 相当于java中 final 关键字修饰的常量 示例中 定义的person对象的name、age以及sayhi()方法 默认都是为true
[[Value]] 表示 该对象属性的实际值 例如示例中 person.name 的实际值就是等于"zhangsan" 这个特性的的值默认为undefined
r如何修改对象属性默认的特性 则必须使用ECMAscript5的 Object.defineProperty()方法 此方法接收三个参数 第一个参数为对象 第二个参数为对象的属性,第三个参数为对象属性的描述 示例
var person ={};
Object.defineProperty(person,'name',{
writable: false, //设置person对象的name属性为只读
configurable: true,
Enumerable: true,
value: "zhangsan"
});
alert(person.name); // ‘zhangsan’
person.name = 'lisi'; //因为person对象name属性已经变成只读 所以此处修改无效,并且在严格模式下的js解析将会报错
alert(person.name); // ‘zhangsan’
Object.defineProperty(person,'name',{
writable: true,
configurable: true,
Enumerable: true,
value: "zhangsan"
}); person.name = 'lisi';
alert(person.name); // lisi
当对象属性的 [[Configgurable]] 特性 被修改后 将 无法还原 因为再次修改时会报错
6.1.2 访问器属性 -----相当于java中的属性私有化 提供get和set方法 示例
var person ={
name : 'zhangsan',
_age: 25
};
Object.defineProperty(person,'age',{
get : function(){
return this._age;
},
set : function(newValue){
if(newValue>0){
this._age = newValue;
}
}
});
alert(person.age); //
person.age = -18; //由于设定了年龄不能为负数 所以此处的修改无效
alert(person.age); //
get和set 属性 也可以单独 设置 但若只设置了get 那么意味着该属性为只读 而不能写入 严格模式下 尝试写入操作则会报错
6.1.3 获取对象属性的特性描述 ECMAscript5中 可以设置对象属性的特性,亦可以通过 Object.getOwnPropertyDescriptor()方法来获取这些 特性信息 该方法返回的是一个对象 如果是访问器属性 则这个对象的属性为 configurable、enumerable、get和set 如果是 数据属性 则为 configurable、enumerable、waitable、value
6.2创建对象 简单理解成java中自定义对象
//工厂模式创建对象
function createPerson(name,age){
var o = new Object();
o.name = name;
o.age = age;
o.sayhi = function(){
alert('my name is ' + this.name);
}
return o;
}
var person1 = createPerson('zhangsan',27);
var person2 = createPerson('lisi',25);
//---------缺点 无法指定对象的类型------------------------ //构造函数模式 为了表示与普通函数的区别 函数首字母大写
function Person(name,age){
this.name = name;
this.age = age;
this.sayhi = function(){
alert('my name is ' + this.name);
}
}
var person1 = new Person('zhangsan',27);
var person2 = new Person('lisi',25);
构造函数与工厂模式创建对象的最大区别 就是 对象的类型鉴别
通过工厂模式创建的对象一定是Object类型 而通过构造函数创建的对象 既属于Object对象类型 也属于自定义对象类型 因为任何对象都是由Object对象继承而来的
构造函数模式创建对象带来的问题 由于每个函数都是一个特殊对象 因此person1和 person2的sayhi方法实际上引用了2个不同的对象 而只完成了相同的事情 就是告诉别人我叫啥 当 存在N个person对象的同时 也存在 N个sayh 对象 造成内存浪费
为解决这个问题 ------- 原型模式
function PersonF(name,age){
this.name = name;
this.age = age;
this.sayhi = function(){
alert('my name is ' + this.name);
};
}
var person1 = new PersonF('zhangsan',27);
var person2 = new PersonF('lisi',25);
alert(person1.sayhi === person2.sayhi); // false 因为每创建一个新的person对象 然后也创建了一个新的sayhi函数对象 所以他们不相等 //原型模式
function PersonP(name,age){
this.name = name;
this.age = age; }
PersonP.prototype.sayhi= function(){
alert('my name is ' + this.name);
}
var person1 = new PersonP('zhangsan',27);
var person2 = new PersonP('lisi',25);
alert(person1.sayhi === person2.sayhi) // true 原型模式下 所有被创建的person对象 将共享sayhi函数对象,所以这里相等
无论任何时候创建一个新的函数 js解析器默认会创建这个函数的prototype对象 默认情况下 这个prototype只包含 函数的构造器constructor属性 而其他方法 都是从Object继承而来 或者 后期手动添加进去 例如示例中我们给PersonP()这个对象的prototype中添加了sayhi方法
当一个实例对象中添加了与原型中重名方法时 则实际使用的是实例对象中的方法 ------相当于java的子类重写父类方法 示例
//原型模式
function PersonP(name,age){
this.name = name;
this.age = age;
}
PersonP.prototype.sayhi= function(){
alert('my name is ' + this.name);
}
var person1 = new PersonP('zhangsan',);
var person2 = new PersonP('lisi',);
person1.sayhi(); // my name is zhangsan 来自于原型中的sayhi方法
person1.sayhi = function(){ //修改当前实例对象的sayhi方法
alert("my age = " + this.age);
};
person1.sayhi(); // my age = 27 来自于当前实例中的sayhi方法 alert(person1.hasOwnProperty("sayhi")); // true 此方法是person1对象实例的方法
alert(person2.hasOwnProperty("sayhi")); // false 此方法来自PersonP 原型中
hasOwnProperty() 检测对象的方法是由原型继承而来还是属于本身实例
原型与in操作符
in 操作符 用于判断 某个属性 是否 属于 指定 对象 示例 alert(('name' in person1)); // 执行结果为true in 操作符 不管对象的属性 是实例对象本身的属性 还是由原型中继承而来 都会返回true
for-in 循环 时 返回的都是能通过对象访问的、可以枚举的属性 ,也包括原型中存在的属性 首先遍历的是对象构造函数内的属性 然后再往原型中查找属性
function PersonP(name,age){
this.name = name;
this.age = age;
this.sayhi= function(){
alert('my name is ' + this.name);
}
}
PersonP.prototype.saybay= function(){
alert('my name is ' + this.name);
}
var person2 = new PersonP('lisi',);
person2.money = ;
for(var property in person2){
console.log(property); // 结果 name age sayhi money saybay 依次出现
}
var propertys = Object.keys(person2);
console.log(propertys); // 结果 ["name", "age", "sayhi", "money"]
Object.keys() 方法 接收一个对象参数 返回该对象上所有可枚举的属性
利用原型创建对象的简写方式
function PersonP(){
}
PersonP.prototype ={
constructor : PersonP, // 此属性表明构造器 为 PersonP 对象的构造器 否则PersonP构造器默认由Object对象继承而来 是属于Object对象的构造器 但是会导致对象的构造器的[[enumerable]]特性 设置为true
name : 'zhangsan',
age : ,
sayhi : function(){
alert('my name is ' + this.name);
}
}
在ECMAscript 5 js解析引擎下 可以重设 对象的对象构造器为不可枚举
Object.definedProperty(PersonP.prototype,'constructor',{
enumerable : false,
value: PersonP
});
原型的动态性 ------js引擎 在原型中查找值的过程是一次搜索 因此 对对象原型的任何修改 都会立即在对象的实例上体现出来
当 对象创建以后 再重写其原型 则会出现 无法调用原有函数的现象 参考示例 原因在于 对象实例原有的原型对象已经被切断与对象联系 因此原型查找时无法获取对象的sayhi方法
function PersonP(){
}
var person1 = new PersonP();
PersonP.prototype = {
constructor : PersonP, // 此属性表明构造器 为 PersonP 对象的构造器 否则PersonP 由于是一个空对象 构造器默认由Object对象继承而来
name : 'zhangsan',
age : ,
sayhi : function(){
alert('my name is ' + this.name);
}
}
person1.sayhi(); // error
6.2.4组合使用构造函数模式和原型模式
将对象私有的属性放在构造函数中,而通用的方法放在原型中 例如 以person为例子 name、age、sex可能因人而已 但都会有打招呼 做自我介绍的方法sayhi方法 是通用的可以放在原型中
动态原型模式
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
if(typeof this.sayhi != 'function'){
Person.prototype.sayhi = function(){
alert(this.name);
}
}
}
寄生构造函数模式----- 与工厂模式一致 在一个对象有多个实例的时候 而其中某一个实例需要特殊处理 ,在不影响其他实例属性数据的情况下可以使用此模式来完成操作 有点类似与java中的包装设计模式
function Person(name,age,sex){
var o = new Object();
o.name = name ;
o.age = age;
o.sex = sex;
o.sayhi =function(){
alert(this.name);
}
return o;
}
稳妥模式---- 没有公共属性,而且其他方法也不引用this对象 ,稳妥对象适合在一些安全的环境中使用(这些环境会禁用this和new) ,感觉像java中常量一样,一旦初始化就不可修改
function Person(name,age,sex){
var o = new Object();
o.sayhi =function(){
alert(name); //不使用this
}
return o;
} var person = Person('zhangsan',18,'男'); //不使用new操作符创建对象
person.sayhi(); //除此方法 之外 没有任何其他方法可以访问 person对象的name属性
6.3 继承
一、原型链式继承 其本质 是重写原型对象,
function SuperType(){
this.property = true; }
SuperType.prototype.getSuperValue = function(){
return this.property;
} function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType(); var sub = new SubType();
alert(sub.getSuperValue()); //true 通过原型继承而来的方法
原型继承注意的问题: 一、共享原型中的属性和方法 二、不能向超类型的构造函数中传递参数
二、借用构造函数
利用 apply() 和 call() 方法在新创建的对象上执行构造函数 此方式可以传递参数给超类的构造函数 问题点 一、不能继承超类原型的属性和方法,二、方法都在构造函数当中,无法实现函数复用
function SuperType(){
this.colors = ['red','blue','green'];
}
function SubType(){
SuperType.call(this);
} var instance1 = new SubType();
instance1.colors.push('black');
alert(instance1.colors); //red,blue,green,black
三、组合式继承 ---又叫做伪经典继承
将原型链和借用构造函数组合到一块 利用原型链继承超类的原型属性和方法,而借用构造函数来实现对实例属性的继承
function SuperType(name){
this.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
alert(this.age);
} var instance1 = new SubType('zhangsan',28);
instance1.colors.push('black');
alert(instance1.colors); //red,blue,green,black 继承自超类的属性
instance1.sayName(); //zhangsan 传递给超类的参数 超类原型中的方法
instance1.sayAge(); //28 自定义的方法
四、原型式继承
先建立一个临时性的构造函数 然后将传入的对象当做这个构造函数的原型,最后返回这个临时类型的新实例 从本质上看 是object对传入对象的一次浅复制
function object(o){
function F(){}
F.prototype = o;
return new F();
}
var person = {
name : 'zhangsan',
friends : ['lisi','wangwu']
}
var anotherPerson = object(person);
anotherPerson.name = 'zhaotiezhu';
anotherPerson.friends.push('zhangxiaohua'); //找了个女朋友赵小花
alert(person.friends); //lisi,wangwu,zhangxiaohua
ECMA5.0 中 新增了 Object.create() 方法 规范了原型式继承 此方法接收两个参数,第一个参数为创建新对象的原型 另外一个用于修饰新对象中元数据的描述(可选)如下面代码
var person = {
name : 'zhangsan',
friends : ['lisi','wangwu']
}
var person1 = Object.create(person);
person1.name = 'lisi';
alert(person1.name);
var person2 = Object.create(person,{
name :{
//writable : false,
value : 'wangwu'
}
}); //第二个参数为新对象的元数据修饰参数 此处由于未设置 person2对象的name属性 为可写的 所以导致 在修改 person2的name属性不成功
alert(person2.name); //wangwu
person2.name = 'zhaoliu';
alert(person2.name); //wangwu
寄生式继承 ----接收一个对象参数 在函数内部对此对象进行增强 然后返回这个函数--------------------------感觉像java中的实现接口????
function createAnother(original){
var clone = object(original);
clone.sayhi = function(){ //
alert("hi");
}
return clone;
}
var person ={
name:'zhangsan',
friends:['lisi','wangwu']
}
var anotherPerson = createAnother(person);
anotherPerson.sayhi(); //hi
6.3.6 寄生组合式继承
组合式继承的缺陷 ---无论任何条件下都需要调用两次超类型的构造函数 第一次为指定子类原型 第二次为子类构造函数中 借用超类的构造函数 第一次调用已经拥有了超类的属性 第二次调用 则是在子类上重新创建了与原型中相同属性 从而屏蔽了原型的属性
寄生组合式继承 通过借用构造函数来继承超类属性,通过原型链的混成形式来继承方法---------此方式体现在只调用一次超类的构造函数 避免了subtype.prototype上面创建多余的属性 ,原型链还能保持不变,因此能够正常使用 instanceof和isPrototypeOf()方法去确定类型
function inheritPrototype(subType,superType){
var prototype = Object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
} function SuperType(name){
this.name = name;
this.friends = ['xiaohua','xiaoming']
} SuperType .prototype.sayhi = function (){
alert(this.name);
} function SubType(name,age){
SuperType.call(this,name);
this.age = age;
} inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
} var person = new SubType('zhangsan',28);
person.friends.push('xiaohong'); //找了个女朋友 小红
person.sayAge(); //
person.sayhi(); //zhangsan
alert(person.friends); //xiaohua,xiaoming,xiaohong
小结 : ECMAscript支持面向对象编程,但没有类和接口的概念 。对象可以在代码执行过程中创建和增强,因此具有动态性而非严格的定义的实体对象,
创建对象 1.工厂模式 定义一个函数 接收指定参数 函数内部创建Object对象 添加传入的参数作为属性,然后返回对象
2.构造函数模式 可以创建自定义引用类型 可以向内置对象一样使用new 操作符 缺点 每个成功都无法得到复用 包括方法
3.原型模式,使用构造函数的prototype属性来指定共有的属性和方法
对象继承 ECMAscript 主要通过原型链实现继承 原型链的构造是将一个实例赋值给另一个构造函数 ,这样通过构造函数 new处理的对象的原型指向超类的实例 实现 属性和方法复用
通常使用 组合式寄生继承 避免了多次调用超类的构造函数 以及属性的唯一性
JAVASCRIPT高程笔记-------第六章 面向对象的程序设计的更多相关文章
- JavaScript高级程序设计学习笔记第六章--面向对象程序设计
1.ECMAScript没有类的概念,ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”,有点类似于散列表 2.ECMAScript 中有两种属性:数据属性和访问 ...
- JAVASCRIPT高程笔记-------第五章 引用类型
一.Object类型 1.1创建方式 ①new关键字 : var person = new Oject(); ②给定直接量: var person = { name : "zhangsan& ...
- javascript高程笔记-------第四章 变量、作用域和内存问题
首先JavaScript中的变量分为基本类型和引用类型. 基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象. 1.参数传递 javascript中所有参数的传递都是值传 ...
- JavaScript高级程序设计-第六章面向对象的程序设计
创建对象主要的两种形式,创建Object实例和创建对象字面量 对象包含属性和方法 数据 .属性有四个特性,特性是为了描述属性行为的,他们是: Configurable(可配置的)是否能删除或是否能修改 ...
- JAVASCRIPT高程笔记-------第 七章 函数表达式
7.1递归 经典递归例子 function factorial(num){ if(num <= 1){ return 1; }else{ return num * factorial(num - ...
- 读书笔记 - js高级程序设计 - 第六章 面向对象的程序设计
EcmaScript有两种属性 数据属性 和 访问器属性 数据属性有4个特性 Configurable Enumerable Writable Value 前三个值的默认值都为false ...
- 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承
ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...
- javascript高级程序设计第3版——第6章 面向对象的程序设计
第六章——面向对象的程序设计 这一章主要讲述了:面向对象的语言由于没有类/接口情况下工作的几种模式以及面向对象语言的继承: 模式:工厂模式,构造函数模式,原型模式 继承:原型式继承,寄生式继承,以及寄 ...
- Android群英传笔记——第六章:Android绘图机制与处理技巧
Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...
随机推荐
- XML输出到浏览器报错
在使用Firefox浏览器测试我编写的xml文件时,遇到如下错误:我的xml源代码如下: <?xml version="1.0" encoding="UTF-8&q ...
- js进阶 11-13 jquery如何包裹元素和去除元素外的包裹
js进阶 11-13 jquery如何包裹元素和去除元素外的包裹 一.总结 一句话总结:wrap().wrapAll().unwrap().innerWrap()四个方法 1.jquery中unwr ...
- USACO--2.1The Castle
思路:这个题目难在建图,開始的时候我想把每一个房间没有墙的面求出来,然后再和他邻近的房间加上一条边进行建图,后面发现要通过题目给定的条件求出房间那个面没有墙是十分困难的:后面參考了别人的思路,我们记录 ...
- Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能
最近老大要求做一个类米聊的app,于是就去找解决方案,首先用Android本身的MediaRecorder肯定是不行的,只支持amr,wav,acc,如果要做到Android,Iphone,pc通用的 ...
- [React Router v4] Render Nested Routes
With React Router v4 the entire library is built as a series of React components. That means that cr ...
- [NPM] Run npm scripts in parallel
In this lesson we will look at running several npm scripts in parallel. Sometimes you don’t need scr ...
- C#-numericUpDown-数字选择---ShinePans
program.cs using System; using System.Collections.Generic; using System.Linq; using System.Windows.F ...
- ITFriend创业败局(一):选择创业方向和寻找合伙人,创业失败的2个关键点
这次创业惨淡收场,最主要的原因是没有选择一个合适的创业方向,没有找到合适的创业合伙人. 首先要说到创业方向,因为不同的创业方向需要组建不同的创业团队.我个人比较偏好,软件.网络.互联网等有一 ...
- Hibernate的数据操作(4.*以上版本)
Hibernate的基本数据操作 适用于4.* ..sessionFactory的创建区别 public class NewsTest { private Session session = null ...
- eclipse 编写scala代码时提示computing additional info
window->proference,把方框中那两个选项去掉不选,保存即可(或者只选择scala completions(java sources)),(只不过这么做之后就没有代码提示了)遇到这 ...