步遥——多种姿势创建对象

使用字面量这种方式去创建对象,很简洁,但是如果需要构造多个对象呢?比如,创建了一个男生personMale,还想再创建一个女生personFemale,那就再来一个对象字面量,多个person,就会一个个手写创建多个对象字面量。
重复劳动必然会有懒人想要节省一下劳动力:
懒人方法1:
工厂模式:犹如工厂生产一般,批量创建!
函数是一种创建一次就可以无限次调用的方法,所以,如果某一类对象含有相同的属性,就可以包装到一个函数中,并最终返回一个想要的对象,就可以节省劳动力,简单使用一下方法,就创建出来一个实例!也就好比是使用一个简单的api,一键生成,简单高效!看下懒人工厂模式:

function createPerson(name,age,job){  //一次创建一个加工厂,无限次生产person
      var o = new Object();
      o.name = name;
      o.age = age;
      o.job = job;
      o.sayName = function(){
          alert(this.name)
      }
  return o;
}
var person1 = createPerson('Nicholas',29,'Software English');
var person2 = createPerson('Greg',27,'Doctor');

以上方法可以无限制的调用,重复生产person,懒人开心了,只要复制过来createPerson就可以啦,多么简单就可以写代码啦!
但是,这些批量生产出来的对象,只能被程序识别出来它们只是对象,因为它们还是通过Object的构造函数来的,但是批量生产后,其实它们都应该有一个共同的名字——person呀,需要给工厂加一个品牌效应,形成一个可以被大家一眼就认出来的类型,拥有像Object一样的江湖地位!于是就有了构造函数生产对象。
懒人方法2:
构造函数生产对象:

function Person(name ,age,job){//形成了Person的自定义品牌
     this.name = name;
     this.age = age;
     this.job = job;
     this.sayName = function(){
       alert(this.name)
     }
}
var person1 = new Person('Nicholas',29,'Software English');//使用时使用跟Object一样的方式,new一个构造函数
var person2 = new Person('Greg',27,'Doctor');

跟工厂模式对比:构造函数地位上升了一个level,有以下不同:
1:不需要自己再辛苦的创建对象了;
2:把参数和方法统一交给一个管家:this;
3:也不需要再自己把对象给return出去了;
以上这些重复劳作的脏活累活,统统交给了一个工具:new,所以,使用构造函数创建对象的那一刻,new默默的做了以下工作:
1:创建一个对象;(原本工厂中每次都有的创建对象不做了,那就交给new来做)
2:管家跟这个对象建立起联系,则this管家在工作时,获取属性时就会去连接的对象上找,这也就是隐式的将作用域this绑定到了新建立的对象上
3:执行构造函数中的任务:给新对象添加属性
4:返回新对象;(原本工厂中每次都return的对象,现在也都交给了new来包装)
总结以上过程:构造函数方法,也就是在工厂方法的基础上的一次提炼,将相同的如同流水线一般的无脑操作统一起来交给一个管家来负责,构造函数体内部只做接受厂外需求的对接。而既然做了构造函数,也就要遵守构造函数首字母大写的规范,这样别人也容易辨识你这个品牌logo!,构造函数还具有了一定的特权,就是通过constructor属性(脐带)连接实例:

person1.constructor === Person//用constructor连接孩子和父母

同时打造了属于Person的品牌:

person1 instanceof Person
person2 instanceof Person
personn instanceof Person

构造函数确实让懒人更节省了操作,但是在生成的每个实例对象person1,person2,personn上都挂着一个相同作用sayName的方法,好像又有点浪费。既然已经形成了一定的品牌,在做好公司的同时还要给公司节流不是吗?节省一个函数的存储,当函数随着功能的不断扩展,肯定占据非常大的存储空间,把这么大的资源浪费进行优化,提取到公共的地方,实例使用时再来拿,不就起到了非常大的效益吗?于是就出现了懒人方法3:
原型模式:
每个函数都有一个prototype属性,这个属性转向的对象是一个共享空间,由相同类型的实例都可以共享的属性和方法。就像是Person家族的一块共享的菜园,如果实例想要南瓜,就可以来这里摘南瓜,而不用自己再种南瓜了~~~

function Person(){}

Person.prototype.name = 'Nicholas';//Person.prototype共享菜园
Person.prototype.age = 29;
Person.prototype.job = 'Software English';
Person.sayName = function(){
    alert(this.name)
}
var person1 = new Person();
var person2 = new Person();
person1.name === person2.name;//true  都是共享菜园拿来的

使用hasOwnProperty就可以检测属性是实例上的还是原型对象上的

person1.hasOwnProperty(name)//false,因为name在prototype上
person1.name = 'tiger'
person1.hasOwnProperty(name)//true,此时name是实例上

结合以上构造函数方法和原型方法的优点,就进化升级到懒人方法4:
组合使用构造函数模式和原型模式
构造函数用来创建实例属性,而原型模式用来定义方法和共享属性。这样每个实例都会有自己的一份实例属性,但同时又可以访问共享方法,最大限度的节省了内存。

function Person(name,age,job){
  this.name = name;
  this.age  = age;
  this.job = job;
  this.friends = ['Shelly','Lily']
}
Person.prototype={
constructor:Person,
sayName:function(){
    alert(this.name);
  }
}
var person1 = new Person('Nicholas',29,'Software English');
var person2 = new Person('Greg',27,'Doctor')
person1.friends === person2.friends //false//不同实例引用了不同的数组
person1.sayName === person2.sayName // true // 引用的同一个方法

此外还有寄生构造函数:就是仿照构造函数的样子,重写原有的构造函数方法:

function Person (name,age,job){
    var o = new Object();//可以是别的构造函数 
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){//对别的构造函数的方法的重写或者是扩展的方法
      aler(this.name)
    }
    return o 
}

var person = new Person('Nicholas',30,'Teacher');

好啦,以上就是所有的创建对象的懒人方法。回想工作中还是使用构造函数的方法比较多~

你可能感兴趣的:(步遥——多种姿势创建对象)