• 面向对象的程序设计


    一,理解对象
    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;     指定对象
      }
  • 相关阅读:
    Windows OpenGL ES 图像亮度调节
    Windows OpenGL ES 图像曝光度调节
    OpenGL 对比度调节
    OpenGL 伽马线
    OpenGL 亮度调节
    LyScript 插件实现自定义反汇编
    LyScript 从文本中读写ShellCode
    LyScript 自实现汇编搜索功能
    LyScript 插件实现UPX寻找入口
    LyScript 获取上或下一条汇编指令
  • 原文地址:https://www.cnblogs.com/b0xiaoli/p/3620141.html
Copyright © 2020-2023  润新知