类和模块

一、类

  JavaScript中类的实现是基于原型机制的。如果两个实例都从同一个原型上继承属性,则他们它们是同一个类的实例,类的所有实例对象都从同一个原型对象上继承属性。

   使用构造函数定义类

 1 //使用构造函数定义一个范围类
 2 function Range(from,to){
 3     this.from=from;
 4     this.to=to;
 5 }
 6 Range.prototype={
 7     //定义构造器属性
 8     constructor:Range,
 9     //判断x是否在范围内
10     include:function (x){
11         return this.from<=x&&x<=this.to;
12     },
13      //对范围内的每一个整数执行f;
14     foreach:function (f){
15         for(var i=Math.ceil(this.from);i<=this.to;i++)
16         {
17             f(i);
18         }
19     },
20     //返回表示范围的字符串
21     toString(){
22         return this.from+'...'+this.to;
23     }  
24 }
25 //调用构造函数
26 var range=new Range(1,10);
27 console.log(range.include(5));//true
28 range.foreach((ele)=>{console.log(ele)});//1  2  3  4 5..10
29 console.log(range.toString());//1...10

  构造函数是类的公共表示(往往代表类明),而原型对象是类的唯一标识。

   类的实例是一个独立的对象,直接给实例定义的属性不会被所有实例共享。可以用来模拟实例字段。

   原型对象的属性和方法或被类的实例所共享,可以用来模拟类的实例方法。

   构造函数上定义的方法可以直接用构造函数对象调用,可以用来模拟类的方法(通过类名调用)

   java中用final表示声明字段为常量。JavaScript可以使用属性名字全部大写来暗示这是一个常量。

   java中可以把字段设置为私有成员(类的外部不可见)。JavaScript中使用属性名以下划线开始暗示这是一个私有变量。 

 1 //使用构造函数定义一个范围类
 2 function Range(from,to){
 3     //定义实例方法:对象字段;保存对象的独立状态
 4     this.from=from;
 5     this.to=to;
 6 }
 7     //定义实例方法:所有实例共享
 8 Range.prototype={
 9     //定义构造器属性
10     constructor:Range,
11     //判断x是否在范围内
12     include:function (x){
13         return this.from<=x&&x<=this.to;
14     },
15      //对范围内的每一个整数执行f;
16     foreach:function (f){
17         for(var i=Math.ceil(this.from);i<=this.to;i++)
18         {
19             f(i);
20         }
21     },
22     //返回表示范围的字符串
23     toString(){
24         return this.from+'...'+this.to;
25     }  
26 }
27 //类的方法和属性
28 Range.NAME='Range';//大写表示只读的。
29 Range._format="";//下划线表示它是私有变量  

可以将上面的过程封装成一个defineClass方法。

 

 1 //将p对象的属性复制到o对象,覆盖同名方法
 2 //构造器属性只能复制值
 3 function extend(o, p) {
 4     for (var s in p) {
 5         if (p.hasOwnProperty(s))
 6             o[s] = p[s];
 7     }
 8     return o;
 9 }
10 function defineClass(constructor, method, static) {
11     //constructor代表创建类的构造函数
12     //method  实例方法
13     //static 类方法
14     if (method)
15         extend(constructor.prototype, method);
16     if (static)
17         extend(constructor, static);
18     return constructor;
19 }
20 //定义一个SimpleRange
21 var SimpleRange = defineClass(function () { this.x = 1; this.y = 2 },
22     { add: function () { return 10 } },
23     { pi: 3.14 });
24 var s=new SimpleRange();
25 console.log(SimpleRange.pi)//3,14
26 console.log(s.x);//1
27 console.log(s.add());//10

 

二、类的扩充

  JavaScript基于原型的继承是动态的,给对象的原型添加的方法,继承这个原型对象也会继承这些方法。   

1 Pange.prototype.toJson=function(){
2     return ....//
3 }

  类的实例对象都会添加toJson();

  我们可以内置对象的原型上添加方法,是内置对象都可以使用这个方法。

三、检测对象类的方法 

   intanceof、对象的constructor属性、isprototype()    

1 var o={};
2 console.log(o instanceof Object);//true
3 console.log(Object.prototype.isPrototypeOf(o));//true
4 console.log(o.constructor);//Object函数的引用

  intanceof和constructor属性会在web应用存在问题,web的框架和多窗中会有独立的上限下文,独立上下文包含独立的变量和构造方法。一个框架页面中的数组不是另一个框架页面中Array()的实例,所以instance和constructor返回false;

四. 面向对象技术

定义一个集合类Set

 

 1 //定义集合类 :将传入的值建立一个唯一的到字符串的映射,然后将字符串和值保存进对象中
 2 
 3 //定义一个构造函数
 4 function Set() {
 5     //用于将值保存在对象中
 6     this.value = {};
 7     //集合中值得个数
 8     this.n = 0;
 9     //初始化集合中的值。
10     this.add.apply(this, arguments);
11 }
12 //定义一个类内部使用的私有属性;用来产生值对应的字符串
13 Set._v2s = function (val) {
14     switch (val) {
15         case undefined: return "u";
16         case null: return 'n';
17         case true: return 't';
18         case false: return 'f';
19         default: switch (typeof val) {
20             case "number": return "#" + val;
21             case "string": return '"' + val;
22             default: return "@" + objectid(val);
23         }
24     }
25 }
26 //生成对象的id方法
27 function objectid(val) {
28     //相同的对象产生相同的id,不同的对象产生不同的id
29     var prop = "|*prop*|";//定义一个私有属性
30     if (!val.hasOwnProperty(prop))
31         val[prop] = Set._v2s.next++;
32     return val[prop];
33 }
34 //定义一个类属性
35 Set._v2s.next = 100;
36 //给集合添加实例方法
37 Set.prototype.add = function () {
38     for (var i = 0; i < arguments.length; i++) {
39         var val = arguments[i];
40         //得到值到字符串的映射
41         var str = Set._v2s(val);
42         //检验集合中是否存在这个字符串
43         if (!this.value.hasOwnProperty(str)) {
44             //当集合中不存在这个值时,将值保存近集合
45             this.value[str] = val;
46             this.n++;
47         }
48     }
49     return this;//支持链式编程
50 }
51 //删除集合中的值
52 Set.prototype.remove = function () {
53     for (var i = 0; i < arguments.length; i++) {
54         var val = arguments[i];
55         //得到值到字符串的映射
56         var str = Set._v2s(val);
57         //检验集合中是否存在这个字符串
58         if (this.value.hasOwnProperty(str)) {
59             //当集合中存在这个值时,将值删除
60             delete this.value[str]
61             this.n--;
62         }
63     }
64     return this;//支持链式编程
65 }
66 //判断集合中是否有这个值
67 Set.prototype.contains = function (val) {
68     var str = Set._v2s(val);
69     return val.hasOwnProperty(str);
70 }
71 //遍历集合,使用指定的上下文执行f函数
72 Set.prototype.forEach=function(f,content){
73    for(var p in this.value){
74        if(this.value.hasOwnProperty(p)){
75            f.call(content,this.value[p]);
76        }
77    }
78    return this;
79 }
80 //返回集合的大小
81 Set.prototype.size=function(){
82     return this.n;
83 }
84 //创建一个集合
85 var set=new Set(1,2,3);
86 set.add(4,5,6,{},{},{x:1});
87 set.remove(4,5);
88 set.forEach((ele)=>{console.log(ele)});
89 console.log(set.size());
90 console.log(set.contains(1));

 

五、标准转化方法

  应该给类的原型上定义一些标准转发方法:toString()、valueOf()、toJSON()、toLocalString()。这些方法在对象的类型转换时会用到。如果没有定义最好是刻意为之而不是忘了定义。

  对象的比较是引用的比较,我们可以自己在原型定义一类比较方法。

六、方法借用

  多个类中的方法可以共用一个函数,我们称之为方法借用。

  如;Set.prototype.equals=A.equals;

七、可以利用闭包实现变量的私有 

 1 //变量只能被类的实例方法访问,类的外面不可见
 2 function Range(from,to){
 3     this.from=function(){
 4         return from;
 5     }
 6     this.to=function(){
 7         return to;
 8     }
 9 }
10 Range.prototype.include=function(x){
11     return this.from()<=x&&x<=this.to;
12 }

 

八、构造方法的重载和工厂方法

  有时候,我们希望对象的初始化有多种方式,比如我们用构造函数创建初始化一个数组。

  

 

  

  

 

  

  

  

 

posted @ 2018-03-17 00:26  Skd一路花开  阅读(270)  评论(0编辑  收藏  举报