做网站的 书籍,网站推广ww,产品免费推广网站有哪些,百度广告联盟价格目录 一、原型继承与属性拷贝1.1 功能说明1.2 功能测试 二、多重继承2.1 功能实现2.2 功能测试 三、寄生式继承四、构造器借用4.1 简单实现4.2 进化版4.2.1 功能实现4.2.2 案例测试 五、借用构造器和原型复制六 综合案例6.1 需求说明6.2 代码实现 一、原型继承与属性拷贝 1.1 功… 目录 一、原型继承与属性拷贝1.1 功能说明1.2 功能测试 二、多重继承2.1 功能实现2.2 功能测试 三、寄生式继承四、构造器借用4.1 简单实现4.2 进化版4.2.1 功能实现4.2.2 案例测试 五、借用构造器和原型复制六 综合案例6.1 需求说明6.2 代码实现 一、原型继承与属性拷贝 1.1 功能说明
对于继承应用来说主要目标是将一些现有的功能归为己有。也就是说我们在新建一个对象时通常首先应该继承于现有对象然后在为其添加额外的方法和属性。对此我们可以通过一个函数调用来完成并且在其中混合使用我们刚才所讨论的两种方式
使用原型继承的方式克隆现存对象其他对象使用属性拷贝的方式
function objectPlus(o, stuff){var n;var F function(){};F.prototype o;n new F();n.uber o;for(var i in stuff){n[i] stuff[i];}return n;
}
这个函数用于接受两个参数o 用于继承而另一个对象stuff 则用于拷贝方法和属性.
1.2 功能测试
var shape {name: shape,toString: function(){return this.name;}
}
var twoDee objectPlus(shape,{name: 2D shape,toString: function(){return this.uber.toString() , this.name; }
})
var triangle objectPlus(twoDee,{name: triangle,getArea: function(){return this.side * this.height / 2 ;},side: 0,height: 0
})var my objectPlus(triangle,{side: 4,height: 4
})console.log(my.getArea()); //8
console.log(my.toString()); //shape, 2D shape, triangle, triangle。这里有两个triangle是因为我们在具体实例化时是//继承于triangle对象的所以多了一层继承关系我们也可以给实例一个新的名字。例如下面var my objectPlus(triangle,{side: 4,height: 4,name: My Ext
})
console.log(my.toString()); //shape, 2D shape, triangle, My Ext 这里就变成了新的名字了二、多重继承 所谓多重继承通常是指一个子类对象中不止一个父对象的继承模式。对于JavaScript 这样的动态语言来说实现多重继承是很简单的尽管语言本身没有提供特殊的语法单元多重继承实现是极其简单的我们只需要延续属性拷贝的继承思路依次扩展对象不对其所继承的对象数量参数进行输入限制即可实现。
2.1 功能实现
下面我们创建一个multi() 函数它可以接受任意数量的输入性对象。然后我们在其中实现了一个双重循环内层循环用于拷贝属性而外层循环用于遍历函数参数中所传递进来的所有对象。
function multi(){ //这里是按照参数传递的顺序循环的而且是浅拷贝var n {}, stuff, j 0, len arguments.length;for(var j 0; j len; j){stuff arguments[j];for(var i in stuff){n[i] stuff[i];}}return n;
}2.2 功能测试 需要注意的是multi() 函数中循环是按照对象输入的顺序来进行遍历的。如果两个对象拥有相同的属性以最后一个对象为准。 var shape {name: shape,toString: function(){return this.name;}
}var twoDee {name: 2D shape,dimensions: 2,numbers: [1,2,3]
}var triangle multi(shape, twoDee, {name: triangle,getArea: function(){return this.side * this.height / 2; },side: 5,height: 10
})console.log(triangle.getArea()); //25
console.log(triangle.dimensions); //2
console.log(triangle.toString()); //triangletriangle.numbers.push(4);
console.log(triangle.numbers); //[1,2,3,4]
console.log(twoDee.numbers); //[1,2,3,4] 显然这个是浅拷贝的属性三、寄生式继承 基本思想是我们可以在创建对象的函数中直接吸收其他对象的功能然后对其进行扩展并返回。就好像所有的工作都是自己做的一样。
代码示例如下
function object(o){var n;var F function(){};F.prototype o;n new F();n.uber o;return n;
}
var twoD {name: 2D shape,dimensions: 2
}function triangle(s, h){var that object(twoD);that.name triangle;that.getArea function () {return this.side * this.height / 2;}that.side s;that.height h;return that;
}
//由于这里triangle是一个普通函数不属于构造函数所以调用它是不需要要new操作符的但是
//该函数返回的是要给对象所以在我们错误的使用了new操作符也会正常工作
var t triangle(5,6);
console.log(t.dimensions); //2
console.log(t.getArea()); //15var t2 new triangle(5,5); //照样正常工作
console.log(t2.getArea()); //12.5四、构造器借用 子对象构造器可以通过call()或apply()方法来调用父对象的构造器。因而它通常被称为构造器盗用法或者构造器借用法。
4.1 简单实现
在这里新的Triangle 对象继承了父对象的id 属性但它并没有继承父对象原型中的其他任何东西。之所以对象中不包含Shape的原型属性是因为我们从来没有调用new Shape()创建任何一个实例
function Shape(id){this.id id;
}
Shape.prototype.name Shape;
Shape.prototype.toString function () {return this.name;}function Triangle(){Shape.apply(this,arguments);
}
Triangle.prototype.name triangle;
var t new Triangle(101);
console.log(t.name); //triangle
//在这里新的Triangle对象继承了父对象的id属性但它并没有继承父对象原型中的其他任何东西
//之所以对象中不包含Shape的原型属性是因为我们从来没有调用new Shape()创建任何一个实例
//自然其原型也从来没有被用到。所以底下打印的是[object object]
console.log(t.toString()); //[object object],4.2 进化版
那么如使其包含Shape中的原型呢我们可以对Triangle构造器进行如下重定义
4.2.1 功能实现
function Triangle(){Shape.apply(this,arguments);
}
Triangle.prototype new Shape();
Triangle.prototype.constructor Triangle;在这种继承模式中父对象的属性是以子对象自身的属性的身份来重建的这与原型链模式中的子对象属性正好相反。这也体现了构造器借用法的一大优势当我们创建一个继承于数组或者其他对象类型的子对象时将获得一个完完全全的新值不是一个引用对它做任何修改都不会影响父对象。 但这种模式也是有缺点的因为这种情况下父对象的构造器往往会被调用两次一次发生在通过apply方法继承其自身属性时而另一次则发生在通过 new 操作符继承其原型时。这样一来父对象的自身属性事实上被继承了两次。
4.2.2 案例测试
下面我们来做一个简单的演示
function Shape(id){this.id id;
}
Shape.prototype.name Shape;
Shape.prototype.toString function () {return this.name;}function Triangle(){Shape.apply(this,arguments);
}
Triangle.prototype new Shape(101); //为了演示加上了101如果不加的话底下打印的就是undefined虽然是为什么是undefined因为你没有传入参数在执行Shape构造器的时候给id就是没有定义的值所以this。id就赋值成了undefined但是原型中还有有这个属性的还是重复定义了两次
Triangle.prototype.constructor Triangle;
Triangle.prototype.name triangle;var t new Triangle(202);
console.log(t.id); //202
console.log(t.__proto__.id); //101delete t.id; //删除之后
console.log(t.id); //101五、借用构造器和原型复制 对于这种由于构造器的双重调用而带来的重复执行问题实际上是很容易修正的。我们可以在父类构造器上调用apply()方法以获得其全部的自身属性然后在用一个简单的迭代器对其原型属性执行逐项拷贝。
function extend2(Child, Parent){var p Parent.prototype;var c Child.prototype;for (var i in p){c[i] p[i];}c.uber p; //扩展子类原型增加一个uber属性
}function Shape(id){this.id id;
}
Shape.prototype.name Shape;
Shape.prototype.toString function () {return this.name;}function Triangle(){Shape.apply(this,arguments);
}
extend2(Triangle,Shape);
Triangle.prototype.name triangle;var t new Triangle(202);
console.log(t.toString()); //triangle
console.log(t.id); //202
console.log(t.__proto__.id); //undefined六 综合案例 6.1 需求说明
我们利用所学的知识来写一个综合案例结合canvas 绘制如下图形 6.2 代码实现
!DOCTYPE html
html
head langenmeta charsetUTF-8titlecanvasprototype/title
/head
bodycanvas idcanvas height600 width800/canvas
/body
/html //定义点类
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 {constructor: Shape,init: function(){if(typeof this.context undefined){var canvas document.getElementById(canvas);Shape.prototype.context canvas.getContext(2d);}},draw: function(){var ctx this.context;ctx.strokeStyle this.getColor();ctx.beginPath();ctx.moveTo(this.points[0].x, this.points[0].y);for(var i 1; ithis.points.length; i){ctx.lineTo(this.points[i].x, this.points[i].y);}ctx.closePath();ctx.stroke();},getColor: function(){var rgb [];for(var 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 lines [];for(var i 0; i this.points.length; i){lines[i] new Line(this.points[i],(this.points[i1]) ? this.points[i1] : this.points[0]);}this.lines lines;return lines;},getArea: function () { //面积},getPerimeter: function(){ //z周长var lines this.getLines();var perim 0;for(var 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_a * side_b;}
}//定义正方形
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.getPerimeter());
console.log(r.getArea());//正方形
var s new Square(new Point(130, 130), 50);
s.draw();
console.log(s.getPerimeter());
console.log(s.getArea());new Square(p1, 200).draw();