理解对象的概念  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高程笔记-------第六章 面向对象的程序设计的更多相关文章

  1. JavaScript高级程序设计学习笔记第六章--面向对象程序设计

    1.ECMAScript没有类的概念,ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”,有点类似于散列表 2.ECMAScript 中有两种属性:数据属性和访问 ...

  2. JAVASCRIPT高程笔记-------第五章 引用类型

    一.Object类型 1.1创建方式 ①new关键字 : var person = new Oject(); ②给定直接量: var person = { name : "zhangsan& ...

  3. javascript高程笔记-------第四章 变量、作用域和内存问题

    首先JavaScript中的变量分为基本类型和引用类型. 基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象. 1.参数传递 javascript中所有参数的传递都是值传 ...

  4. JavaScript高级程序设计-第六章面向对象的程序设计

    创建对象主要的两种形式,创建Object实例和创建对象字面量 对象包含属性和方法 数据 .属性有四个特性,特性是为了描述属性行为的,他们是: Configurable(可配置的)是否能删除或是否能修改 ...

  5. JAVASCRIPT高程笔记-------第 七章 函数表达式

    7.1递归 经典递归例子 function factorial(num){ if(num <= 1){ return 1; }else{ return num * factorial(num - ...

  6. 读书笔记 - js高级程序设计 - 第六章 面向对象的程序设计

      EcmaScript有两种属性 数据属性 和 访问器属性 数据属性有4个特性 Configurable Enumerable Writable Value   前三个值的默认值都为false   ...

  7. 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承

    ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...

  8. javascript高级程序设计第3版——第6章 面向对象的程序设计

    第六章——面向对象的程序设计 这一章主要讲述了:面向对象的语言由于没有类/接口情况下工作的几种模式以及面向对象语言的继承: 模式:工厂模式,构造函数模式,原型模式 继承:原型式继承,寄生式继承,以及寄 ...

  9. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

随机推荐

  1. [RxJS] Use RxJS concatMap to map and concat high order observables

    Like switchMap and mergeMap, concatMap is a shortcut for map() followed by a concatAll(). In this le ...

  2. php实现 坐标移动

    php实现  坐标移动 一.总结 一句话总结:伪代码,带函数逻辑,函数这样的方式写算法程序会节约超多的时间. 1.为什么算法题数据输入最好用多组数据输入的方式? 因为都是多组数据测试,而且多组数据输入 ...

  3. href="javascript:;" href="javascript:void(0);" href="#"区别

    一.href="javascript:;" 这种用法不正确,这么用的话会出现浏览器访问"javascript:;"这个地址的现象: 二.href="j ...

  4. Android菜鸟的成长笔记(26)——普通广播与有序广播

    BroadcastReceiver是Android系统的四大组件之一,BroadcastReceiver是一个全局的系统级监听器,它拥有自己的独立进程. 我们来写一个最简单的广播接收过程 先在mani ...

  5. javascript 验证附件大小

    ///验证单个文件不能超过30M function onChangeFile() { ///定义布尔类型的返回结果,初始值为false(默认不超过30M) var sResult = false; / ...

  6. Shell脚本实现超简洁的在Linux服务器上安装nginx、resin、java、tomcat、redis等程序

    说明: 用平常的方式在Linux服务器上安装程序,需要下载安装包.进入安装包位置.给安装包文件赋予可执行权限.执行安装.设置环境变量--等等一系列复杂的操作.并且如果有关联也需要一个一个的挨着安装.耗 ...

  7. 【64.52%】【codeforces 697D】Puzzles

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  8. Android官方教程翻译(6)——添加ActionBar

    The action bar allows you to add buttons for the most important action items relating to the app's c ...

  9. sql server通过脚本添加链接服务器

    exec sp_addlinkedserver  'ZZSJK','','SQLOLEDB','192.168.10.22'  --链接服务器名称 ‘’ ip地址exec sp_addlinkedsr ...

  10. 解决android模拟器无法上网问题

    1.  将 android的tool增加到,windows 环境变量 path中, D:\Android\android-sdk_r3-windows\android-sdk-windows\tool ...