js中的对象建立的模式

对象建立模式:

  • 工厂模式
    • 因为javascript中没有类的概念,因此用开发人员发明了一种函数,经过函数来封装特定接口建立对象的,见例子:
    function createObj (name, age) {
    		return {
    		name: name,
    		age: age
    		}
    	}
  • 构造函数模式
    • 该模式和上述工厂模式的不一样点:
      • 没有显示地建立对象
      • 直接将属性和方法赋给了this对象
      • 没有return语句
      function Person (name, age){
          this.name = name;
          this.age = age;
      }
    • 构造函数名首字母约定大写
    • 建立对象的过程大概分为如下三个步骤:
      1. 建立一个对象
      2. 将构造函数的做用域赋给新对象
      3. 执行构造函数内的代码,为这个对象添加属性
      4. 返回对象
      var obj = Object.create(Person.prototype);
      // 建立一个对象,将这个对象的原型指向构造函数的的原型;
      Person.call(obj);
      // 执行步骤2和3, 将构造函数的this指向建立的obj对象,并运行构造函数内的代码,为obj对象添加属性
    • 须要注意的是: 若是构造函数中有return语句,返回的是引用类型的数据,则返回该引用类型数据
    • 若是作普通函数,在全局做用域中执行,则this指向window
    • 构造函数存在的问题:每一个方法都要在每一个实例上建立一遍,对此有一个简单的方法解决,将方法函数的定义放在外面,可是若是有不少个方法,那就须要在外面定义不少个方法,好在能够经过原型模式来解决这一问题
  • 原型模式
    • 将共同的方法属性添加到函数的原型中,好处也体如今此处,让全部的对象实例共享它包含的属性和方法
      function Person () {};
      Person.prototype.name = 'zhanhui';
      Person.prototype.job = 'programmer';
      Person.prototype.sayName = function () {
          console.log(this.name);
      };
    • 每个函数都有一个prototype原型属性,指向一个对象
    • prototype原型对象上有一个constructor属性,指向构造函数
    • Object.getPrototypeOf() 获取对象的原型属性
    • isPrototypeOf()方法肯定对象之间是否存在原型关系
    • 虽然能够经过对象实例访问保存在原型中的值,可是不能经过对象实例重写原型中的值,而且为对象实例添加一个原型上重名的属性时,这个属性会屏蔽原型对象中保存的同名属性,若是要回复对原型对象该属性的访问,能够用delete操做符删除实例属性,见下例子:
    var person1 = new Person();
    var person2 = new Person();
    person1.name = 'wawa';
    console.log(person1.name); // 'wawa'来自实例对象
    console.log(person2.name); // 'zhanhui'来自原型对象
    • hasOwnProperty()获取实例对象上的属性,不能获取原型对象的属性
    • in 操做符 单独使用或者配合for-in循环中使用
      • 单独使用时,in操做符会在经过对象是否能访问到给定的属性时返回true,不管该属性是否存在于实例中仍是原型中
      • for-in循环时,能够经过对象访问到、可枚举的属性,该属性既能够在实例中,也能够是原型中,而且即便将该属性的Enumerable标记为false,也是能够遍历到的
      person1.age = 26;
      Object.defineProperty(Object.getPrototypeOf(person1), 'age', {
          enumerable: false
      });
      for (var key in person1) {
          console.log(key); // name job sayName
      }
      • for-in获取key
      var obj = {
          x: 1,
          y: 2
          };
          var props = [];
          var i = 0;
      
          for (props[i++] in obj);
      
          props // ['x', 'y']
    • hasPrototypeProperty() 判断读取到的某属性是在实例中读取到还时原型中读取到
    hasPrototypeProperty(person1, 'name'); // false person1中的name是从实例中读取的
    hasPrototypeProperty(person2, 'name'); // true person2中的name是从原型中读取的
    • Object.keys()返回全部可枚举属性的字符串数组
    • Object.getOwnPropertyNames()能够获取实例的全部属性,无论是否可枚举
    • 原型对象:
      • 默认原型对象的constructor是不可枚举的,当咱们重写原型时,constructor指向object构造函数,因此在重写构造函数的原型对象时,若是constructor很重要,会用的到,就须要特别指定一下,见例子:
      function Person (){}
      Person.prototype = {
          constructor: Person, // 特别指定
          name: 'zhanhui',
          say: function() {
              console.log(this.name);
          }
      }
      // 将constructor属性设置为不可枚举
      Object.defineProperty(Person.prototype, 'constructor', {
          enumberable: false
      })
      • 重写原型后,调用构造函数时会为实例添加一个指向最初的原型,而重写原型则将构造函数和其最初的原型断开了联系,实例化时又将实例对象的__proto__指向最初的原型,因此就存在问题,实例不能获取重写后的原型上的属性和方法,见例子:
      var boo = new Person();
      boo.say() // error
      // 可是通过验证并非,新的浏览器内核已经不存在这样的问题了
      • 原型对象存在的问题:主要是其共享性所带来的,例如原型对象上挂载了一个引用类型的属性,其余一个实例中更改这个引用属性都会将影响扩散到其余的全部实例上,见例子:
      function Person (){}
          Person.prototype = {
              constructor: Person, // 特别指定
              name: 'zhanhui',
              say: function() {
                  console.log(this.name);
              },
              friends: ['boo', 'mike']
          }
          var person1 = new Person();
          var person2 = new Person();
          person1.friends.push('lili');
          console.log(person1.friends); // ['boo', 'mike', 'lili']    console.log(person2.friends); // ['boo', 'mike', 'lili']
  • 组合构造函数模式和原型模式
    • 构造函数模式用来定义实例属性,而原型模式用于定义方法和共享的属性
    • 见例子:
    function Person (name, age) {
        this.name = name;
        this.age = age;
        this.friends = ['boo', 'mike'];
    }
    Person.prototype = {
        constructor: Person,
        say: function () {
            console.log(this.name);
        }
    }
  • 寄生构造函数模式
    • 其实和工厂模式相似,构造函数用来封装建立对象的代码,而后在返回新建立的对象,见例子:
    function Person (name, age) {
        var obj = {};
        obj.name = name;
        obj.age = age;
        obj.say = function () {
            console.log(this.name);
        }
    		return obj;
    }
    var person1 = new Person('zhanhui', 26);
    • 应用场景: 例如咱们要建立一个额外方法的数组
    • 特殊说明:构造函数返回的对象和构造函数以及构造函数的原型没有关系,所以不能用instanceof来肯定对象类型
  • 稳妥构造函数
    • 所谓稳妥就是没有公共属性,其方法不使用new调用函数,也不引用this
    • 见例子:
    function Person (name,age){
        var o = {};
        // 定义私有变量和方法;
        function howOld () {
            console.log(age);
        }
        // 添加共有方法,这也是闭包的应用场景,共有方法访问私有变量
        o.say = function () {
            console.log(this.name);
        };
        return o;
    }
     var person1 = Person('zh', 26);
    // 只能经过say方法访问私有变量name
相关文章
相关标签/搜索