面向对象的程序设计

一,理解对象
1,属性类型
  1)数据属性(为了表示数据是内部值放在[[]]之内)
    [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特征,能否把属性修改为访问器属性
    [[Enumerable]]:表示能否通过for-in循环返回属性
    [[Writable]]:表示能否修改属性的值
    [[Value]]:包含这个属性的数据值,默认值为undefined
    object.defineProperty(属性所在的对象,属性的名字,描述符对象) 修改属性默认的特性,
    el:var person = {};
    Object.defineProperty(person,name,{writable:false;value:zhang;enumerable:false;});
    一旦属性定义为不可配置的,就不能再改变回来为可配置的了
  2)访问器属性
  访问器属性不包含数据值,包含一对getter和setter函数(不是必须的)读取时调用getter函数,写入时调用setter函数
  [[Configurable]]:表示能否通过delete删除属性,能否修改属性值,能否把属性修改为数据属性
  [[Enumerable]]:表示能否通过for-in循环返回属性
  [[Get]]:读取属性时调用的函数,默认为undefined
  [[Set]]:写入属性时调用的函数,默认为undefined
  访问器属性不能直接调用,必修使用Object.defineProperty()来定义
  _属性名:表示只能通过对象方法访问的属性,访问器属性最常见就是设置属性的值,改变其他属性的变化
  创建访问器属性使用_defineGetter_()和_defineSetter_(),也可使用Object.defineProperty()
  el:var book = {_year : 2004,edition : 1};
  book._defineGetter_("year",function(){return this._year});
  book._defineSetter_("year",function(newValue){if(new Value > 2004){this._year = newValue;this.edition += newValue - 2004;}});
2,定义多个属性
  Object.defineProperties()可以一次性定义多个属性,
  接收两个对象参数:要添加和修改其属性的对象,和描述符对象,要与第一个对象要添加和修改的属性相对应
3,读取属性的特性
  Object.getOwnPropertyDescriptor(属性所在对象,读取其描述符的属性名称),获取给定属性的描述符,
  返回值为一个对象,对于数据属性,返回对象的属性有configuraable,enumerable,writable,value
  对于访问器属性,返回对象的属性有configurable,enumerable,get,set
二,创建对象
1,工厂模式

  function createPerson(name,age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
      alert("");
    };
    return 0;
  }
  var person1 = createPerson("asdg",29,"dasgj");
  ....

  解决了创建多个相似对象的问题,没有解决对象识别的问题
2,构造函数模式

  function createPerson(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
      alert("");
    };
  }
  var person1 = createPerson("asdg",29,"dasgj");

  没有显示的创建对象,没有return,将属性和方法直接赋给了this对象
  1)将构造函数当做函数
    任何函数,只要通过new操作符调用都可以看做构造函数
  2)构造函数的问题
    每个方法都在每个实例上重新创建一遍,虽然可以将方法移到外面作为全局函数,但是全局函数不宜过多
    构造函数中的方法可以定义在外面成为全局函数,当需要定义的方法很多的时候通过原型模式了
3,原型模式
  每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,包含可以由特定类型的所有实例共享和属性和方法
  1)理解原型对象
    function Person(){}
    Person.prototype.name = "";
    Person.prototype.age = 29;
    ...
    只要创建了一个函数,就会为该函数创建一个prototype属性,指向函数的原型对象
    所有的原型对象都会获得一个constructor(构造函数)属性,包含一个指向prototype属性所在函数的指针
    实例的内部包含一个指针指向构造函数的原型对象 [[Prototype]]
    所有实例都无法访问[[Prototype]] ,通过isPrototypeOf(), Person.prototype.isPrototypeOf(Person实例) 返回true
    Object.getPrototypeOf(实例对象) 返回[[Prototype]]的值(实例所指向的构造函数的原型对象)
    hasOwnProperty() 在给定属性存在于对象实例中,返回true,参数传进字符串形式属性名
    Object.getOwnPropertyDescript() 在原型对象上调用返回原型属性
  2)原型与in操作符
    单独使用in操作符,对象能够访问的属性 都返回true,实例和原型都可
    for-in 返回所有能够通过对象访问的,可枚举的,屏蔽了原型中不可枚举的([[Enumerable]]标记为false的)实例属性也可以返回
    Object.keys() 方法接收一个对象作为参数,返回所有可枚举属性的字符串数组
    Object.getOwnPropertyNames() 返回实例的所有属性,包括原型中的属性和不可枚举的属性
  3)更简单的原型语法;

    function Person(){}
    Person.prototype = {
      name : "",
      age : 310,
      ...
    };相当于重写原型函数

    此时原型对象的constructor属性不指向Person,而是指向Object了
    可以指定constructor的值为Person
    Object.defineProperty(Person.prototype,"constructor",{enumerable:false,value:Person;});
  4)原型的动态性
    可以随时为原型添加属性和方法,,能够立即在实例中反映出来
    重写原型函数,需要放在实例之前,否则无法访问到构造函数中的属性和方法
    重写原型函数,切断了实例和原型之间的联系,实例[[prototype]]仍然指向最初的原型
  5)原生对象的原型
    可以给原生对象的原型添加属性和方法,也可以修改其属性和方法
  6)原型对象的问题
    通过在原型上添加一个同名的属性,可以屏蔽原型中的属性
4,组合使用构造函数模式和原型模式
  构造函数模式用于定义实例,原型模式用于定义方法和共享属性,结果每个实例都有一份实例属性的副本,又共享方法的引用
  改变实例的属性不会影响其他实例的属性

    function Person(name,age,job){
      this.name = name;
      this.age = age;
      this.job = job;
      this.friends = ["",""];
    }
    Person.prototype = {
      constructor : Person,
      sayName : function(){};
    }

    定义实例可以分别使用自己的属性和共享方法
5,动态原型模式

  function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    if(typeof this.sayName != 'function'){
      Persong.prototype.sayName = function(){};
    }
  }

  只有在sayName() 方法不存在的时候才能将其初始化,初次调用构造函数的时候才会使用,对原型所做的修改能立刻反映在实例中
6,寄生构造函数模式

  function Person(name,age,job){
    var o = new Object();
    o.name = name ;
    o.age = age;
    o.job = job;
    o.sayName = function(){};
    return o;
  }

  函数中创建对象,并返回该函数
  返回的对象与构造函数和构造函数的原型之间没有关系
7,稳妥构造函数模式
  遵循与寄生构造函数类似的模型,区别在于创建对象的实例方法不引用this,不使用new操作符调用构造函数

三,继承
1,原型链
  1)概念
    原型链是实现基础的主要方法,利用原型让一个引用类型继承另一个引用类型的属性和方法
    一个对象的原型 = 另个对象的实例 搜索时(实例-原型-继承原型)
  2)别忘记默认的原型
    所有函数的默认原型都是object的实例,默认原型都都包含一个内部指针,指向object.prototype
  3)确定原型和实例的关系
    instanceof,只要检测实例与原型链中出现的构造函数,结果就返回true (实例 instanceof 对象)
    isPrototypeOf() ,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型 (实例.prototype.isPrototypeOf(实例))
  4)谨慎的定义方法
    继承了一个实例后,才能重写其中的方法
    使用原型链继承不能使用字面量方法创建原型对象
  5)原型链的问题
    原型变成了 实例 则实例属性也就变成了原型属性了
    创建子类的实例时,不能向超类型的构造函数传递参数
2,借用构造函数
  解决原型中包含引用类型值所带来的问题
  使用call() apply() 方法在将来新创建的对象上执行构造函数
  1)传递参数
    function SuperType(name){this.name = name; }
    function SubType(){SuperType.call(this,"asdgasd");this.age = 20;}
    传递了新的参数
  2)借用构造函数的问题
    无法避免构造函数模式存在的问题
3,组合继承
  将原型链和借用构造函数结合
  原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承
  function SuperType(name){this.name = name;this.colors = ["","",""];}
  SuperType.prototype.sayName = function(){alert("");}; 添加原型函数
  function SubType(name,age){SuperType.call(this,name);this.age = age;} 继承name属性
  SubType.prototype = new SuperType(); 原型链
  SubType.prototype.constructor = SubType;
  SubType.prototype.sayAge = function(){};
  instanceof isPrototypeof() 也用于判断组合继承的对象
  缺点:调用两次超类型构造函数,一次是创建子类型原型的时候,二次是子类型构造函数的内部
4,原型式继承

  function object(o){
    function F(){}
    F.prototype = o;   传人的对象作为临时构造函数的原型
    return new F();          返回临时对象的实例
  }
  var Person = {name:"",friend:["","",""]};
  var anotherPerson = object(person);
  anotherPerson.name = "";
  anotherPerson.friend.push("");
  var yetanotherPerson = object(person);
  yetanotherPerson.name = "";
  yetanotherPerson.friend.push("");
  1,Object.create(用作新对象原型的对象,为新对象定义额外属性的对象),规范化了原型继承
  var person = {
    name:"Nicholas",friends:["shelby","",""]
  };
  var anotherPerson = Object.create(person,{
    name:{
    value:"Greg"
    }
  });

5,寄生式继承

  function createAnother(original){
    var clone = object(original);
    clone.sayHi = function(){};
    return clone;
  }

6,寄生组合式继承
  1,思想:借用构造函数来继承属性,不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非只是超类型的副本而已
  本质,使用寄生式继承来继承超类型的原型,将结果指定给子类型的原型

  function inheritPrototype(subType,superType){
    var prototype = object(superType,prototype); 创建对象
    prototype.constructor = subType;     增强对象
    subType.prototype = prototype;     指定对象
  }

posted on 2014-03-24 09:14  哈哈李小博  阅读(197)  评论(0编辑  收藏  举报