js创建对象之设计模式

来源:互联网 发布:广东网络玩魔兽世界 编辑:程序博客网 时间:2024/06/05 09:48

1. 工厂模式

function createPerson(name, age){    var obj = new Object();    obj.name = name;    obj.age = age;    obj.sayName = function(){        console.log(this.name); // | console.log(obj.name)    };    return obj;}var p1 = createPerson("ys", 12);var p2 = createPerson("ys", 12);console.log(p1);         // { name: 'ys', age: 12, sayName: [Function] }console.log(p2);         // { name: 'ys', age: 12, sayName: [Function] }console.log(p1 == p2);   //false

特点:

  • 内部创建对象,外部返回,相当于调用函数,
  • 对象无类型(比如其他oo语言,new一个对象,那个这个对象的构造函数就是对象类型)

2.构造函数模式

function Person(name, age){    this.name = name;    this.age = age;    this.sayName = function(){        console.log(this.name);    };}var p1 = new Person("ys", 12);var p2 = new Person("ys", 12);console.log(p1);                        // { name: 'ys', age: 12, sayName: [Function] }console.log(p2);                        // { name: 'ys', age: 12, sayName: [Function] }console.log(p1 == p2);                  //falseconsole.log(p1 instanceof Person);      //trueconsole.log(p2 instanceof Person);      //trueconsole.log(p1 instanceof Object);      //trueconsole.log(p2 instanceof Object);      //trueconsole.log(p1.constructor == Person);  //true  /*constructor属性为构造函数属性,指向构造函数Person*/console.log(p2.constructor == Person);  //true

特点:

  • 通过该模式创建的对象有自定义类型Person, 每个对象都是构造函数的实例
  • 构造函数已经不再是意义上的调用函数,而是使用了new,构造过程包括四个步骤:
    • ①创建一个新对象
    • ②将构造函数的作用域赋给新对象(因此this指向了这个新对象)
    • ③执行构造函数中的代码(为这个新对象添加属性)
    • ④返回新对象

对于这样的构造函数模式,会发现有一点瑕疵,那就是sayName函数的功能是一样的,但是每个对象的实例都有该函数,这样却显得有点冗余,在此基础上,进行了一些改良:

function Person(name, age){    this.name = name;    this.age = age;    this.sayName = sayName;}function sayName(){    console.log(this.name);}

将公共的函数部分,提取出来,作为全局函数,使得每个构造函数去调用他,达到了所有实例对象复用的效果。

2015-12-12 补充…
通过不断的的学习,对构造函数模式有了新的理解,补充:

上面我写的构造函数是用函数声明的方式定义的,另一种方法,我们也可以用对象直接量方法声明

var Person = function(name, age){    this.name = name;    this.age = age;    this.sayName = function(){        console.log(this.name);    };}var p1 = new Person("ys", 12);var p2 = new Person("ys", 12);console.log(p1);                        // { name: 'ys', age: 12, sayName: [Function] }console.log(p2);                        // { name: 'ys', age: 12, sayName: [Function] }

这样同样我得到了效果….但是最近看书学习,发现了一个问题,上面我这种方法(包括两种方法 )安全吗?
就连我之前都没有质疑过安全性,看看下面的代码

构造函数我就不写了.函数,对象直接量都是一个意思…

var p1 = Person("ys", 12);var p2 = Person("ys", 12);console.log(p1);                        // undefinedconsole.log(p2);                        // undefined

我们会发现竟然是undefined,怎么会,快找找原因….原因是他少了new这个关键字…
为什么会出现这样的原因呢,我们正确的结果,或许一看你就会了解。

var p1 = Person("ys", 12);var p2 = Person("ys", 12);console.log(p1);                        // undefinedconsole.log(p2);                        // undefinedconsole.log(window.name);               //ysconsole.log(window.age);                //12

原因就是没了new这个关键字,对于js的new关键字,大家可以这样理解:
new就是将函数内部的this的值,赋值给当前对象的this,如:this.name(实例对象) = this.name(构造函数)
当没有new的时候,this就变为了window,也就解释了。

那么问题又来了,有时候我们就是会忘记new,那这样的构造函数就显得不安全,这里有一个安全的构造函数模式,可以帮到你

/*安全的构造函数模式*/var Person = function(name, age){    if(this instanceof Person){             this.name = name;        this.age = age;        this.sayName = function(){            console.log(this.name);        };    }else{        return new Person(name, age);    }}var p1 = Person("ys", 12);var p2 = Person("ys", 12);console.log(p1);                        // { name: 'ys', age: 12, sayName: [Function] }console.log(p2);                        // { name: 'ys', age: 12, sayName: [Function] }console.log(window.name);               // undefinedconsole.log(window.age);                // undefined

3.原型对象模式

然后我们也觉得一个问题出现了,对于上面改良后的构造函数模式,所创建的全局函数sayName似乎成了Person构造函数的私人司机,只对于他一个人用,这样也就失去了全局函数的价值,而且当存在诸多构造函数时候,诸多的“sayName”也是一个问题,这个时候,原型模式完美的解决了这个问题

//需要变动部分function Person(name){    this.name = name;}//永久不变部分Person.prototype.age = 12;Person.prototype.sayName = function(){    console.log(this.name);}var p1 = new Person("ys");var p2 = new Person("ab");console.log(p1.sayName());              //ysconsole.log(p1.age);                    //12console.log(p2.sayName());              //abconsole.log(p2.age);                    //12console.log(p1.sayName == p2.sayName);  //true

当创建一个函数时候,该函数存在一个prototype属性,该属性是一个指针,指向一个对象,这个对象是一个方法和属性的集合,存储公共的属性和方法,达到所有实例共享的目的。
有全局对象的特性,区别于全局,Person构造函数的私人全局,只对它(Person)一个人生效。
当存在于对象实例时候,他们共享prototype里面的东西。

1 0
原创粉丝点击