您的位置:首页 > Web前端 > JavaScript

读书笔记----javascript类和模块

2016-03-24 19:50 232 查看
构造函数时用来初始化新创建的对象的,使用new关键字来初始化这个对象。使用new调用构造函数会自动创建一个新对象,因此构造函数本身只需要初始化这个新对象即可。

//range,js 实现一个能表示值的范围的类
function range(from,to){
//使用inherit()创建对象,这个对象继承下面定义的原型对象
var r=inherit(range.methods);//创建一个对象r,继承原型对象range.methods
//定义起始位置和结束为止,这两个属性是非共享的不可继承的,每个对象都拥有唯一的属性
r.from=from;
r.to=to;
return r;//返回创建的新对象

}

//原型对象的定义方法,这些方法为每个范围对象继承
range.methods={
includes:function (x){
return this.from<=x&&x<=this.to;

},
//对于范围内的每个整数都调用一次f
foreach: function (f){
for (var x=Math.ceil(this.from);x<=this.to;x++) f(x);

},
//返回表示这个范围的字符串
toString:function(){ return "("+this.from+"..."+this.to+")";}                   }

};
var r=range(1,3);//穿件一个范围对象
r.includes(2);//true 2在这个范围内
r.foreach(console.log);//输出1 2 3
console.log(r);//输出(1...3)
// form to都是非共享的,不可继承的,但是range.methods中定义的可共享的,可继承的方法
//都用到了from和to,而且使用了this关键字。任何类的方法都可以通过this读取对象的属性


这里写代码片


调用构造函数,构造函数的prototype属性被用做新对象的原型。所以通过构造函数创建的对象都继承一个相同的对象,他们都是同一个类的成员。

//使用构造函数定义范围类
function Range(from,to){  //定义构造函数就是定义类,并且类的首字母大写
this.from=from;
this.to=to;
}
Range.prototype={  //Range()构造函数调用会自动使用Range.prototype作为新的Range对象原形
includes:function (x){return this.from<=x&&x<=this.to;},
foreach:function(f){
for (var x=Math.ceil(this.from);x<=this.to;x++) f(x);
},
toString: function(){return "("+this.from+"..."+this.to+")";}
};
var r=range(1,3);
r.includes(2);
r.foreach(console.log);
console.log(r);

//上述构造函数定义类,定义的Range类使用它自身的一个对象重写预定义的Range.prototype对象。
//这个心定义的原型对象不含有constructor属性,因此Range类实例也不含有constructor属性


原型对象是类的唯一标识,当且仅当两个对象继承同一个原型对象是,它们才是同一个类的实例。

r instanceof Range//如果r继承自Range.prototype,则返回true

instanceof运算符并不会检查r是否由Range构造函数初始化来的,只会检查r是否继承自Range.prototype

每个javscript函数都拥有一个prototype属性,这个属性的值是一个对象,这个对象包含唯一一个不可枚举的属性constructor.

//显式给原型添加一个构造函数
Range.prototype={
constructor:Range, // 显式设置构造函数反向引用
includes: function(x){ return this.from<=x&&x<=this.to;},
foreach:function (f){
for (var x=Math.ceil(this.from);x<=this.to;x++) f(x);
},
toString: function(){  return "("+this.from+"..."+this.to+")";}
};


var p=F.prototype;//这是F相关联的原型对象

var c=p.constructor;//这是与原型相关联的函数

c===F //true 对于任意函数F.prototype.constructor==F

对象继承的constructor均指代它们的构造函数

var 0=new F();//提供F的一个对象

o.constructor===F //true constructor属性指代这个类

//使用预定义的原型对象,预定义的原型对象包含constructor属性,然后依次给原型对象添加方法
//扩展预定义的Range.prototype对象,这样就自动创建Range.prototype.constructor属性
Range.prototype.includes=function (x){ return this.from<=x&&x<=this.to;};
Range.prototype.foreach=function (f){
for (var x=Math.ceil(this.from);x<=this.to;x++) f(x);
};
Range.prototype.toString=function(){
return "("+this.from+"..."+this.to+")";
};


构造函数对象:为javascript的类定义了名字,任何添加到这个构造函数对象中的属性都是类字段和类方法

原型对象:属性被类的所有实例所继承,如果原型对象的属性值是函数的话,这个函数就作为类的实例方法来调用

实例对象:类的每个实例都是一个独立的对象

定义类的步骤:第一步先定义一个构造函数,并设置初始化新对象的实例属性

第二步给构造函数prototype对象定义实例方法

第三步给构造函数定义类字段和类属性

//定义一个简单的类函数
function defineClass( constructor,  //用来设置实例属性的函数
methods,     //实例的方法,复制至原型中
statics    //类属性,复制到构造函数中
)
{  if (methods) extend(constructor.prototype,methods);
if (statics) extend(constructor,statics);
return constructor;

}
//Range 类的实现
var SimpleRange=
defineClass (function (f,t) {this.f=f;this.t=t;},
{
includes:function (x){return this.f<=x&&x<=this.t;},
toString: function(){  return this.f+"..."+this.t}
},
{upto: function(t) {return new SimpleRange(0,t);}}
);


js中的原型继承机制是动态的,对象从原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象。

检测对象类的技术 instanceof isPrototypeOf constructor

instanceof检测对象继承关系,而不是检测创建对象的构造函数

isPrototypeOf()检测对象原型链上是否存在某个特定的原型对象

这两种方法的缺点:无法通过对象获得类名,只能检测对象是否属于指定的类名。在多个执行上下文中存在构造函数的多个副本的时候,检测结果出错。

辅助构造函数

//辅助构造函数
function SetFromArray(a){
//将a的元素作为参数传入
Set.apply(this,a);
}
//设置原型,以便SetFormArray能够创建Set实例
SetFromArray.prototype=Set.prototype;
var s=new SetFromArray([1,2,3]);
s instanceof Set  //true


如果O是类B的实例,B是A 的子类,那么O一定从A中继承了属性。为此首先确保B的原型对象继承自A的原型对象

B.prototype=inherit(A.prototype); //子类派生自父类

B.prototype.constructor=B; //重载继承来的constructor属性

这是创建子类的关键,如果不这样做,原型对象仅仅是一个普通对象,它只继承Object.prototype。

Object.preventExtensions()可以将对象设置为不可扩展的,不能为对象添加新的属性

Object.seal()除了阻止用户给对象添加新属性,还能将当前已有的属性设置为不可配置。

//定义一个复数类
function Complex(real,imaginary){
if (isNaN(real)||isNaN(imaginary))
throw new TypeError();
this.r=real;
this.i=imaginary;
}
Complex.prototype.add=function(that){
return new Complex(this.r+that.r,this.i+that.i);
}
Complex.prototype.equals=function(that){
return that!=null&&  //必须有定义且不能是null
that.constructor===Complex&&  //必须是Complex实例
this.r===that.r&&this.i===that.i;  //包含相同的值

}
//定义对复数运算有帮助的类字段,他们都是常量
Complex.ZERO=new Complex(0,0);
Complex.ONE=new Complex(1,0);


function typeAndValue(x){
if (x==null)  return " ";// null undefined 没有构造函数
switch (x.constructor){
case Number: return "Number:"+x;//处理原始类型
case String: return "String:' "+x+" '" ;
case Date:return "Date: "+x;  //处理内置对象
case RegExp: return "Regexp: "+x;
case Complex:return "Complex: "+x;//定义自定义类型
}
}
//case后的表达式都是函数,如果改为typeof 运算符或获取到对象的class属性的话,应当改为字符串
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: