相信但凡作为一个前端工程师,都被面试到过这个面试题目,HR考察的就是对oop思想的理解。

  作为一个从后端转过来的怂逼,oop一直是心中的永远的痛啊。

这几天一直在通读js高级程序设计,重复理解js创建对象的几种方式,以及原型链和constructor等关键点。

  谈到创建对象,我们要从最原始的方式说起,也是最简单的方式,就是直接创建一个Object实例,然后添加属性和方法。

1、简单方式

var o=new Object();
o.name='Lucy';
o.age="20";
o.job = "doctor";
o.showName=function(){
console.log(this.name);
}

  简单方式不仅有这种Object构造函数形式,还有对象字面量

    var o = {
name:"Lucy",
age:20,
job:"doctor",
sayName: function () {
console.log(this.name);
}
}

这种写法看上去没啥问题,但是在创建多个p,就需要重复的代码,给p添加属性和方法,所以这种写法终究还是不算通用。所以后面就干脆把创建对象的过程抽象出来了,就有了工厂模式。

2、工厂模式

  function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.showName = function(){
console.log(this.name);
}
return o;
}
var p = createPerson('wly','23','前端工程师');
p.showName();
  alert(p.constructor == createPerson); //false
  alert(p instanceof createPerson); //false

  

现在可以通过调用这个函数,无数次创建对象了,但是却并不能确切地知道对象的类型。因为ECMAScript的构造函数可用来创建特定类型的对象,所以构造函数模式就出现了。

3、构造函数模式

    function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayInfo= function(){
console.log(this.name +"," + this.age + "," + this.job);
}
}
var p1 = new Person('lily','23','前端工程师');
var p2 = new Person('lucy','24','前端工程师');
alert(p1.constructor == Person); //true
alert(p2.constructor == Person); //true
alert(p1 instanceof Person); //true
alert(p2 instanceof Person); //true
alert(p1 instanceof Object); //true
alert(p2 instanceof Object); //true
alert(p1.sayInfo == p2.sayInfo); //false

构造函数模式最大的问题:同一构造函数的不同实例的相同方法是不一样的。  

p1,p2都有个constructor属性,该属性指向的就是person。而对象的constructor属性本来就是用来标识对象类型的。不过检测对象类型,还是用instanceof比较好些。至于其中的_prototo__,constructor以后另做详解。

那构造函数又有什么缺点呢,p1和p2都有sayInfo方法,但是是不同实例的同名函数,所以是不相等的( alert(p1.sayInfo == p2.sayInfo) 是false),也就是说构造函数的每个方法事实上是在每个实例中重新重建了一遍,所以难免有点浪费内存。

后面就干脆把sayInfo拎出来,成为下面这个样子。

    function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayInfo= sayInfo;
}
function sayInfo(){
console.log(this.name +"," + this.age + "," + this.job);
}
var p1 = new Person('lily','23','前端工程师');
var p2 = new Person('lucy','24','前端工程师');
alert(p1.sayInfo == p2.sayInfo); //true

  

这儿其实就是p1和p2共享了在全局作用域的sayInfo函数。但是如果我们定义这个全局函数只是为了给某个对象调用,是不是有点奇怪。假设这个Person对象有多个方法,那岂不是要定义多个全局函数。

  

4、原型模式

    function Person(){}
Person.prototype.name = "lily";
Person.prototype.age = 12;
Person.prototype.job = "doctor";
Person.prototype.friends = ["Tom","Lucy"];
Person.prototype.sayName = function(){
console.log(this.name);
};
var a = new Person();
var b = new Person();
a.friends.push("Jack");
console.log(a.friends); //"Tom","Lucy","Jack"
console.log(b.friends); //"Tom","Lucy","Jack"
console.log(a.friends == b.friends) //true

我们的初衷是像这样在所有实例共享属性和方法,我们无话可说,但是一般很少会这样用,因为实例应该拥有自己的全部的属性,这也是为啥很少有人用原型模式的原因。

5、构造模式和原型模式组合使用

创建对象最常见的方式,就是组合使用构造函数模式和原型模式。构造函数用来定义实例属性,原型模式用来定义方法和共享属性。每个实例都会有自己的一份实例属性的副本,但同时又可以共享对方付的引用。

    function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Tom","Lucy"];
} Person.prototype = {
constructor : Person,
sayName:function(){
alert(this.name);
}
}
var a = new Person("lily",12,"doctor");
var b = new Person("lucy",23,"teacher");
a.friends.push("Jack");
console.log(a.friends); //"Tom","Lucy","Jack"
console.log(b.friends); //"Tom","Lucy"
console.log(a.friends == b.friends) //false
console.log(a.sayName == b.sayName) //true

独立的friends属性,共享的sayName,这是定义引用类型的一种默认模式。

还有两种方式:寄生构造函数模式 、稳妥构造函数模式,我认为有需要可以去了解下,感觉这两种模式只是在特定情况才会去使用,一般是很少会用到的,着重点应该前面5个的演变历程。

JS创建对象的方式有几种的更多相关文章

  1. js创建对象的方式 三种

    1. 使用直接量创建1个对象: var aobj = { x : 10, y : function(){ console.log("aobj--> "+this.x); } ...

  2. JS创建对象的方式

    1.采用直接量创建方式:系统会使用new方式自动创建对象 var o = {x:1,y:2,z:2}; 2.采用new关键字创建对象:采用构造函数创建对象 var o = new Object();/ ...

  3. javascript(js)创建对象的模式与继承的几种方式

    1.js创建对象的几种方式 工厂模式 为什么会产生工厂模式,原因是使用同一个接口创建很多对象,会产生大量的重复代码,为了解决这个问题,产生了工厂模式. function createPerson(na ...

  4. JS高级---三种创建对象的方式

    JS高级---三种创建对象的方式 字面量的方式 (实例对象) 调用系统的构造函数 自定义构造函数方式 //创建对象---->实例化一个对象,的同时对属性进行初始化 var per=new Per ...

  5. JS创建对象的几种方式整理

    javascript是一种“基于prototype的面向对象语言“,与java有非常大的区别,无法通过类来创建对象.那么,既然是面象对象的,如何来创建对象呢? 一:通过“字面量”方式创建对象 方法:将 ...

  6. js几种创建对象的方式

    javascript是一种“基于prototype的面向对象语言“,与java有非常大的区别,无法通过类来创建对象.那么,既然是面象对象的,如何来创建对象呢? 一.通过”字面量“方式创建. 方法:将成 ...

  7. 对JS关于对象创建的几种方式的整理

    最近一直在看JS高级程序设计这本书,有空来梳理一下几种创建对象的方式.话不多说,直接步入正题. 第一种:Object构造函数创建 var Person = new Object();Person.na ...

  8. js创建对象的多种方式及优缺点

    在js中,如果你想输入一个的信息,例如姓名,性别,年龄等,如果你用值类型来存储的话,那么你就必须要声明很多个变量才行,变量声明的多了的话,就会造成变量污染.所以最好的方式就是存储到对象中.下面能我就给 ...

  9. JS继承以及继承的几种实现方式总结

    传统面向对象语言:继承是类与类之间的关系. 而在js中由于es6之前没有类的概念,所以继承是对象与对象之间的关系. 在js中,继承就是指使一个对象有权去访问另一个对象的能力. 比如:比如对象a能够访问 ...

随机推荐

  1. LINQ to Entities 不识别方法“System int string 转换的问题

    这个问题困扰了挺久,网上找了挺多方法 都太好使. 分几种情况. 1.如果查询结果 转换,那比较容易. var q = from c in db.Customers where c.Country == ...

  2. 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...

  3. [GDOI2016] 疯狂动物园 [树链剖分+可持久化线段树]

    题面 太长了,而且解释的不清楚,我来给个简化版的题意: 给定一棵$n$个点的数,每个点有点权,你需要实现以下$m$个操作 操作1,把$x$到$y$的路径上的所有点的权值都加上$delta$,并且更新一 ...

  4. [bzoj] 3343 教主的魔法 || 带修改分块

    原题 长度为n的序列,有两种操作: 1.[l,r]区间每个数+w 2.询问[l,r]区间有多少个数>c 记录lazy数组即可. #include<cstdio> #include&l ...

  5. [bzoj] 1036 Count

    原题 树链剖分板子题 树剖详解: #include<cstdio> #include<algorithm> typedef long long ll; #define N 30 ...

  6. 3.5 实例讲解Lucene索引的结构设计

    3.2节我们已经运行了一个Lucene建立索引的小程序,这一节我们就以这个小程序为例讲解一下Lucene建立索引的过程. import java.nio.charset.StandardCharset ...

  7. Lesson 7: C#多线程

    C#多线程 1.适用于: 通过网络进行通信 执行占用时间的操作 区分具有不同优先级的任务 使用户界面在执行后台任务时能快速响应用户的交互 2.Thread类常用属性及方法 属性: IsAlive:显示 ...

  8. codeforces gym/100814 humming distance (二进制位数比较)

    Gym - 100814I I. Salem time limit per test 1 second memory limit per test 1024 megabytes input stand ...

  9. openGL初学函数解释汇总

    openGL初学函数解释汇总 1.GLUT工具包提供的函数 //GLUT工具包所提供的函数 glutInit(&argc, argv);//对GLUT进行初始化,这个函数必须在其它的GLUT使 ...

  10. Hibernate的之间生成策略

    1.assigned 主键由外部程序负责生成,在save()之前必须指定一个.hibernate不负责维护主键生成.与hibernate和底层数据库都无关.在存储对象前,必须使用主键的setter方法 ...