零JS筆記 | 面向對象 | 繼承
继承:在原有對象的基础上,略作修改,得到一个新对象,不影响原对象的功能;
如何添加?
属性继承: 调用父类的构造函数;父类.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的對象;
當然也有其他繼承:寄生式、、、