<script>
'use strict';
// let arr = [1, 2, 3];
// let res = arr.concat(5, 6);
// console.log(res);
// 原型鏈
// __proto__ 上一級原型 Array(0)
// __proto__ 上上一級原型 Object
let obj1 = {};
console.log(obj1);// __proto__ 上一級原型 Object
// 獲取原型
let proto1 = Object.getPrototypeOf(obj1);
console.log(obj1);
let obj2 = { name: 'cyy' };
let proto2 = Object.getPrototypeOf(obj2);
console.log(proto1 == proto2);
</script>
沒有原型的物件也是存在的:
<script>
'use strict';
//Object.create 指定原型和屬性
// 完全的資料字典物件
let obj = Object.create(null, {
name: {
value: 'cyy'
}
});
console.log(obj);
//hasOwnProperty是原型的方法,由于obj沒有原型,因為無法使用該方法
console.log(obj.hasOwnProperty('name'));
</script>
原型方法與物件方法的優先級:
<script>
'use strict';
//自己有就執行自己的,自己沒有就執行原型的,原型也沒有就沒法執行
// let obj = {
// show() {
// console.log('obj.show');
// }
// }
// obj.__proto__.show = function () {
// console.log('obj.__proto__.show');
// }
// obj.show();
let obj = {}
obj.__proto__.show = function () {
console.log('obj.__proto__.show');
}
obj.show();
</script>
函式擁有多個長輩:
1.每個物件都具有一個名為__proto__的屬性;
2.每個建構式(建構式標準為大寫開頭,如Function(),Object()等等JS中自帶的建構式,以及自己創建的)都具有一個名為prototype的方法(注意:既然是方法,那么就是一個物件(JS中函式同樣是物件),所以prototype同樣帶有__proto__屬性);
3.每個物件的__proto__屬性指向自身建構式的prototype;
<script>
'use strict';
// function user() { }
// // 列印結果
// console.log(user);
// // 列印詳細結構
// console.dir(user);
// prototype和__proto__都是原型,但是使用場景不一樣
// prototype是建構式的,__proto__是物件的
function User() { }
let obj = new User();
console.log(obj.__proto__ == User.prototype);
</script>
原型關系詳解與屬性繼承實體:
<script>
'use strict';
// 系統常見建構式 Number String Function Object
let obj = new Object();
obj.name = 'cyy';
// console.dir(obj);// 物件有__proto__屬性,沒有prototype屬性
Object.prototype.show = function () {
console.log('Object-prototype-show');
}
// console.dir(Object);// 系統建構式Object有__proto__屬性和prototype屬性
// Object.prototype的原型為null
// console.dir(Object.prototype.__proto__);
function User() { }
//建構式User有__proto__屬性和prototype屬性
console.dir(User);
console.log(User.__proto__.__proto__ == User.prototype.__proto__);
let u = new User();
u.show();
User.show();
</script>
系統建構式的原型體現:
<script>
'use strict';
// let obj = {};
// console.log(obj.__proto__ == Object.prototype);
let arr = [];
console.log(arr.__proto__ == Array.prototype);
Array.prototype.show = function () {
console.log('show');
}
arr.show();
// let str = '111';
// console.log(str.__proto__ == String.prototype);
// let bool = true;
// console.log(bool.__proto__ == Boolean.prototype);
// let reg = /a/i; //new RegExp
// console.log(reg.__proto__ == RegExp.prototype);
</script>
自定義物件的原型設定:
<script>
'use strict';
let child = { name: 'child' };
let parent = {
name: 'parent', show() {
console.log('show:' + this.name);
}
};
console.log(child.__proto__ == Object.prototype);
// 設定原型
Object.setPrototypeOf(child, parent);
child.show();
// 獲取原型
console.log(Object.getPrototypeOf(child));
</script>
原型中的constructor參考:
<script>
function User(name) {
this.name = name;
}
console.dir(User);
// prototype是物件,物件的原型用__proto__獲取
// 建構式通過prototype來找原型
console.log(User.prototype.__proto__ == Object.prototype);
console.log(User.__proto__.__proto__ == Object.prototype);
// 原型通過constructor來找建構式
console.log(User.prototype.constructor == User);
let cyy = new User.prototype.constructor('cyy');
console.log(cyy);
// __proto__只服務于物件自己本身
// 在prototype中加功能
// User.prototype.show = function() {
// console.log(this.name);
// }
// cyy.show();
// 同時添加多個功能
User.prototype = {
constructor: User,
show1() {
console.log('show1');
},
show2() {
console.log('show2');
}
};
let cyy2 = new User.prototype.constructor('cyy');
console.log(cyy2);
cyy2.show1();
cyy2.show2();
</script>
給我一個物件還你一個世界:
<script>
function User(name) {
this.name = name;
// this.show = function() {
// console.log(this.name);
// }
}
let cyy = new User('cyy');
// console.log(cyy);
User.prototype = {
constructor: User,
show() {
console.log(this.name);
}
};
function createByObject(obj, ...args) {
const constructor = Object.getPrototypeOf(obj).constructor; // 獲取指定物件的建構式
// console.log(constructor == User);
return new constructor(...args);
}
let cyy2 = createByObject(cyy, 'cyy的子物件');
console.log(cyy2);
cyy2.show();
</script>
總結一下原型鏈:
<script>
// let arr = [];
// // arr是物件,物件只有__proto__屬性
// console.log(arr.__proto__ == Array.prototype);
// console.log(arr.__proto__.__proto__ == Object.prototype);
// console.log(Object.prototype.__proto__); //null
let a = {
name: 'a'
};
let c = {
name: 'c'
};
let b = {
name: 'b',
show() {
console.log(this.name)
}
};
Object.setPrototypeOf(a, b); //a的原型設定為b
console.log(a);
a.show();
Object.setPrototypeOf(c, b); //a的原型設定為b
console.log(c);
c.show();
</script>
原型鏈檢測之instanceof:
<script>
function A() {}
function B() {}
function C() {}
// 這里順序很重要,先修改A的原型,再實體化A
let c = new C();
B.prototype = c;
let b = new B();
A.prototype = b;
let a = new A();
// 檢測a的原型鏈上是否有A的prototype
console.log(a instanceof A);
console.log(a instanceof Object);
console.log(a instanceof B);
console.log(a instanceof C);
console.log(b instanceof C);
</script>
Object.isPortotypeOf 原型檢測:
<script> let a = {}; let b = {}; let c = {}; Object.setPrototypeOf(b, c); console.log(b.isPrototypeOf(a)); //b是否在a的原型鏈上 console.log(b.__proto__ == Object.prototype); console.log(b.__proto__.isPrototypeOf(a)); Object.setPrototypeOf(a, b); console.log(b.isPrototypeOf(a)); console.log(c.isPrototypeOf(a)); console.log(c.isPrototypeOf(b)); </script>
in與hasOwnProperty的屬性差異:
let a = { name: 'a' }; let b = { age: 18 }; console.log('name' in a); //name屬性是否在a物件上,或者在a的原型鏈上 console.log('web' in a); Object.prototype.web = 'url'; console.log('web' in a); console.log(a.hasOwnProperty('name')); // 檢測a物件是否含有name屬性,不會去檢測原型鏈 Object.setPrototypeOf(a, b); console.log('age' in a); console.log(a.hasOwnProperty('age')); for (const key in a) { // console.log(key); if (a.hasOwnProperty(key)) { console.log(key); } }
使用call或者apply借用原型鏈:
<script>
// let obj = {
// data: [11, 44, 2, 77, 2]
// };
// Object.setPrototypeOf(obj, {
// max() {
// return this.data.sort((a, b) => b - a)[0]; // 從大到小排序之后的陣列,最大值在第一位
// }
// });
// console.log(obj.max());
// let lessonObj = {
// lessons: {
// html: 3,
// css: 58,
// js: 88
// },
// //getter
// get data() {
// return Object.values(this.lessons);
// }
// };
// let res = obj.max.apply(lessonObj); // 借用其他物件原型鏈中的方法
// console.log(res);
//沒有this引數的情況
let obj = {
data: [11, 44, 2, 77, 2]
};
Object.setPrototypeOf(obj, {
max(data) {
return data.sort((a, b) => b - a)[0]; // 從大到小排序之后的陣列,最大值在第一位
}
});
console.log(obj.max(obj.data));
let lessonObj = {
lessons: {
html: 3,
css: 58,
js: 88
}
};
let res = obj.max.call(null, Object.values(lessonObj.lessons)); //沒有用到this,第一個引數可以設定為null
console.log(res);
</script>
優化方法借用:
<script>
// console.log(Math.max(22, 55, 33));
// let obj = {
// data: [11, 44, 2, 77, 2]
// };
// console.log(Math.max.apply(null, obj.data));
// let lessonObj = {
// lessons: {
// html: 3,
// css: 58,
// js: 88
// }
// };
// console.log(Math.max.apply(null, Object.values(lessonObj.lessons)));
// 使用展開語法
let arr = [22, 55, 33];
console.log(Math.max(...arr));
let obj = {
data: [11, 44, 2, 77, 2]
};
console.log(Math.max.call(null, ...obj.data));
let lessonObj = {
lessons: {
html: 3,
css: 58,
js: 88
}
};
console.log(Math.max.call(null, ...Object.values(lessonObj.lessons)));
</script>
DOM節點借用Array原型方法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title> </head> <body> <button message="cyy1" class="red">cyy1</button> <button message="cyy2">cyy2</button> <script> //array的過濾操作 let arr = [1, 2, 3, 4, 5]; console.log(arr.filter(item => item > 3)); console.dir(arr.__proto__.filter); console.dir(Array.prototype.filter); const btns = document.querySelectorAll('button'); // let res = Array.prototype.filter.call(btns, btn => { // // console.log(btn); // return btn.hasAttribute('class'); // }); let res = [].filter.call(btns, btn => { // console.log(btn); return btn.hasAttribute('class'); }); console.log(res); console.log(res[0].innerHTML); </script> </body> </html>
合理的建構式方法宣告:
<script>
// function User(name) {
// this.name = name;
// this.show = function() {
// console.log(this.name);
// }
// }
// let cyy1 = new User('cyy1');
// let cyy2 = new User('cyy2');
// console.dir(cyy1);
// console.dir(cyy2);
//這里的show方法寫在建構式里面,存在記憶體浪費,可以組合使用建構式方法和原型方法
// function User(name) {
// this.name = name;
// }
// User.prototype.show = function() {
// console.log(this.name);
// }
// let cyy1 = new User('cyy1');
// let cyy2 = new User('cyy2');
// console.dir(cyy1);
// console.dir(cyy2);
// 多個方法
function User(name) {
this.name = name;
}
User.prototype = {
constructor: User,
show() {
console.log(this.name);
}
}
let cyy1 = new User('cyy1');
let cyy2 = new User('cyy2');
console.dir(cyy1);
console.dir(cyy2);
</script>
this和原型沒有關系的:
this與原型無關,始終指向呼叫原型的物件 始終指向函式運行的背景關系不要濫用原型:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title> </head> <body> <button onclick="this.hide()">btn</button> <script> // 不建議在系統的原型中追加方法 Object.prototype.hide = function() { // console.log('hide'); this.style.display = 'none'; //this指向被點擊的button } </script> </body> </html>
Object.create與__proto__:
<script>
// 單個物件修改原型的方法
let User = {
show() {
console.log(this.name);
}
}
// 1、通過Object.create創建物件并指定原型
// 缺點:只能定義原型,不能獲取
// let cyy = Object.create(User, {
// name: {
// value: 'cyy'
// }
// });
// cyy.show();
// console.log(cyy);
// let cyy2 = Object.create(User);
// cyy2.name = 'cyy2';
// cyy2.show();
// 2、使用__proto__,可以設定原型,也可以獲取原型
let cyy = {
name: 'cyy'
};
cyy.__proto__ = User;
cyy.show();
console.log(cyy.__proto__);
</script>
使用setPrototypeOf替代__proto__:
<script>
// 單個物件修改原型的方法
let User = {
show() {
console.log(this.name);
}
}
// __proto__是非標準操作
// setPrototypeOf()是標準操作
// 推薦使用Object.setPrototypeOf定義原型,使用Object.getPrototypeOf獲取原型
let cyy = {
name: 'cyy'
};
Object.setPrototypeOf(cyy, User);
cyy.show();
console.dir(cyy);
console.log(Object.getPrototypeOf(cyy));
</script>
__proto__原來是屬性訪問器:
<script>
// __proto__ getter setter
let User = {
name: 'user'
}
User.__proto__ = {
show() {
console.log(this.name);
}
}
User.show();
console.log(User.__proto__);
User.__proto__ = 99;
// 智能判斷,如果是物件,則修改原型;否則不修改
console.log(User.__proto__);
let user = {
action: {},
get proto() {
return this.action;
},
set proto(obj) {
if (obj instanceof Object) {
this.action = obj;
}
}
}
// let obj = 99;
// user.proto = obj;
// console.log(user.proto);
let obj = {
name: 'obj'
};
user.proto = obj;
console.log(user.proto);
let obj2 = {};
console.dir(obj2);
// 如何讓物件設定__proto__屬性為非物件?
// 不繼承Object即可
let obj3 = Object.create(null);
obj3.__proto__ = 'obj3';
console.log(obj3);
</script>
改變建構式原型并不是繼承:
<script>
// 原型的繼承,而不是改變建構式的原型
// function User() {
// this.name = function() {
// console.log('name method');
// }
// }
// let cyy = new User('cyy');
// console.dir(cyy);
function User() {}
User.prototype.name = function() {
console.log('User name');
}
let cyy = new User('cyy');
console.dir(cyy);
// 改變建構式的原型
function Admin() {}
Admin.prototype = User.prototype; // 這是賦值,而不是繼承,改變Admin的原型的同時,也改變了User的原型
Admin.prototype.role = function() {
console.log('admin role');
}
function Member() {}
Member.prototype = User.prototype;
Member.prototype.role = function() {
console.log('member role');
}
let m = new Member();
m.name();
let a = new Admin();
a.name();
a.role();
</script>
繼承是原型的繼承:
<script>
// let f = {};
// console.dir(f.__proto__);
// console.log(Object.getPrototypeOf(f)); //查看原型
// 1、這種設定方式,對于順序沒有要求
// 實作原型的繼承,保留本身的方法和屬性,不會被覆寫和互相影響
// function User() {}
// User.prototype.name = function() {
// console.log('User name');
// }
// // 改變建構式的原型
// function Admin() {}
// // Admin.prototype.__proto__指向Object.prototype,就是指向null
// Admin.prototype.__proto__ = User.prototype; // 這是原型的繼承
// Admin.prototype.role = function() {
// console.log('admin role');
// }
// function Member() {}
// // Member.prototype.__proto__指向Object.prototype,就是指向null
// Member.prototype.__proto__ = User.prototype; // 這是原型的繼承
// Member.prototype.role = function() {
// console.log('member role');
// }
// let a = new Admin();
// a.role();
// let m = new Member();
// m.role();
// 2、這種設定方式,對順序有要求
function User() {}
User.prototype.name = function() {
console.log('User name');
}
// 改變建構式的原型
function Admin() {}
Admin.prototype.role = function() { //這個role方法在原來的Admin原型物件上,修改后就沒有了
console.log('admin role');
}
Admin.prototype = Object.create(User.prototype);
function Member() {}
Member.prototype.role = function() {
console.log('member role');
}
Member.prototype = Object.create(User.prototype);
let a = new Admin();
a.role();
let m = new Member();
m.role();
</script>
繼承對新增物件的影響:
<script>
// 1、這種設定方式,對于順序沒有要求
// function User() {}
// User.prototype.name = function() {
// console.log('User name');
// }
// // 改變建構式的原型
// function Admin() {}
// let a = new Admin();
// // 改變原來原型物件的原型,就是Object.prototype的原型
// Admin.prototype.__proto__ = User.prototype;
// Admin.prototype.role = function() {
// console.log('admin role');
// }
// a.role();
// 2、這種設定方式,對順序有要求
function User() {}
User.prototype.name = function() {
console.log('User name');
}
// 先實體化,再改變建構式的原型;此時物件不具有新的原型物件的方法
function Admin() {}
let a = new Admin();
Admin.prototype = Object.create(User.prototype);
Admin.prototype.role = function() { //這個role方法在原來的Admin原型物件上,修改后就沒有了
console.log('admin role');
}
a.role();
</script>
繼承對constructor屬性的影響:
<script>
// function User() {}
// let obj1 = new User();
// console.log(obj1.__proto__.constructor == User);
// let obj2 = new obj1.__proto__.constructor;
// console.log(obj2);
function User() {}
User.prototype.name = function() {
console.log('User name');
}
// 先實體化,再改變建構式的原型;此時物件不具有新的原型物件的方法
function Admin() {}
Admin.prototype = Object.create(User.prototype); //這種方式指定原型,沒有constructor
Admin.prototype.constructor = Admin; //手動指定constructor
Admin.prototype.role = function() { //這個role方法在原來的Admin原型物件上,修改后就沒有了
console.log('admin role');
}
let a = new Admin();
console.log(a.__proto__);
let b = new a.__proto__.constructor;
console.log(b);
</script>
禁止constructor被遍歷:
<script>
function User() {}
User.prototype.name = function() {
console.log('User name');
}
function Admin() {}
Admin.prototype = Object.create(User.prototype); //這種方式指定原型,沒有constructor
Object.defineProperty(Admin.prototype, 'constructor', {
value: Admin,
enumerable: false, //不允許遍歷
});
console.log(Object.getOwnPropertyDescriptors(Admin.prototype));
Admin.prototype.role = function() {
console.log('admin role');
}
let a = new Admin();
for (const key in a) {
console.log(key);
}
</script>
方法重寫與父級屬性訪問:
<script>
function User() {}
User.prototype.name = function() {
console.log('User name');
}
User.prototype.age = 18;
function Admin() {}
Admin.prototype = Object.create(User.prototype); //這種方式指定原型,沒有constructor
Admin.prototype.constructor = Admin;
Admin.prototype.role = function() {
console.log('admin role');
}
// 重寫父類中的方法,并使用父類中的屬性
Admin.prototype.name = function() {
console.log(User.prototype.age + ' admin name');
}
let a = new Admin();
a.name();
</script>
面向物件的多型:
<script>
function User() {}
User.prototype.show = function() {
this.role(); //role方法在每個子物件中實作
}
function Admin() {}
Admin.prototype = Object.create(User.prototype);
Admin.prototype.role = function() {
console.log('admin role');
}
function Member() {}
Member.prototype = Object.create(User.prototype);
Member.prototype.role = function() {
console.log('member role');
}
for (const obj of[new Admin, new Member]) {
obj.show();
}
</script>
使用父類建構式初始屬性:
<script>
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.show = function() {
console.log(this.name + this.age);
}
function Admin(...args) {
User.apply(this, args);
}
Admin.prototype = Object.create(User.prototype);
function Member(name, age) {
User.call(this, name, age);
}
Member.prototype = Object.create(User.prototype);
let a = new Admin('admin', 18);
let b = new Member('member', 20);
a.show();
b.show();
</script>
使用原型工廠封裝繼承:
<script>
function extend(sub, sup) {
sub.prototype = Object.create(sup.prototype);
Object.defineProperty(sub.prototype, 'constructor', {
value: sub,
enumerable: false
});
};
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.show = function() {
console.log(this.name + this.age);
}
function Admin(...args) {
User.apply(this, args);
}
extend(Admin, User);
let admin = new Admin('cyy', 18);
admin.show();
function Member(name, age) {
User.call(this, name, age);
}
extend(Member, User);
let member = new Member('cyy2', 22);
member.show();
</script>
物件工廠派生物件并實作繼承:
<script>
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.show = function() {
console.log(this.name + this.age);
}
function admin(name, age) {
let instance = Object.create(User.prototype);
User.call(instance, name, age);
instance.info = function() {
console.log('admin--info');
}
return instance;
}
let cyy1 = admin('cyy1', 11);
cyy1.show();
cyy1.info();
</script>
多繼承造成的困擾:
<script>
function Request() {}
Request.prototype.ajax = function() {
console.log('請求后臺');
}
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype = Object.create(Request.prototype);
User.prototype.show = function() {
console.log(this.name + this.age);
}
function admin(name, age) {
let instance = Object.create(User.prototype);
User.call(instance, name, age);
instance.info = function() {
console.log('admin--info');
}
return instance;
}
let cyy1 = admin('cyy1', 11);
cyy1.ajax();
</script>
使用mixin實作多繼承:
<script>
//改造成物件,把要繼承的方法變成物件的屬性
let Request = {
ajax() {
console.log('請求后臺');
}
};
let Credit = {
all() {
console.log('請求積分');
}
};
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.show = function() {
console.log(this.name + this.age);
}
function Admin(name, age) {
User.call(this, name, age);
}
Admin.prototype = Object.create(User.prototype); // Admin繼承User
// 陣列的合并實作多繼承
Admin.prototype = Object.assign(Admin.prototype, Request, Credit);
let cyy1 = new Admin('cyy1', 11);
cyy1.ajax();
cyy1.all();
</script>
mixin的內部繼承與super關鍵字:
<script> let obj = {}; console.dir(obj); //改造成物件,把要繼承的方法變成物件的屬性 let Request = { ajax() { return '請求后臺'; } }; let Credit = { __proto__: Request, all() { // console.log(this.__proto__.ajax() + '請求積分'); // super 當前類的原型,super關鍵字也可以用來呼叫父物件上的函式 console.log(super.ajax() + '請求積分'); } }; function User(name, age) { this.name = name; this.age = age; } User.prototype.show = function() { console.log(this.name + this.age); } function Admin(name, age) { User.call(this, name, age); } Admin.prototype = Object.create(User.prototype); // Admin繼承User // 陣列的合并實作多繼承 Admin.prototype = Object.assign(Admin.prototype, Request, Credit); let cyy1 = new Admin('cyy1', 11); console.log(Admin); console.log(Credit); cyy1.ajax(); cyy1.all(); </script>
TAB選項卡顯示效果基類開發:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title> <style> main { position: relative; display: inline-block; margin-right: 100px; width: 200px; height: 200px; } nav>a { display: inline-block; padding: 10px 20px; background: orange; border: 1px solid #ddd; } section { width: 200px; height: 100px; background: pink; position: absolute; top: 50px; } </style> </head> <body> <main class="tab1"> <nav> <a href="javascript:;">cyy1</a> <a href="javascript:;">cyy2</a> </nav> <section>1</section> <section>2</section> </main> <main class="tab2"> <nav> <a href="javascript:;">cyy1</a> <a href="javascript:;">cyy2</a> </nav> <section>1</section> <section>2</section> </main> <script> // 原型工廠 function extend(sub, sup) { sub.prototype = Object.create(sup.prototype); Object.defineProperty(sub.prototype, 'constructor', { value: sub, enumerable: false }); } function Animation() {} Animation.prototype.show = function() { this.style.display = 'inline-block'; } Animation.prototype.hide = function() { this.style.display = 'none'; } Animation.prototype.background = function(color) { this.style.backgroundColor = color; } let tab = document.querySelector('.tab2'); // Animation.prototype.hide.call(tab); Animation.prototype.background.call(tab, 'lightblue'); function Tab(el) { this.tab = document.querySelector(el); // console.log(this.tab); this.links = this.tab.querySelectorAll('a'); this.sections = this.tab.querySelectorAll('section'); // console.log(this.sections); } extend(Tab, Animation); Tab.prototype.run = function() { this.reset(); this.action(0); this.bindEvent(); } Tab.prototype.bindEvent = function() { this.links.forEach((a, i) => { // 閉包 a.addEventListener('click', () => { this.action(i); }); }); } Tab.prototype.action = function(i) { this.reset(); this.background.call(this.links[i], 'orange'); this.show.call(this.sections[i]); } Tab.prototype.reset = function() { this.links.forEach((el, i) => { this.background.call(this.links[i], '#ddd'); }); this.sections.forEach((el, i) => { this.hide.call(this.sections[i]); }); } new Tab('.tab1').run(); </script> </body> </html>

開放更多API實作靈活定制:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title> <style> main { position: relative; display: inline-block; margin-right: 100px; width: 200px; height: 200px; } nav>a, nav>span { display: inline-block; padding: 10px 20px; background: orange; border: 1px solid #ddd; } section { width: 200px; height: 100px; background: pink; position: absolute; top: 50px; } </style> </head> <body> <main class="tab1"> <nav> <span>cyy1</span> <span>cyy2</span> </nav> <section>1</section> <section>2</section> </main> <main class="tab2"> <nav> <a href="javascript:;">cyy1</a> <a href="javascript:;">cyy2</a> </nav> <section>1</section> <section>2</section> </main> <script> // 原型工廠 function extend(sub, sup) { sub.prototype = Object.create(sup.prototype); Object.defineProperty(sub.prototype, 'constructor', { value: sub, enumerable: false }); } function Animation() { } Animation.prototype.show = function () { this.style.display = 'inline-block'; } Animation.prototype.hide = function () { this.style.display = 'none'; } Animation.prototype.background = function (color) { this.style.backgroundColor = color; } // let tab = document.querySelector('.tab2'); // Animation.prototype.hide.call(tab); // Animation.prototype.background.call(tab, 'lightblue'); function Tab(args) { args = Object.assign({ el: null, link: 'a', section: 'section', callback: null }, args); this.tab = document.querySelector(args['el']); // console.log(this.tab); this.links = this.tab.querySelectorAll(args['link']); this.sections = this.tab.querySelectorAll(args['section']); // console.log(this.sections); this.callback = args['callback']; } extend(Tab, Animation); Tab.prototype.run = function () { this.reset(); this.action(0); this.bindEvent(); } Tab.prototype.bindEvent = function () { this.links.forEach((a, i) => { // 閉包 a.addEventListener('click', () => { this.action(i); }); if (this.callback) this.callback(); }); } Tab.prototype.action = function (i) { this.reset(); this.background.call(this.links[i], 'orange'); this.show.call(this.sections[i]); } Tab.prototype.reset = function () { this.links.forEach((el, i) => { this.background.call(this.links[i], '#ddd'); }); this.sections.forEach((el, i) => { this.hide.call(this.sections[i]); }); } new Tab({ el: '.tab1', link: 'span', callback() { console.log('執行回呼'); } }).run(); new Tab({ el: '.tab2' }).run(); </script> </body> </html>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/227119.html
標籤:其他
上一篇:DOM事件流與事件物件
下一篇:單例模式
