第6章 继承
1.使用原型继承模式(而不是属性拷贝的方式)实现多重继承。例如:
var my = objectMulti(obj,another_obj,a_third,{
additional: "properties"
});
属性additional应该是私有属性,而其他属性则应该归并如prototype。
答:我也不是很清楚作者什么意思,我就想出这么一个挫方法,以后有了更好的方法再改吧。
function objectMulit() {
var n={};
var parent;
var np={};
var i=0;
var l=arguments.length;
for(i=0;i<l-1;i++){
parent=arguments[i];
for(var j in parent){
if(parent.hasOwnProperty([j])){
np[j]=parent[j];
}
}
}
n.prototype=np;
for(var j in arguments[l-1]){
if(arguments[l-1].hasOwnProperty([j])){
n[j]=arguments[l-1][j];
}
}
return n;
}
var obj={
attr1: "attr1"
};
var another_obj={
attr2: "arrt2"
};
var a_third={
attr3: "attr3"
};
var my=objectMulit(obj,another_obj,a_third,{
additional:"properties"
});
console.log(my);
ps:原书标准答案
function objectMulti() {
var Constr,
i,
prop,
mixme;
// constructor that sets own properties
var Constr = function (props) {
for (var prop in props) {
this[prop] = props[prop];
}
};
// mix into the prototype
for (var i = 0; i < arguments.length - 1; i++) {
var mixme = arguments[i];
for (var prop in mixme) {
Constr.prototype[prop] = mixme[prop];
}
}
return new Constr(arguments[arguments.length - 1]);
}
2.利用上面(书中前文,代码如下)的画布示例展开实践,
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css"> #canvas{ background-color: #ccc; } </style>
</head>
<body>
<canvas id="canvas" width="1000px" height="1000px"></canvas>
<script type="text/javascript"> function Point(x,y){ this.x=x; this.y=y; } function Line(p1,p2){ this.p1=p1; this.p2=p2; this.length=Math.sqrt(Math.pow(p1.x-p2.x,2)+Math.pow(p1.y-p2.y,2)); } function Shape(){ this.points=[]; this.lines=[]; this.init(); } Shape.prototype={ init:function(){ if(this.context===undefined){ var canvas=document.getElementById("canvas"); Shape.prototype.context=canvas.getContext("2d"); } }, draw:function(){ var i,ctx=this.context; ctx.strokeStyle=this.getColor(); ctx.beginPath(); ctx.moveTo(this.points[0].x,this.points[0].y); for(i=0;i<this.points.length;i++){ ctx.lineTo(this.points[i].x,this.points[i].y); } ctx.closePath(); ctx.stroke(); }, getColor:function(){ var i,rgb=[]; for(i=0;i<3;i++){ rgb[i]=Math.round(255*Math.random()); } return "rgb("+rgb.join(",")+")"; }, getLines:function(){ if(this.lines.length>0){ return this.lines; } var i,lines=[]; for(i=0;i<this.points.length;i++){ lines[i]=new Line(this.points[i],this.points[i+1]||this.points[0]); } this.lines=lines; return lines; }, getArea:function(){}, getPerimeter:function(){ var i,perim=0,lines=this.getLines(); for(i=0;i<lines.length;i++){ perim+=lines[i].length; } return perim; } } function Triangle(a,b,c){ this.points=[a,b,c]; this.getArea=function(){ var p=this.getPerimeter(); var s=p/2; return Math.sqrt(s*(s-this.lines[0].length)*(s-this.lines[1].length)*(s-this.lines[2].length)); }; } function Rectangle(p,side_a,side_b){ this.points=[ p, new Point(p.x+side_a,p.y), new Point(p.x+side_a,p.y+side_b), new Point(p.x,p.y+side_b) ]; this.getArea=function(){ return side_b*side_a; }; } function Square(p,side){ Rectangle.call(this,p,side,side); } var s=new Shape(); Triangle.prototype=s; Rectangle.prototype=s; Square.prototype=s; var p1=new Point(100,100); var p2=new Point(300,100); var p3=new Point(200,0); var t=new Triangle(p1,p2,p3); t.draw(); console.log(t.getPerimeter()); console.log(t.getArea()); var r=new Rectangle(new Point(200,200),50,100); r.draw(); console.log(r.getArea()); console.log(r.getPerimeter()); var s=new Square(new Point(130,130),50); s.draw(); console.log(s.getArea()); console.log(s.getPerimeter()); new Square(p1,200).draw(); </script>
</body>
</html>
尝试各种不同的东西,例如:
1)绘制出一些Triangle、Square、Rectangle图形。
答:
new Rectangle(new Point(120,40),10,60).draw();
(我又画了一个小烟囱,好了,就这样吧。。。)
2)添加更多的图形构造器,例如Trapezoid、Rhombus、Kite以及Pentagon等。如果您还想对canvas标签有更多的了解,也可以创建一个Circle构造器,该构造器需要您重写父对象的draw()方法。
答:画出梯形、菱形、风筝什么的太麻烦了,我就做一个多边形的类,和一个圆形的。
function Polygon(){
this.points=arguments;
}
Polygon.prototype=s;
var plg1=new Polygon(new Point(100,400),new Point(300,400),new Point(350,600),new Point(50,600));
plg1.draw();
var plg2=new Polygon(new Point(600,50),new Point(550,150),new Point(600,250),new Point(650,150));
plg2.draw();
function Circle(p1,radius){
this.centerPoint=p1;
this.radius=radius;
this.draw=function(){
var ctx=this.context;
ctx.beginPath();
ctx.strokeStyle=this.getColor();
ctx.arc(this.centerPoint.x,this.centerPoint.y,this.radius,0,Math.PI*2,false);
ctx.stroke();
};
this.getPerimeter=function(){
return Math.PI*2*this.radius;
};
this.getArea=function(){
return Math.pow(this.radius,2)*Math.PI;
};
}
Circle.prototype=s;
var c=new Circle(new Point(700,500),100);
console.log(c.getPerimeter());
console.log(c.getArea());
console.log(c);
c.draw();
3)考虑一下,是否还有其他方式可以实现并使用这些类型继承关系,从而解决上述问题?
答:书中前面内容随便找了个方式
function extend(Child,stuff){
var F=function(){};
F.prototype=stuff;
Child.prototype=new F();
Child.prototype.constructor=Child;
Child.uber=stuff;
}
4)请选择一个子对象能通过uber属性访问的方法,并为其添加新的功能,使得父对象可以追踪到该对象所属的子对象。例如,或许我们可以在父对象中建立一个用于存储其所有子对象的数组属性。
答:想了半天不知道怎么弄,试了几种方法也不行。父对象怎么也追踪不到子对象啊。然后我就看了一下答案,把原书的标准答案给出来
function inherit(Child, Parent) {
// remember prototype
var extensions = Child.prototype;
// inheritance with an intermediate F()
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
// reset constructor
Child.prototype.constructor = Child;
// remember parent
Child.prototype.uber = Parent;
// keep track of who inherits the Parent
if (!Parent.children) {
Parent.children = [];
}
Parent.children.push(Child);
// carry over stuff previsouly added to the prototype
// because the prototype is now overwritten completely
for (var i in extensions) {
if (extensions.hasOwnProperty(i)) {
Child.prototype[i] = extensions[i];
}
}
}
父对象构造函数保留了子对象的构造函数,也不是保留对象啊。
我考虑到可能是翻译有误会,所以把英文版问题也贴出来吧
Think of another way to do the inheritance part. Use uber so kids can have access to their parents. Also, get parents to be aware of their children.