相信但凡作为一个前端工程师,都被面试到过这个面试题目,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. Oracle在登陆时被告知用户被锁,如何解决?

    在登陆时被告知test用户被锁 1.用dba角色的用户登陆,进行解锁,先设置具体时间格式,以便查看具体时间 SQL> alter session set nls_date_format=’yyy ...

  2. Java操作 Redis 集群

    // 连接redis集群 @Test public void testJedisCluster() { JedisPoolConfig config = new JedisPoolConfig(); ...

  3. Java中方法的重写与成员变量的隐藏

    这篇文章讨论了Java面向对象概念中一个基本的概念–Field Hiding(隐藏成员变量) 在讨论这个问题之前,我们看一段特别特别简单的代码,请问一下方法的数据结果是什么? public class ...

  4. Selenium2设置隐式等待和显示等待

    1. 设置显示等待 Java代码: public static WebElement WaitForElement(WebDriver driver, String locator) { WebEle ...

  5. Grep查看日志的方法【转】

    转自:http://blog.csdn.net/stormkey/article/details/5905204 版权声明 :转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://go ...

  6. Java设计模式_创建型模式_单例模式

    单例模式的实现: 定义一个类,在类中定义该类的静态变量,再定一个一个获取该类的静态变量的方法. UML图:

  7. zlib、libzip、 libzippp 库编译(windows + cmake + vs2013)

    "libzipp" 这库是基于 "libzip" 之上封装的,而 "libzip" 又是基于 "zlib"库封装的,所以 ...

  8. 在 Flask 项目中解决 CSRF 攻击

    #转载请留言联系 1. CSRF是什么? CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求.包括:以你名义 ...

  9. python接口自动化10-token登录【转载】

    本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/tag/python%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E ...

  10. blog postman 翻译(2):postman中新增request attributes 的描述(desc)

    blog的原文链接是:http://blog.getpostman.com/2017/06/03/descriptions-for-request-attributes-in-postman/ pos ...