最近研究了一下JavaScript中的类,JS中的类还是很奇葩的,是伪类,类的实现是基于其原型继承机制的。写出来和大家分享一下!
一.JS类的建立方式是怎么样呢?它有哪几种建立方式呢?
(1).通过原型建立
function MyCreate(pro){
if (pro === null) {
throw TypeError();
}
if (Object.create) {
return Object.create(pro);
}
var newV = function(){};
var thisType = typeof pro;
if(thisType !== 'function' && thisType !== 'object')
throw TypeError();
newV.prototype = thisType;
return new newV();//在new 后的函数当成构造函数,通过new 创建对象
}
function NumberFW(fir_num,sec_num){
var newDX = MyCreate(NumberFW.methods);
newDX.from = fir_num;
newDX.to = sec_num;
return newDX;
}
NumberFW.methods = {
includes:function(x){
return this.from <= x && x <= this.to;
},
foreach:function(fun){
if(typeof fun != 'function')
throw TypeError();
for(var i = this.from;i <= this.to; i++)
fun(i);
return this;
}
};
在JS中,类的所有实例对象都是从同一个原型对象上继承属性。因此,原型对象是类的核心!上面是一个通过原型建立的模型实例,MyCreate()函数是解决一些不支持Object.create浏览器的功能函数,它接受一个参数,返回以参数为原型的一个实例对象,在NumberPW函数中,接收两个参数,以NumberPw.methods为原型,创建一个newDX对象,然后初始化它返回!
需要注意的是:上面的例子中,原型属性作为函数的一个属性存储,它定义了所有“范围对象"所共享的方法!
(2).通过构造函数
使用关键字new来调用构造函数,使用new调用构造函数会自动创建一个新对象,此构造函数的作用只是初始化这个新对象。 还有必须要清楚地就是:通过构造函数创建对象会继承构造函数的prototype属性,也就是构造函数的prototype会当作新对象的原型。通过同一构造函数创建的对象的原型都相同,继承相同的属性。
说了这么多废话,来给大家看个实例:
<script type="text/javascript">
function MyCreate(fir_num,sec_num){
this.from = fir_num;
this.to = sec_num;
//不需要返回
}
MyCreate.prototype = {
includes: function(x){
return this.from <= x && x <= this.to;
},
foreach: function(fun){
for(var i = this.from; i <= this.to;i++)
fun(i);
return this;
}
}//用new 创建的对象会 以 函数的prototype属性为原型,会继承它
</script>
MyCreate()是构造函数,值得注意的一点:构造函数的首字母要大写~ 通过构造函数创建的对象的原型是构造函数对象的prototype属性。
总结:通过new在构造函数调用之前已经创建了对象,实际上,构造函数只是当作只是当作新对象的一个方法调用的一次。那么构造函数的使命就是初始化这个新对象,所用使用this来初始化对象,注意,使用构造函数并不需要返回什么,因为它只是当作新对象的一个方法来初始化新对象!
(3)极简主义
<span style="font-size:12px;"><script type="text/javascript">
var Animal = {
createNew: function(){
var animal = {};
animal.sleep = function(){
console.log("打呼噜!");
}
return animal;
}
};
var Cat = {
likeEat : "fish", //公共共享的属性,只会被创建一次
createNew: function(){
var catVol = "喵喵喵" //<span style="color:#FF0000;">私有变量,其实就是只有在构造函数中才可以控制他,构造函数外不可操作它!</span>
var cat = Animal.createNew(); <span style="color:#FF0000;">//继承!</span>
cat.voice = function(){
console.log(catVol);
};
cat.eatSome = function(){
console.log("I like eat " + Cat.likeEat);
};
cat.setFood = function(food){
Cat.likeEat = food;
}
return cat;
}
};
</script>
</span>
这种方式创建类,非常简单,上文例子中有Animal对象和Cat对象,他们都有createNew方法,每次只需要调用他们就可以创建一个实例对iang,createNew方法有一个特点,就是创建一个空对象,然后再函数里初始化它,最后返回它。 上面代码中有一个catVol,他是一个私有变量,通过闭包控制他,只有通过这个新对象的特权方法才能访问他!
二.子类的使用
(1).举个例子,如果B是A的子类,那么首先要确保B的原型对象继承A的原型对象。
function MyCreate(pro){
if (pro === null) {
throw TypeError();
}
if (Object.create) {
return Object.create(pro);
}
var newV = function(){};
var thisType = typeof pro;
if(thisType !== 'function' && thisType !== 'object')
throw TypeError();
newV.prototype = thisType;
return new newV();//在new 后的函数当成构造函数,通过new 创建对象
}
function Son(firstName,years){
this.firstName = firstName;
this.years = years;
}
function Father(lastName){
this.lastName = lastName;
}
Father.prototype = {
getName: function(){return this.firstName;}
};
Son.prototype = MyCreate(Father.prototype);//通过这样的给Son.prototype赋值,不会破坏Father.prototype的封装!
Son.constructor = Son;
<span style="color:#FF0000;"><strong>Son.prototype = MyCreate(Father.prototype);
Son.constructor = Son;
<span style="color:#000000;">这两行是核心代码,让Son.prototype是以Father.prototype为原型对象,并且第二句意思是让Son.constuctor属性在指回Son构造函数!
</span></strong></span>
(2).另一种方法
function Son(firstName,years){
this.firstName = firstName;
this.years = years;
}
function Father(lastName){
this.lastName = lastName;
};
Father.prototype = {
getName: function(){return this.firstName + this.lastName},
};
var try_this = new Father("li");
Son.prototype = try_this;
Son.prototype.constructor = Son;
Father.prototype.getYear= function(){
return this.years;
};
try_this.lastName = "Smile";
var me = new Son("ruihao",20);
var you = new Son("jiahua",19);
第二张方法的核心代码:
var try_this = new Father("li");
Son.prototype = try_this;
Son.prototype.constructor = Son;
这样确实可以!需要注意的是,无论创建多少次新的Son对象,这个Father只会创建一次,它又是Son的prototype ,所以会被所有的Son继承并且共享变量!
这里更新Father.prototype,因为是动态的,并且将 Father的一个实例赋值给Son.prototype,其实赋的是 引用!!!
me you这些实例的原型是Son.prototype,也就是Father的一个实例,但是在修改me you 这些实例中继承来的lastName时候,Father的那个实例确实不会修改,个人感觉,就是把Father 那个实例的属性浅复制到me 和 you 中!!
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
作者: 李睿豪 2015.11.22