继承:让一个没有某个属性或方法的对象能够使用另一个具有某个方法或属性的对象的属性或方法。
var obj = {
name:"obj",
show:function(){
console.log(this.name);
}
}
var obj2 = {
name:"obj2"
}
// 如何利用show,打印出obj2的名字?
obj.show(); // obj
obj.show.call(obj2); // obj2
obj2.show();
以上是实例和实例之间的继承,规模太小。
继承的分类:
- 原型的继承
- 构造函数的继承
- 混合继承
- ES6 class继承
原型继承之原型对象继承:简单,方便,易操作;缺点时只能继承原型身上的方法和属性,不能继承构造函数内部的方法和属性。
function Parent(){
// this.name = "parent";// 这里的内容没有被继承到
}
Parent.prototype.name = "parent";
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(){
}
// 浅拷贝
Child.prototype = Parent.prototype;
// 这里更改Child的方法时,Parent的属性会一起被改变
// Child.prototype.show = function(){
// console.log("hello");
// }
// 浅拷贝时,在Child原型上写的方法和属性,在Parent原型上也能拿到
// Child.prototype.abc = function(){
// console.log("hello");
//}
var p = new Parent();
p.show();
// p.abc();
console.log(p.name);
var c = new Child();
c.show();
// c.abc();
console.log(c.name);
// 为了避免出现上面那种情况,所以需要用for循环进行深拷贝,当在Child中改变或添加方法和属性时,Parent原型的方法和属性不会被改变和添加
function Parent(){
// this.name = "parent";
}
Parent.prototype.name = "parent";
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(){
}
// 浅拷贝
// Child.prototype = Parent.prototype;
// 深拷贝
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
// Child.prototype.abc = function(){
// console.log("hello");
// }
Child.prototype.show = function(){
console.log("hello");
}
var p = new Parent();
p.show();
// p.abc();
console.log(p.name);
var c = new Child();
c.show();
// c.abc();
console.log(c.name);
原型继承之原型链继承:更加的简单,方便,易操作;不仅可以继承原型身上的方法和属性,而且还可以继承构造函数中的方法和属性;但是,不方便传参。
function Parent(){
this.name = "hello world";
}
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(n){
}
// 原型链继承
Child.prototype = new Parent();
// 他的传递过程是:Child的实例c ---> __proto__ ---> Child.prototype ---> Parent的实例 ---> __proto__ ---> Parent.prototype
// 在Child中改变show方法时,不会影响Parent中show方法的结果
// Child.prototype.show = function(){
// console.log("嘿嘿嘿");
// }
var p = new Parent();
p.show();
console.log(p.name);
var c = new Child();
c.show();
console.log(c.name);
function Parent(n){
// this.name = "hello world";
this.name = n;
}
Parent.prototype.show = function(){
// console.log("哈哈哈show方法");
console.log(this.name);
}
function Child(n){
// this.name = "html";
// this.name = n;
}
// Chlid的传参需要在这里传,对使用来说非常的不方便
Child.prototype = new Parent("就你了!");
// Child.prototype.show = function(){
// console.log("嘿嘿嘿");
// }
var p = new Parent("张三");
// console.log(p)
p.show();
// console.log(p.name);
var c = new Child();
// console.log(c);
c.show();
// console.log(c.name);
构造函数继承:可以方便的传参,还可以实现多继承,但是,只能继承构造函数内部的属性或方法,不能继承原型身上的属性或方法。
function Parent(s){
this.skill = s;
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Parent(s){
this.skill = s;
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(n){
// 利用this的改变
// this
// 在Child中执行Parent的同时,修改this指向,为Child的this
// 因为Child将来被new执行,Child中的this,指向将来Child的实例
// Parent.call(this,n);
// Parent.apply(this,[n]);
Parent.bind(this,n)();
}
var p = new Parent("大鉴定师");
console.log(p.skill);
p.show();
var c = new Child("实习鉴定师");
console.log(c.skill);
c.show();
构造函数继承的多继承
function Mp3(){
this.music = "放音乐";
}
function Camera(){
this.photo = "拍照";
}
function Tel(){
this.call = "打电话";
}
function Email(){
this.message = "发信息";
}
function MobilePhone(n){
Mp3.call(this);
Camera.call(this);
Tel.call(this);
Email.call(this);
this.name = n;
this.game = "打游戏";
}
var mp = new MobilePhone("HUAWEI P30");
console.log(mp);
混合继承:构造函数继承 + 原型继承
特点:
- 略复杂
- 既可以继承构造函数,又可以继承原型
- 方便传参
- 可以多继承构造函数
- 注意:原型链继承时,依然有参数隐患
- 常用的继承方式之一
function Parent(s){
this.skill = s;
// 测试原型链继承的参数隐患
// this.skill.split();
}
Parent.prototype.show = function(){
console.log(this.skill);
}
function Child(s){
Parent.call(this, s);
}
// Child.prototype = new Parent();
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
console.log("hello 鉴定师");
}
var p = new Parent("大鉴定师");
p.show();
var c = new Child("实习鉴定师");
c.show();
ES6的class继承的原理:构造函数方式继承 + 原型链继承
class Parent{
constructor(s){
this.skill = s;
}
show(){
console.log(this.skill);
}
}
class Child extends Parent{
constructor(s){
super(s);
// this.skill = s + "哈哈";
}
// show(){
// alert(this.skill);
// }
}
var p = new Parent("大鉴定师");
p.show();
console.log(p);
var c = new Child("实习鉴定师");
c.show();
console.log(c);
用继承的方式,解决不同的推拽(一个有边界限定,一个无边界限定)
<style>
div{width: 100px;height: 100px;position: absolute;left:0;}
#box1{background:red;top:0;}
#box2{background:blue;top:130px;}
</style>
<body>
<div id="box1"></div>
<div id="box2"></div>
</body>
function Drag(ele){
this.ele = ele;
this.addEvent();
}
Drag.prototype.addEvent = function(){
var that = this;
this.ele.onmousedown = function(eve){
that.downE = eve || window.event;
document.onmousemove = function(eve){
that.moveE = eve || window.event;
that.move();
}
document.onmouseup = function(){
that.up();
}
}
}
Drag.prototype.move = function(){
this.ele.style.left = this.moveE.clientX - this.downE.offsetX + "px";
this.ele.style.top = this.moveE.clientY - this.downE.offsetY + "px";
}
Drag.prototype.up = function(){
document.onmousemove = null;
}
function SmallDrag(ele){
Drag.call(this, ele)
}
for(var i in Drag.prototype){
SmallDrag.prototype[i] = Drag.prototype[i];
}
SmallDrag.prototype.move = function(){
let l = this.moveE.clientX - this.downE.offsetX;
let t = this.moveE.clientY - this.downE.offsetY;
if(l<0) l=0;
if(t<0) t=0;
this.ele.style.left = l + "px";
this.ele.style.top = t + "px";
}
var obox1 = document.getElementById("box1");
var obox2 = document.getElementById("box2");
new Drag(obox1);
new SmallDrag(obox2);
// 当有多个相似程序或相似对象,具有一些类似功能时,可以将公共功能做成一个总的父级
// 所有细节部分,在继承公共对象之后,另做修改