面向对象的程序设计-2-创建对象

该文为阅读高级程序设计(第三本)p144-p164的理解与总结!  接受指导与批评。

对于我,我一直是使用字面量的方式创建对象,然而体系上的创建对象的方法却并不局限于此。

创建对象的方法

  1. 工厂模式
  2. 构造函数模式
  3. 原型模式
  4. 组合使用构造模式和原型模式
  5. 动态原型模式
  6. 寄生构造函数模式
  7. 稳妥的构造函数模式

1 工厂模式:

  定义工厂函数创建并返回包含特定属性的对象, 

function createPerson(name, age, job) {
    var o = new Object();    // var o = {}; //一样
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}
var person0 = createPerson('jody', 22, 'wife');

 

2 构造函数模式:

  先贴出代码

function Person(name) {
    this.name = name;
    this.sayName = function() {
        console.log(this);
    }
}
var person1 = new Person('xxx');
var person2 = new Person('bbb');
console.log(person1)

 

  2.1 new Person() 的发生了什么?步骤分解:这是重点(new的工作原理)

    1. 新建一个对象: instance = new Object(); 
    2. 设置原型链: instance.prototype = Person.prototype 
      1.   任意函数在创建的时候都会创建prototype对象,并自动为它添加constructor属性
    3. 让 Person 中的 this 指向 instance, 然后执行函数:
      1.   相当于在instance中定义属性(name,sayName)
    4. 判断 Person 函数的返回 :
      1.   Person 中没有写return,相当于return undefined(值类型),因此返回instance
      2.   如果返回值类型,则丢弃该值类型, 然后返回 instance。
      3.   如果返回引用类型,则丢弃instance, 返回该引用类型。

  2.2 构造函数也是函数,

    它是可以直接执行的,然后给执行作用域绑定属性。    

    任何函数,只要使用new 操作符,这个函数函数就变成了构造函数

  2.3 构造函数的优缺点

      1.优点:

person1 instanceof Person
person2 instanceof Object   //都为ture,用于判断类型(工厂模式不行)

      2.缺点:公共属性(如sayName)在每一个Person实例中都创建了,不能做到复用

 

3 原型模式

function Person() {
};
Person.prototype.sayName = function() {
    console.log(this.name);
}
Person.prototype.name = 'miaowwwwww';
var person1 = new Person();
var person2 = new Person();
person1.sayName();
console.log(person1)

 

  3.1 什么是原型对象??

    当创建一个函数的时候,js根据一组特定的规则自动地为函数创建 prototype 属性 和 一个原型对象。

    prototype 属性是一个指针,指向原型对象。

    原型对象自动获得一个 constructor(构造函数) 指针属性,该属性指向 被创建的函数。

  3.2 实际应用重点:

        使用构造函数创建的每一个实例,都自动包含一个[[prototype]] 指针属性。(在浏览器prototype是隐藏的,一些浏览器提供__proto__)。

        并且这个属性指向,构造函数的 prototype (即原型对象, 所以每一个实例共享一个原型对象

  3.3 构造函数-原型-实例的关系如图:

 

 

 

 

 

 

 

 

 

 

   3.4 注意:

    1.  原型对象上的可遍历属属性将会出现在 实例的 for-in 遍历中  
    2.  构造函数 Person.prototype 是一个指针
      1.   若使用 Person.prototype.sayName = function() {...}  表示在原 原型中添加属性
      2.   若使用如下方式:表示 改变了 Person.prototype 的指针, 让它指向了一个新的对象,该对象的属性被实例共享,当缺失了constructor属性
        Person.prototype = {
            constructor: Person,    // 可手动添加,补全constructor属性
            name: 'miaowwwww',
            sayName: function() {
                console.log(this.name);
            }
        }

   3.5 原型模式的优缺点

       1.优点:

      1.   完善构造函数模式的缺点,所有实例可以共享原型的方法,而不需要是个实例创建副本,提高复用性
      2.   类型判断
person1 instanceOf Person 
Person.isPrototypeOf(person1)
Object.getPrototypeOf(person1) === Person
// 都可以正确判断结果

 

       2.缺点:若原型中使用引用类型,则实例可以修改原型中的

function Person() {};
Person.prototype = {
    constructor: Person,
    name: 'miaowwwww',
    friends: ['jody', 'robin'],
    sayName: function() {}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push('mike');
// person2.friends : ['jody', 'robin', 'mike'];

  

 4. 组合构造函数模式与原型模式

function Bird(name) {
    this.name = name;
    this.friends = ['mike', 'jody'];
}
Bird.prototype = {
    sayName: function() {
        console.log(this.name);
    }
}

 

   4.1 优点: 结合构造函数模式与原型模式的优点,把引用类型的属性,放到构造函数中,为每一个实例创建副本,同时复用原型上的方法

 

5.动态原型模式

function Cat(name) {
    this.name = name;
    this.friends = ['a', 'b'],
    if(typeof this.sayName !== 'function') {
        Cat.prototype.sayName = function() {
            console.log(this.name);
        }
    }
}

  5.1 解读:就是把第四种模式,变异一下,在判断实例没有 sayName 方法的时候才添加 该方法到 原型上

       每次新建对象的时候都会执行判断代码, 然后只有第一次执行, if 才为true

 

6.寄生构造函数模式

function Book(name) {
    var o = new Array();
    o.name = name;
    o.sayName = function() {
        console.log(this.name);
    }
    return o;
}
var book1 = new Book('javascript');

 

   6.1 请回顾上面说过的 2.1 new 的工作原理

   6.2 理解:

    1. 这种方法除了 return 以及 new Book()  之外,跟工厂函数基本没有区别。
    2. 可以理解为对已有对象的增强(如这里的Array,因为不能直接修改Array对象)

  6.3 缺点:

    1. book1 的原型中不包含 Book, 而是Array, 所以叫寄生
    2. 与构造函数一样,每一个实例都有 sayName.. 的副本,复用性降低

 7 稳妥的构造函数模式

function Fish(_name){
    var o = new Object(); // new Person(); 或其他对象
    
    // 私有变量和函数
    var name = _name;
    function sayHi() {
        console.log('hi')
    };
    // ...

    // 添加方法
    o.sayName = function() {
        console.log(name);
        sayHi();
        return name;
    }
    o.setName = function(value) {
        name = value;
    }
    return o;
}
var aa = Fish('miaowwwww');
var bb = Fish('jody');
aa.sayName();
bb.sayName();

 

  7.1 这个竟然是平时一直在用的闭包。

  7.2 优点:变量私有化,并且只能通过特定接口访问

    缺点: 又是每一个实例一个函数副本,复用性降低了;

  

 

posted @ 2017-01-06 14:12  miaowwwww  阅读(273)  评论(0编辑  收藏  举报