《javascript语言精粹》学习笔记——继承
javascript是一门弱类型语言,从不需要类型转换。对象的起源无关紧要。对于一个对象来说重要的是它能做什么,而不是他从哪里来。
javascript提供了一套更为丰富的代码重用模式。他可以模拟那些基于类的模式,也可以支持其他更具表现力的模式。在JavaScript中可能的继承模式有很多。
在基于类的语言中,对象是类的示例,并且类可以从另一个类继承。JavaScript是一门基于原型的语言,这意味着对象可以直接从其他对象继承。
伪类
他不让对象直接从对象继承,而是插入一个多余的中间层,从而使构造器函数产生对象。
我们可以定义一个构造器并扩充他的原型
var Mammal = function(name){
this.name = name;
};
Mammal.prototype.get_name=function(){
return this.name;
};
Mammal.prototype.says=function(){
return this.saying || ''
};
我们可以构造另一个伪类来继承Mammal,这是通过定义他的constructor函数并替换他的prototype为一个Mammal实例来实现的
var Cat=function(name){
this.name =name
this.saying='meow';
};
//替换 Cat.prototype 为一个新的 Mammal 实例
Cat.prototype =new Mammal();
// 扩充新原型对象,增加 purr 和 get name 方法。
Cat.prototype.purr=function(n){
vari,s='';
for(i=0;i<n;i+=1){
if(s){
s+= '-'!
}
s +='r';
return s;
}
Cat.prototype.getname=function(){
return this.says()+''+ this.name+ this.says();
};
定义一个实例
var myCat =new Cat('Henrietta');
var says=myCat.says();//meow
var purr=myCat.purr(5)//"r--r-r-r
var name =myCat.get_name()//meow Henrietta meow
//
可以看到myCat可以直接使用Mammal的方法。
我们可以隐藏一些丑陋的细节,通过使用method方法定义一个inherits方法来实现
Function.method('inherits',function(Parent){
this.prototype = new Parent();
return this;
})
我们的inherit和method方法都返回this,这允许我们采用级联编程。
var Cat=function(name){
this.name = name
this.saying='meow';
}
.inherits(Mammal)
.method('purr',function(n){
var i,s='';
for(i=0;i<n;i+= 1){
if(s){
s+='-'
}
s+='r'
}
return s
})
.method('get_name',function(){
return this.says()++this.name +!+ this.says();
});
但是他们没有私有环境,所有属性都是公开的。无法访问super的方法。
并且使用构造器函数会产生一个严重的危害,如果在调用构造器函数时忘记加上new前缀,那么this将不会被绑定到一个新对象上,而是会在全局对象上,所以不但没有扩充新对象,反而将破坏全局变量。
“伪类”形式可以给不熟悉 JavaScript的程序员提供便利,但它也隐藏了该语言的真实本质。借鉴类的表示法可能误导程序员去编写过于深入与复杂的层次结构。许多复杂的类层次结构产生的原因就是静态类型检查的约束。javaScript完全摆脱了那些约束。在基于类的语言中,类的继承是代码重用的唯一方式。JavaScript有着更多且更好的选择。
对象说明符
有时候,构造器要接受一大串的参数。这可能是令人烦恼的,因为要记住参数的顺序可能非常困难。在这种情况下,如果我们在编写构造器时使其接受一个简单的对象说明符可能会更加友好。那个对象包含了将要构建的对象规格说明。
原型
在一个纯粹的原型模式中,我们会摒弃类,转而专注于对象。基于原型的继承就是,一个新对象可以继承一个旧对象的属性。这样可以避免把一个应用拆解成一系列嵌套抽象类的分类过程。
先用对象字面量去构造一个有用的对象
var myMammal ={
name:'Herb the Mammal',
get_name :function(){
return this.name;
}
says :function(){
return this.saying || '’;
}
}
现在我们可以使用Object.beget方法(第三章定义的方法)构造出更多的示例来
var myCat=Object.beget(myMammal);
myCat.name ='Henrietta'
myCat.saying='meow';
myCat.purr=function(n){
vari,s='';
for(i=0;i<n;i+=1){
if(s){
s += '-';
}
s += 'r'
}
return s;
}
myCat.get_name=function(){
return this.says++this,name +''+ this.says;
};
这是一种差异化继承,通过定制一个新的对象,指明了他与所基于的基本对象的区别
函数化
目前所看到的继承模式的一个弱点就是我们没法保护隐私。可以采用模块模式。
从构造一个将产生对象的函数开始,他并不需要使用new前缀。该函数包含四个步骤。
1.它创建一个新对象。有很多的方式去构造一个对象。它可以构造一个对象字面量,或者它可以和 new前连用去调用一个构造器函数,或者它可以使用object.beget方法去构造一个已经存在的对象的新实例,或者它可以调用任意一个会返回一个对象的函数。
2. 它选择性地定义私有实例变量和方法。这些就是函数中通过var语句定义的普通变量
3. 它给这个新对象扩充方法。那些方法将拥有特权去访问参数,以及在第二步中通过 var语句定义的变量。
4. 它返回那个新对象
这里是一个函数化构造器的伪代码模板
var constructor=function(spec,my){
var that,其他的私有实例变量;
my=my || {};
把共享的变量和函数添加到 my 中
that =一个新对象
添加给 that 的特权方法
return that;
}
应用到mammal示例中,此处暂时不需要my:
var mammal=function(spec){
var that=(};
that.get name =function(){
return spec.name;
}
that.says =function(){
return spec.saying';
}
return that
}
var myMammal=mammal({name:Herb'});
在伪类构造器中,构造器函数Cat不得不重复构造器Mammal已经完成的工作。在函数化模式中不再需要了,让Mammal去做对象创建中的大部分工作
var cat=function(spec){
spec.saying=spec.saying ||'meow'
var that=mammal(spec)
that.purr=function(n)...
that.get name =function()...
return that;
var myCat =cat({name:"Henrietta'));
函数化模式还给我们提供了一个处理父类方法的方法。它取得一个方法名并返回调用那个方法的函数。该函数将调用原来的方法,尽管属性已经变化了
Object.method('superior',function (name){
var that = this,method = that[name];
return function(){
return method.apply(that,arguments);
});
var coolcat=function(spec){
var that=cat(spec),
super_get_name=that.superior('get_name');
that.get_name =function(n){
return 'like '+super_get_name()+ ' baby'
);
return that;
}:
var myCoolCat=coolcat({name:Bix'));
var name=myCoolCat.get_name();/1like meow Bix meow baby
部件
从一套部件中组合出对象来。
原文地址:https://blog.csdn.net/qq_45862085/article/details/140485821
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!