继承:在原有對象的基础上,略作修改,得到一个新对象,不影响原对象的功能;
如何添加?
属性继承: 调用父类的构造函数;父类.call(this,参数,参数。。。);
方法继承: 父类的原型直接给子类的原形

function CreatePerson(name, sex) {
    this.name = name;
    this.sex = sex;
}
CreatePerson.prototype.showname = function () {
    console.log(this.name);

}
var p1 = new CreatePerson('小明', '男');
p1.showname();

///CreateStar繼承CreatePerson

function CreateStar(name, sex, job) { //子
//調用相當於執行;调用父类构造函数 ,不加call,则this指向window,必须使用this指向实例;
    CreatePerson.call(this, name, sex) 
    this.job = job;
}
CreateStar.prototype = CreatePerson.prototype

var p2 = new CreateStar('张敬轩', '男', '歌手');

p2.showname()

以上存在问题:一个原型给另一个原型,即对像给对像,所以出现了引用(修改一个会影响另一个;)



一、拷貝繼承;

如何添加?
属性继承: 调用父类的构造函数;父类.call(this,参数,参数。。。);
方法继承: for in形式實現 extend()函數,jq

function CreatePerson(name, sex) {
    this.name = name;
    this.sex = sex;
}
CreatePerson.prototype.showname = function () {
    console.log(this.name);

}
var p1 = new CreatePerson('小明', '男');
p1.showname();

///CreateStar繼承CreatePerson

function CreateStar(name, sex, job) { //子
//調用相當於執行;调用父类构造函数 ,不加call,则this指向window,必须使用this指向实例;
    CreatePerson.call(this, name, sex) 
    this.job = job;
}
//for in繼承
  extend( CreateStar.prototype ,CreatePerson.prototype)

var p2 = new CreateStar('张敬轩', '男', '歌手');

p2.showname()

    function extend(o1,o2){
        for(var attr in o2){
            o1[attr] = o2[attr];
        }
    }
//函數的的特點不能修改,只能重新賦值,所以雖然函數也是對象,但不會出問題;

拖拽繼承小例;

window.onload = function () {
    var d1 = new Drag('div1')
    d1.init()
    var d2 = new ChildDrag('div2')
    d2.init()
}
function Drag(id) {
    this.obj = document.getElementById(id)
    this.disX = 0;
    this.dixY = 0;
}
Drag.prototype.init = function () {
    var _this = this;
    this.obj.onmousedown = function (ev) {
        var ev = ev || event;
        _this.fnDown(ev)  //ev要傳進來,下面才不用定義 ;
        document.onmousemove = function (ev) {
            var ev = ev || event;
            _this.fnMove(ev)
        }
        document.onmouseup = function () {
            _this.fnUp();
        }
        return false //最後加阻止默認事件;
    }
}
Drag.prototype.fnDown = function (ev) {
    this.disX = ev.clientX - this.obj.offsetLeft;
    this.disY = ev.clientY - this.obj.offsetTop;
}
Drag.prototype.fnMove = function (ev) {
    this.obj.style.left = ev.clientX - this.disX + 'px'
    this.obj.style.top = ev.clientY - this.disY + 'px'
}
Drag.prototype.fnUp = function () {
    document.onmousemove = document.onmouseup = null;
}

function ChildDrag(id) {
    Drag.call(this, id) //指向與傳參數
}

//繼承Drag類
extend(ChildDrag.prototype, Drag.prototype);

//繼承後重新改寫move限制範圍;
ChildDrag.prototype.fnMove = function (ev) {
    var L = ev.clientX - this.disX;
    var T = ev.clientY - this.disY;
    if (L < 0) {
        L = 0;
    }
    else if (L > document.documentElement.clientWidth - this.obj.offsetWidth) {
        L = document.documentElement.clientWidth - this.obj.offsetWidth
    }
    this.obj.style.left = L + 'px'
    this.obj.style.top = T + 'px'

}
function extend(o1, o2) {
    for (var attr in o2) {
        o1[attr] = o2[attr]
    }
}



一、類繼承;
利用構造函數的方式;

b1找showName,b1下沒有,但因為賦值(Bbb.prototype = new Aaa();),則通過原型鏈找Bbb.prototype 相當於找 new Aaa(),new Aaa()再通過原型鏈找Aaa.prototype

    //父
    function Aaa() {
        this.name = '小明'
    }
    Aaa.prototype.showName = function () {
        console.log(this.name);
    }
    //子
    function Bbb() {

    }
    //子原型,= 誰去給值給子類原型:父類創建出來的對象 ;
    Bbb.prototype = new Aaa(); //其實也是引用

    var b1 = new Bbb();
    b1.showName()

問題一:constructor

 console.log(b1.constructor);  //變成function Aaa(){}了;修改了;

//修正
 Bbb.prototype = new Aaa(); //其實也是引用
 Bbb.prototype.constructor = Bbb; //修正指向;

問題二:引用時,值的改變會相互影響 ;所以,完整個類繼承的寫法是:

    
    function Bbb(){
        Aaa.call(this)
    }
    
    var F  = function () {}
    F.prototype = Aaa.prototype; //只會給showName,不會接收到屬性;,所以需要設置接收屬性;
    Bbb.prototype = new F();
    Bbb.prototype.constructor = Bbb; //修正指向;

推斷過程:

function Aaa() {
//        this.name = '小明'
    this.name = [1,2,3]
}
Aaa.prototype.showName = function () {
    console.log(this.name);
}
//子
function Bbb() {
    Aaa.call(this)
}
//子原型,= 誰去給值給子類原型:父類創建出來的對象 ;
//  Bbb.prototype = new Aaa(); //其實也是引用
//  Bbb.prototype.constructor = Bbb; //修正指向;

var F  = function () {}
F.prototype = Aaa.prototype; //只會給showName,不會接收到屬性;,所以下面需要設置接收屬性;
Bbb.prototype = new F();
Bbb.prototype.constructor = Bbb; //修正指向;
//屬性與方法的繼承要分開繼承;
var a1 = new Aaa()
var b1 = new Bbb();
b1.showName()
//   console.log(b1);
//b1找showName,b1下沒有,則通過原型鏈找Bbb.prototype 相當於找 new Aaa(),new Aaa()再通過原型鏈找Aaa.prototype

//如何用一句話來完成繼承;
//Bbb.prototype = new Aaa(); 但不坑

b1.name.push(4)
var b2 = new Bbb()
console.log(b1.name);
console.log(b2.name); //也變成1,2,3,4;
console.log(b1.constructor);  //變成function Aaa(){}了;修改了;

所以,属性继承使用call,使用F只继承方法



三、原型繼承

var a = {
    name: '小強'
}
var b = cloneObj(a)

b.name = '小強修改'  //相當於在b下面添加了;所以不需要向後找,
console.log(a.name); //則不會受影響了;

console.log(b.name);
function cloneObj(obj) {
    var F = function () {}
    F.prototype = obj;
    return new F
}

解析:f1 (new出來)通過原型鏈F.pro == obj -->name在obj下面,然後直接return f1 ,則f1 == b;
所以 b找name,相當於b 找f1 ,f1找不到則通過原型鏈F.pro == obj,找到name = '小強'
當給b.name = '小強修改',時,相當於給b下面添加了一個屬性name,則再彈b時不需要沿原型鏈找,所以a.name也不會受影響



繼承三種方法:拷貝、類式、原型;

拷貝:通用型,有new無new都可以;

類式:new構造函數情況;

原型:無new的對象;

當然也有其他繼承:寄生式、、、