最近深入学习javascript后,有个体会:面向对象的方式编程才是高效灵活的编程,也是现在唯一可以让代码更加健壮的编程方式。如果我们抛开那些玄乎的抽象出类等等思想,我自己对面向对象的从写程序的角度理解就是:复用和封装。复用具体就是让你尽量少写重复代码,封装就是将一些耦合度很高的逻辑放到一个程序块里,而且尽量让里面内容不受外界影响。最后的结论是:优秀的javascript代码都是面向对象的。

如何构建javascript对象?ECMA-262对对象的定义是:无序属性的集合,其属性可以包含基本值、对象或函数。javascript的对象其实就是java里的map,即键值对。

在javascript创建一个对象一共有三种方式:

  1. 通过Object对象
  2. 通过构造函数
  3. 对象初始化

1. 通过Object对象来构建对象,代码如下:

01 //直接使用Object创建对象
02  
03 var obj = new Object();
04 obj.id = '001';
05 obj.name = 'My name is obj';
06 obj.teststring = 'Test obj';
07 obj.sayHello = function()
08 {
09     console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
10 }
11  
12 obj.sayHello();//id:001@!@name:My name is obj@!@teststring:Test obj
13 obj['sayHello']();//id:001@!@name:My name is obj@!@teststring:Test obj
14 var str = 'sayHello';
15 obj[str]();//id:001@!@name:My name is obj@!@teststring:Test obj

注意:我这里使用了两种访问对象属性的方式,一种是点运算符,一种是方括号运算符,二者是等价的,但是方括号运算似乎要更强大些,方括号里面我们可以放置变量。

这是最常用,最直观的一种创建对象方法,但是它的缺点太明显了,就是代码复用度很低,我们想到一个对象就创建一个对象,如是就会造成大量的重复代码,因此,javascript程序员将工厂模式引入到了javascrip编程里,请大家看下面的代码:

01 // 用工厂模式创建对象
02  
03 function createObj(id,name,teststring)
04 {
05     var o = new Object();
06     o.id = id;
07     o.name = name;
08     o.teststring = teststring;
09     o.sayHello = function()
10     {
11         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
12     }
13     return o;
14 }
15 var obj = createObj('002','My Name is obj2','Test Obj2');
16 obj.sayHello();//id:002@!@name:My Name is obj2@!@teststring:Test Obj2
17 obj['sayHello']();//id:002@!@name:My Name is obj2@!@teststring:Test Obj2
18 var str = 'sayHello';
19 obj[str]();//id:002@!@name:My Name is obj2@!@teststring:Test Obj2

工厂模式解决了创建相似对象的问题,如果抛开它构造对象的对象识别问题,工厂模式挺完美的,如果你做的javascript应用不是太复杂,建议使用工厂模式构造对象,这种写法可读性很高。

2. 通过构造函数

几乎所有使用构造函数方式构建对象都会使用到new运算符,javascript里面的构造函数比较特别的,在javascript里没有类的概念,new 后面跟的直接是构造函数,大家看下面的代码:

01 // 使用构造函数创建对象
02  
03 function Obj(id1,name1,teststring1)
04 {
05     this.id = id1;
06     this.name = name1;
07     this.teststring = teststring1;
08     this.sayHello = function()
09     {
10         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
11     }   
12 }
13  
14 var obj = new Obj('003','My Name is obj3','Test Obj3');
15 obj.sayHello();//id:003@!@name:My Name is obj3@!@teststring:Test Obj3
16 obj['sayHello']();//id:003@!@name:My Name is obj3@!@teststring:Test Obj3
17 var str = 'sayHello';
18 obj[str]();//id:003@!@name:My Name is obj3@!@teststring:Test Obj3

构造函数式和工厂模式从代码角度而言很像,我在学习javascript初期,单独看一种方式,思维总是惯性的把二者混为一谈,如果两个放在一起还是觉得有差异,主要是javascript里面function被赋予的功能太多,如果在一个大型程序里面二者交替使用,不晕头才怪了。其实通过两者构造对象的不同,我可以把function的使用分为构造函数式和函数式。下面我将重点分析下两种方式,这里的见底或许不全面,要是哪位高手看到了可以补充和指点哈。

首先我去掉方法里各个属性的this指针,而sayHello里面引用的this指针不去掉。代码如下:

01 // 深入分析构造函数1
02 function Obj(id1,name1,teststring1)
03 {
04     id = id1;
05     name = name1;
06     teststring = teststring1;
07     sayHello = function()
08     {
09         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
10     }   
11 }
12 var obj = new Obj('004','My Name is obj4','Test Obj4');
13 sayHello();//id:undefined@!@name:@!@teststring:undefined
14 window.sayHello();//id:undefined@!@name:@!@teststring:undefined
15 obj.sayHello();//obj.sayHello is not a function  [在此错误处中断] obj.sayHello();

this永远指向obj的,而sayHello方法里的this.id等等属性的值为undefined,表明Obj的function对象没有id,name,teststring属性,就连sayHello方法在Obj里面也没有定义好,但是直接sayHello();可以找到sayHello方法,最后我们使用window.sayHello();才知道sayHello是被定义在window里面了。如是我去掉Obj里面所有this,代码如下:

01 // 深入分析构造函数2
02  
03 function Obj(id1,name1,teststring1)
04 {
05     id = id1;
06     name = name1;
07     teststring = teststring1;
08     sayHello = function()
09     {
10         console.log('id:' + id + '@!@name:' + name + '@!@teststring:' + teststring);
11     }   
12 }
13 var obj = new Obj('005','My Name is obj5','Test Obj5');
14 sayHello();//id:005@!@name:My Name is obj5@!@teststring:Test Obj5
15 window.sayHello();//id:005@!@name:My Name is obj5@!@teststring:Test Obj5
16 console.log(id);//005
17 console.log(name);//My Name is obj5
18 console.log(teststring);//Test Obj5
19 console.log(window.id);//005
20 console.log(window.name);//My Name is obj5
21 console.log(window.teststring);//Test Obj5

由上面内容我得出了下面的结论:

  1. javascript是可以做面向对象编程的,我们不能把它当做面向过程的语言;
  2. javascript里面对象的创建是特别的,特别在于它和传统的面向对象语言比较起来做了简化,简化到直接使用构造函数来创建对象;
  3. function在javascript里面既可以当做函数式使用,又可以作为构造函数的标示(你也可以直接当做类来看待),而区别构造函数式和函数式的区别就是new;
  4. 如果我们用到了构造函数式才创建对象,那么这里和其他面向对象语言一样,也是有封装的,换种说法是里面定义的属性或者方法是属于该对象的,而让其属于该对象的方式就是用this指针,否则属性和方法将属于window对象。

如果我们不用new运算符,直接使用函数,例如下面代码:

01 // 深入分析函数式1
02  
03 function Obj(id1,name1,teststring1)
04 {
05     this.id = id1;
06     this.name = name1;
07     this.teststring = teststring1;
08     this.sayHello = function()
09     {
10         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
11     }   
12 }
13 Obj('006','My Name is obj6','Test Obj6');
14 sayHello();//id:006@!@name:My Name is obj6@!@teststring:Test Obj6
15 window.sayHello();//id:006@!@name:My Name is obj6@!@teststring:Test Obj6
16 console.log(id);//006
17 console.log(name);//My Name is obj6
18 console.log(teststring);//Test Obj6
19 console.log(window.id);//006
20 console.log(window.name);//My Name is obj6
21 console.log(window.teststring);//Test Obj6

直接调用function,this指针都是指向window,也就是全局对象,我以前看到过一句话:不论哪里直接调用函数,里面的this都是指向全局的。这个不论哪里直接调用函数就有学问了啊,看下面代码:

01 // 深入分析函数式 2
02  
03 function OuterObj(id1,name1,teststring1)
04 {
05     this.id = id1;
06     this.name = name1;
07     this.teststring = teststring1;
08     this.sayHello = function()
09     {
10         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
11     }   
12      
13     function InnerObj(id2,name2,teststring2)
14     {
15         this.id = id2;
16         this.name = name2;
17         this.teststring = teststring2;
18         this.sayHello = function()
19         {
20             console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
21         }   
22     }
23      
24     var innerVal = new InnerObj('101','InnerObj','Test InnerObj');//true
25     console.log(innerVal instanceof InnerObj);
26     innerVal.sayHello();//id:101@!@name:InnerObj@!@teststring:Test InnerObj
27      
28     InnerObj('102','InnerObj0','Test InnerObj0');
29 }
30  
31 var outObj = new OuterObj('007','My Name is obj7','Test Obj7');
32 outObj.sayHello();//id:007@!@name:My Name is obj7@!@teststring:Test Obj7
33 sayHello();//
34 window.sayHello();//id:102@!@name:InnerObj0@!@teststring:Test InnerObj0
35 console.log(id);//102
36 console.log(name);//InnerObj0
37 console.log(teststring);//Test InnerObj0

由此可见只要是函数调用this指向的方法和函数都是指向window的,即全局对象。

3. 对象初始化

对象初始化方式在有些书上也叫字面量方式构建对象,但是我更喜欢对象初始化方式,这样更直观,代码如下:

01 // 对象初始化
02  
03 var obj = {
04     id:'008',
05     name:'My Name is obj8',
06     teststring:'Test Obj8',
07     sayHello:function(){
08         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
09     }
10 };
11 obj.sayHello();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
12 obj['sayHello']();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
13 var str = 'sayHello';
14 obj[str]();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8

这种方式是我比较喜欢的一种构建对象的方式,有位javascript大师级的人物曾经建议构建空对象,最好是var obj = {},这句话就表明var obj = {}和var obj = new Object();是等价的。var obj = {}方式更加简洁,避免了o.id;o.name等等繁琐的写法,jQuery源码里面大量使用这样的构造对象的方式。

以上就是我熟知的三种在javascript里面构建对象的方式。下面我将要换个角度来理解javascript构建对象的知识。首先看一段java的代码:

1 public class Obj {
2     public static String staticParams = "静态属性,它是属于类的";
3     private String objId = "编号是对象私有的";
4     public String objName = "名称是对象公有的";
5      
6     //构造函数
7     public Obj(){}
8 }

javascript对象的属性或方法也可以使用java里的思想分为:属于类的属性和方法,属于对象的属性或方法,还有公有属性和方法以及私有属性和方法。

  1. 属于类的属性和方法:用对象初始化的方式都可以当做是属于类的属性和方法,这种定义在jQuery里面大量运用;
  2. 属于对象的属性或方法:用构造函数的方式构建对象,里面用this指针指向的属性和方法都是属于对象的;
  3. 公有属性和方法:javascript里面属性和方法天生就是公有的;
  4. 私有属性和方法:这个在javascript里面要通过模拟才能实现,这种模拟一般是使用作用域的原理,比如:在一个function内部用var来定义对象,对象作用域属于改function内部,那么在函数外部是不能访问的,这就是私有变量和方法了。

以上对象的创建,里面的属性和方法操作都是对象专有的,用相同方式构建的类似对象不能做到信息的共享,那如何才能让类似的对象能共享信息了,这就的使用prototype原型链了。

在javascript里面每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途包含可以由特定类型所有实例共享的属性和方法。

代码如下:

01 //原型模式
02  
03 function Obj(id1,name1,teststring1)
04 {
05     this.id = id1;
06     this.name = name1;
07     this.teststring = teststring1;
08     this.sayHello = function()
09     {
10         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
11     }   
12 }
13  
14 Obj.prototype.objflag = '自建的Obj对象';
15 Obj.prototype.proSayHello = function()
16 {
17     console.log('Hello World and Obj');
18 }
19  
20 var obj1 = new Obj('008','My Name is obj8','Test Obj8');
21 var obj2 = new Obj('009','My Name is obj9','Test Obj9');
22  
23 obj1.sayHello();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
24 obj2.sayHello();//id:009@!@name:My Name is obj9@!@teststring:Test Obj9
25 obj1.proSayHello();//Hello World and Obj
26 obj2.proSayHello();//Hello World and Obj
27 console.log(obj1.objflag);//自建的Obj对象
28 console.log(obj2.objflag);//自建的Obj对象

prototype写起来太繁琐了,而且又不好记,一般许多实例公用的属性和方法都是固定的不容易改变了,那么我们可以用初始化对象的方式来写原生链,这个思路我是从jQuery里学到的,代码如下:

01 //简化的原型模式
02  
03 function Obj(id1,name1,teststring1)
04 {
05     this.id = id1;
06     this.name = name1;
07     this.teststring = teststring1;
08     this.sayHello = function()
09     {
10         console.log('id:' this.id + '@!@name:' this.name +'@!@teststring:' this.teststring);
11     }   
12 }
13 Obj.prototype = {
14     objflag:'自建的Obj对象',
15     proSayHello:function(){
16         console.log('Hello World and Obj');
17     }
18 };
19 var obj1 = new Obj('010','My Name is obj10','Test Obj10');
20 var obj2 = new Obj('011','My Name is obj11','Test Obj11');
21  
22 obj1.sayHello();//id:010@!@name:My Name is obj10@!@teststring:Test Obj10
23 obj2.sayHello();//id:011@!@name:My Name is obj11@!@teststring:Test Obj11
24 obj1.proSayHello();//Hello World and Obj
25 obj2.proSayHello();//Hello World and Obj
26 console.log(obj1.objflag);//自建的Obj对象
27 console.log(obj2.objflag);//自建的Obj对象

深入JavaScript对象创建的细节的更多相关文章

  1. 【JavaScript学习】JavaScript对象创建

    1.最简单的方法,创建一个对象,然后添加属性 var person = new Object(); person.age = 23; person.name = "David"; ...

  2. JavaScript 对象创建

    tips: JavaScript 除了null和undefined之外,其他变量都可以当做对象使用. JavaScript 的基本数据类型有:number boolean string null  u ...

  3. JavaScript对象创建的几种方式

    1 工厂模式 1.1 创建 function createFruit(name,colors) { var o = new Object(); o.name = name; o.colors = co ...

  4. Javascript 对象创建多种方式 原型链

    一.对象创建 1.new Object 方式 直接赋上属性和方法 var obj = new Object(); obj.name = '娃娃'; obj.showName = function(){ ...

  5. javascript对象创建方式

    工厂模式 在ECMAscript中无法创建类,所以开发人员就发明了一种函数,用函数来封装,以特定接口创建对象的细节,如下面的例子所示: function createPerson(name,age,j ...

  6. Javascript对象创建

    一.概述 虽然对象字面量可以用来创建对象,但在创建多个类似的对象时,不够优雅,不符合DRY原则. 二.创建对象 有以下几种模式: 1.工厂模式 2.构造函数模式 3.原型模式 4.组合构造函数和原型模 ...

  7. JavaScript对象创建,继承

    创建对象 在JS中创建对象有很多方式,第一种: var obj = new Object(); 第二种方式: var obj1 = {};//对象直面量 第三种方式:工厂模式 function Per ...

  8. JavaScript—对象创建方式

    JavaScript 也是面向对象的语言(oop) 之前学JavaScript 没有学对象.现在做下笔记 创建对象的方式: 1.  对象字面量 const hero = { name: '吕布', w ...

  9. [JavaScript]对象创建方法

    1.使用Object或对象字面量创建对象 (1)使用Object创建对象 var cat= new Object(); cat.name = "Tom"; cat.color= & ...

随机推荐

  1. Siki_Unity_2-1_API常用方法和类详细讲解(上)

    Unity 2-1 API常用方法和类详细讲解(上) 任务1&2:课程前言.学习方法 && 开发环境.查API文档 API: Application Programming I ...

  2. 简单说明hadoop集群运行三种模式和配置文件

    Hadoop的运行模式分为3种:本地运行模式,伪分布运行模式,集群运行模式,相应概念如下: 1.独立模式即本地运行模式(standalone或local mode)无需运行任何守护进程(daemon) ...

  3. *转载 Tarjan有向图详解

    注意! 文章转自:https://www.cnblogs.com/liwenchi/p/7259306.html,如有造成任何侵权行为,请与我联系.我会在第一时间删除. 不过说实话,这大佬写的真的强, ...

  4. python常用命令—ipython3环境下获取某个文件夹下的文件列表

    import os os.listdir('文件夹路径')

  5. [leetcode-662-Maximum Width of Binary Tree]

    Given a binary tree, write a function to get the maximum width of the given tree. The width of a tre ...

  6. POJ 1921 Paper Cut(计算几何の折纸问题)

    Description Still remember those games we played in our childhood? Folding and cutting paper must be ...

  7. Catch That Cow(BFS广搜)

    Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...

  8. Pipeline组Alpha版本发布说明

    Pipeline组Alpha版本发布说明 项目名称 Pipeline 项目版本 Alpha版本 负责人 北京航空航天大学计算机学院 ILoveSE 联系方式 http://www.cnblogs.co ...

  9. Unity3D 入门 - 工作区域介绍 与 入门示例

    一. 工作区域详解 1. Scence视图 (场景设计面板) scence视图简介 : 展示创建的游戏对象, 可以对所有的游戏对象进行 移动, 操作 和 放置; -- 示例 : 创建一个球体, 控制摄 ...

  10. TCP系列19—重传—9、thin stream下的重传

    一.介绍 当TCP连续大量的发送数据的时候,当出现丢包的时候可以有足够的dup ACK来触发快速重传.但是internet上还有大量的交互式服务,这类服务一般都是由小包组成,而且一次操作中需要传输的数 ...