前端交流圈

JavaScript——创建对象的模式(一)

2019-04-30  本文已影响20人  lulu_c

最近了解了几种创建对象的模式,下面总结一下它们的区别。

工厂模式

用函数封装以特定接口创建对象的细节。

function a (name) {
    var obj = new Object();
    obj.name = name;
    obj.hello = function () {
          alert("hello "+this.name);
    };
    return obj;
}

var a1 = a("one");
var a2 = a("two");

工厂模式解决了创建多个相似对象的问题,但是无法知道对象的类型。

构造函数模式

构造函数可以创建指定类型的对象。创建自定义的构造函数可以创建自定义对象的属性和方法。

function A (name) {
    this.name = name;
    this.hello = function () {
          alert("hello "+this.name);
    };
}
var a1 = new A("one");
var a2 = new A("two");

这里遵循构造函数命名规则第一个字母要大写,与工厂模式相比,构造函数模式没有显式创建对象,直接把属性和方法赋给this对象,同时也没有返回对象,在创建A对象时要使用new,这种方式的过程:1.创建一个新对象 2. 将构造函数的作用域赋给新对象(this指向这个对象)3.执行构造函数(新对象添加属性方法)4.返回对象。

a1和a2分别保存着A的一个不同的实例,两个对象里都有一个constructor(构造函数)属性指向A

alert(a1.contructor == A);//true
alert(a2.contructor == A);//true

检测对象类型最后还是用instanceof,a1、a2也是Object的实例。

alert(a1 instanceof A);//true
alert(a1 instanceof Object);//true

以这种方式定义的构造函数是定义在Global对象(在浏览器是window对象)的。

1.将构造函数当作函数
构造函数与其他函数的区别在于调用方式不同,任何函数,只要通过new调用就可以作为构造函数,不通过new调用就跟普通函数一样

//当作构造函数
var a = new A("one");
a.hello();//“hello one”
//普通函数
A("one");//添加到window
window.hello();//"hello one"
//在另一个对象的作用域中调用
var obj = new Object();
A.call(obj,"one");
obj.hello();//"hello one"

2.构造函数的问题
构造函数的问题就是每个方法都要在每个实例上重新创建一遍,a1、a2都有hello方法,但是两个方法不是同一个实例。函数也是对象,实例化函数也是实例化对象。也就是说a1和a2的hello方法并不相等。创建两个相同任务的function实例没有必要,而且有this对象,并不用在执行代码前就把函数绑定在特定对象上。

function A (name) {
    this.name = name;
    this.hello = hello;
}
function hello () {
      alert("hello "+this.name);
}
var a1 = new A("one");
var a2 = new A("two");

这样a1、a2 对象共享了在全局作用域定义的同一个hello()函数,解决了两个函数做同一件事的问题,但是这个全局函数只被某个对象调用,不符合全局的说法。而且如果方法很多,就要定义很多全局函数,那我们自定义的类型就没有封装性了。

原型模式

每个函数都有一个prototype属性,是一个指向对象的指针,使用这个属性我们就不必在构造函数中定义对象的实例信息,可以将这些信息直接添加到原型对象中。

function A(){
}
A.prototype.name = "张三";
A.prototype.hello = function(){    
 alert("hello " + this.name);
}

var a1 = new A();

a1.hello();      //"张三"
var a2= new A();

a2.hello();      //"张三"
alert(a1.hello == a2.hello);//true

属性和方法都添加在原型上,构造函数实为空函数,与纯构造函数创建的对象不同,这些属性和方式都是公用的(单例模式)这个是优点也是缺点,函数和基本值属性共享很好,但是如果是引用属性就有问题了。

function A(){}
A.prototype = {    
   constructor:A,    
   name:"张三",   
   cwu:["cat","dog"],    
   hello:function(){ 
      alert("hello " + this.name);  
   }
 }
var a1= new A();
var a2= new A(); 
a1.cwu.push("fish");
console.log(a1.cwu);   //["cat","dog","fish"]
console.log(a2.cwu);   //["cat","dog","fish"]
console.log(a1.cwu=== a2.cwu);   //true

因为共享,改变其中一个的实例就会改变全部的实例。

组合构造函数模式和原型模式

结合两者优点,这种模式也是比较常用的。既存在公共属性和方法,又可以自带私有参数

function A(name){     
   this.name = name; 
   this.cwu = ["cat","dog"];
}
A.prototype = {    
    constructor:A,     
     hello:function(){ 
      alert("hello " + this.name);  
   }
}

var a1= new A("张三");
var a2= new A("哈哈");
a1.cwu.push("fish");

console.log(a1.cwu);   //["cat","dog","fish"]
console.log(a2.cwu);   //["cat","dog"]

console.log(a1.cwu=== a2.cwu);   //false
console.log(a1.hello === a2.hello);   //true
上一篇下一篇

猜你喜欢

热点阅读