体验ES6中类的秘密
class声明类的语法:
<script> // class cc { } // console.log(typeof cc); // let cc = class { }; // console.log(typeof cc); // class User { // show() { // console.log('show'); // } // }; // let u = new User(); // u.show(); // function Lesson(title) { // this.title = title; // } // let l = new Lesson('html'); // console.log(l.title); class Lesson { constructor(title) { this.title = title; } getTitle() { console.log(this.title); } } let l1 = new Lesson('l1'); console.log(l1.title); l1.getTitle(); </script>
类的内部工作机制就是原型操作:
<script> class User { // 属性初始值 constructor(name) { this.name = name; } show() { console.log('show'); } } console.dir(User); console.log(User.prototype.constructor == User); let u = new User('user'); // Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。 console.log(Object.getOwnPropertyNames(u)); console.log(Object.getOwnPropertyNames(User.prototype)); function Func(name) { this.name = name; } Func.prototype.show = function () { console.log('show'); } console.dir(Func); console.log(Func.prototype.constructor == Func); let f = new Func('Func'); console.log(Object.getOwnPropertyNames(f)); console.log(Object.getOwnPropertyNames(Func.prototype)); </script>
对象属性的声明:
<script> class User { site = 'www.baidu.com'; constructor(name) { this.name = name; } } let u = new User('user'); console.log(u.site); </script>
class声明的方法为什么不能遍历:
<script> // function Func(name) { this.name = name; } // Func.prototype.show = function () { } // console.log(JSON.stringify(Object.getOwnPropertyDescriptor(Func.prototype, 'show'), null, 2)); // // 可遍历 // let f = new Func('cyy'); // for (const key in f) { // 会去找原型 // console.log(key); // } // for (const key in f) { // if (f.hasOwnProperty(key)) { // console.log(key); // console.log(f[key]); // } // } class User { constructor(name) { this.name = name; } show() { console.log('show'); } } let u = new User('cyy'); console.log(JSON.stringify(Object.getOwnPropertyDescriptor(User.prototype, 'show'), null, 2)); // 方法不可遍历 for (const key in u) { console.log(key); } </script>
严格模式下运行:
<script> // 'use strict'; // function func() { // console.log(this); // } // func(); // function User() { // } // User.prototype.show = function () { // function func() { // console.log(this);//非严格模式下指向window // } // func(); // } // let u = new User(); // u.show(); // 不管是在严格模式还是非严格模式下,都不会指向window class User { show() { function func() { console.log(this);//非严格模式下指向window } func(); } } let u = new User(); u.show(); </script>
静态属性使用:
<script> // 分配给构造函数的属性,称为静态属性 // function User(site) { // this.site = site; // } // User.site = 'cyy'; // let u = new User('user'); // console.log(u.site);// 非静态属性 // console.log(User.site);//静态属性 // 不能使用name,name会指向构造函数的名字 //静态属性在类上,而不是在实例化的对象上 class Request { host = 'www.baidu.com'; static host2 = 'www.google.com';//静态属性 show(url) { console.log(Request.host2 + url); } } let r1 = new Request(); console.log(r1); let r2 = new Request(); console.log(r2); console.dir(Request); r2.show('/taobao'); </script>
静态方法的实现原理:
<script> // function User() { // } // User.prototype.show = function () { } // let u = new User(); // console.dir(u); //User的原型上有show,非静态方法 // User.show2 = function () { console.log(User == this); console.log(User.prototype.constructor == this); }//prototype.constructor指回构造函数 // console.dir(User);//静态方法:直接定义到函数上(对象原型上) // // 函数也是对象,所以也可以用下面的写法 // User.__proto__.show3 = function () { } // console.dir(User); // User.show2(); // class Request { // show() { // console.log('show'); // } // static show() { // console.log('static-show') // } // } // Request.__proto__.show2 = function () { } // 也是静态方法 // let r1 = new Request(); // r1.show(); // Request.show();//静态方法 // Request.show2(); // console.dir(r1); // console.dir(Request); class Member { constructor(name, age) { this.name = name; this.age = age; } static create(...args) { return new this(...args); } } let m = Member.create('cyy', 18); console.dir(m); </script>
静态属性练习之课程管理类:
<script> const lessons = [ { title: 'title1', click: 99 }, { title: 'title2', click: 13 }, { title: 'title3', click: 44 }, ]; class Lesson { constructor(item) { this.model = item; } // 访问器 get gclick() { return this.model.click; } get gtitle() { return this.model.title; } click() { return this.model.click; } title() { return this.model.title; } static createBatch(data) { return data.map(item => new Lesson(item)); } static maxClick(data) { return data.sort((a, b) => b.click - a.click)[0]; // 访问器 // return data.sort((a, b) => b.click() - a.click())[0]; } static totalClick(data) { return data.reduce((t, c) => { return t + c.gclick; }, 0); } } let res = Lesson.createBatch(lessons); // console.log(res); let res2 = Lesson.maxClick(res); // console.log(res2); // console.log(res2.title()); // console.log(res2.gtitle);//访问器 console.log(Lesson.totalClick(res)); </script>
在类中使用访问器:
<script> class Request { constructor(url) { this._url = url; } // setUrl(url) { // if (!/^https?:\/\//i.test(url)) { // throw new Error('地址错误~'); // } // this.url = url; // } set url(url) { if (!/^https?:\/\//i.test(url)) { throw new Error('地址错误~'); } this._url = url;//这里不能使用url,否则会死循环; } get url() { return this._url; } } let r = new Request('baidu.com'); // r.url = 'taobao.com'; // console.log(r); // r.setUrl('google.com'); console.log(r.url); </script>
使用命名规则保护属性:
<script> class User { site = "baidu.com"; // 使用_代表被保护的属性 _age = 18; constructor(name) { this.name = name; } set age(age) { if (age < 0 || age > 100) { throw new Error('年龄不合法~') ; } this._age = age; } } let u = new User('user'); //开放属性可以在外部被更改 u.name = 'cyy'; u.site = 'taobao.com'; console.log(u); u.age = 101; console.log(u); </script>
使用Symbol定义protected属性:
<!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> <script> // const AGE = Symbol(); // class User { // site = "baidu.com"; // // 使用_代表被保护的属性 // // 实际上还是可以被修改的 // // _age = 18; // [AGE] = 18; // constructor(name) { // this.name = name; // } // set age(age) { // if (age < 0 || age > 100) { // throw new Error('年龄不合法~') // ; // } // // this._age = age; // this[AGE] = age; // } // get age() { // return this[AGE]; // } // } // let u = new User('user'); // //开放属性可以在外部被更改 // u.name = 'cyy'; // u.site = 'taobao.com'; // console.log(u); // // u.age = 101; // // console.log(u); // u.age = 66; // console.log(u); //关于继承 // const AGE = Symbol(); // class Common { // [AGE] = 18; // set age(age) { // if (age < 0 || age > 100) { // throw new Error('年龄不合法~') // ; // } // this[AGE] = age; // } // get age() { // return this[AGE]; // } // } // class User extends Common { // constructor(name) { // super();//必须在子类中使用super()调用父类的构造函数 // this.name = name; // } // } // let u = new User('user'); // u.age = 66; // console.log(u); //多个受保护的属性 const protectes = Symbol(); class Common { constructor() { this[protectes] = {}; this[protectes].age = 18; } set age(age) { if (age < 0 || age > 100) { throw new Error('年龄不合法~') ; } this[protectes].age = age; } get age() { return this[protectes].age; } } class User extends Common { constructor(name) { super();//必须在子类中使用super()调用父类的构造函数 this.name = name; } } let u = new User('user'); u.age = 66; console.log(u); </script></body></html>
使用WeakMap保护属性:
<!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> <script> // 继承的情况 // const host = new WeakMap(); // class Common { // constructor() { // host.set(this, 'baidu.com'); // } // set host(url) { // if (!/^https?/i.test(url)) { // throw new Error('网址不合法~'); // } // host.set(this, url); // } // get host() { // return host.get(this); // } // } // class User extends Common { // constructor() { // super();//调用父类的构造函数 // } // } // let u = new User(); // console.log(u); // console.log(u.host); // 不继承的情况 // const host = new WeakMap(); // class User { // constructor() { // host.set(this, 'baidu.com'); // } // set host(url) { // if (!/^https?/i.test(url)) { // throw new Error('网址不合法~'); // } // host.set(this, url); // } // get host() { // return host.get(this); // } // } // let u = new User(); // console.log(u); // console.log(u.host); // 多个属性值的情况 const protects = new WeakMap(); class User { constructor() { protects.set(this, { host: 'baidu.com', name: 'cyy' }); } set host(url) { if (!/^https?/i.test(url)) { throw new Error('网址不合法~'); } protects.set(this, { ...protects.get(this)['host'], url }); } get host() { return protects.get(this)['host']; } set name(name) { protects.set(this, { ...protects.get(this)['name'], name }); } get name() { return protects.get(this)['name']; } } let u = new User(); console.log(u); console.log(u.host); console.log(u.name); </script></body></html>
private私有属性使用:
<script> //私有属性不可被继承,只能在当前类使用,子类不能使用 class Common { #check() { if (this.name.length < 5) { throw new Error("名字长度不够呀~"); } console.log(true); } } class User extends Common { constructor(name) { this.name = name; super(); this.#check(); } } let u = new User('cyy111'); console.log(u); </script>
class属性继承原理:
<script> //构造函数中属性继承的原理 // function User(name) { // this.name = name; // } // function Admin(name) { // User.call(this, name);//继承属性 // } // Admin.prototype = Object.create(User.prototype);//会自动继承方法 // Admin.prototype.show = function () { // } // console.dir(Admin); //class使用super class Common { constructor(name) { this.name = name; } } class Admin extends Common { constructor(name) { super(name); } } let a = new Admin('cyy'); console.log(a); </script>
类的方法继承原理:
<!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> <script> // function User() { } // User.prototype.show = function () { console.log('user-show'); } // function Admin() { } // Admin.prototype = Object.create(User.prototype);//使用原型继承 // console.dir(Admin); // let a = new Admin(); // a.show(); class Common { show() { console.log('user-show'); } } class Admin extends Common { } let a = new Admin('cyy'); a.show(); </script></body></html>
super原理分析:
<!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> <script> //super访问父类 class Common { show() { console.log(this.name); } } class Admin extends Common { constructor(name) { super(); this.name = name; } show() { super.show();//只调用父类的方法,this仍然指向当前类 } } let a = new Admin('cyy'); a.show(); // let user = { // name: 'user', // show() { // // console.log('user-show'); // console.log(this.name); // } // } // let admin = { // name: 'admin', // __proto__: user, // show() { // //使用父类的方法 // //this.__proto__.show();//this指向父类 // this.__proto__.show.call(this);//this指向子类 // console.log('admin-show'); // } // } // console.log(admin); // admin.show(); </script></body></html>
多重继承中super的魅力:
<!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> <script> //注意:super只能在简写的方法中使用,不能在function中使用!!! // let common = { // show() { // console.log('common-show'); // } // } // let user = { // name: 'user', // __proto__: common, // show() { // this.__proto__.show.call(this);//this指向admin,因此无法访问common中的方法 // console.log(this.name); // } // } // let admin = { // name: 'admin', // __proto__: user, // show() { // this.__proto__.show.call(this);//this指向admin // console.log('admin-show'); // } // } // console.log(admin); // admin.show(); //使用super解决多重继承的问题 let common = { show() { console.log('common-show'); } } let user = { name: 'user', __proto__: common, show() { super.show(this); console.log(this.name); } } let admin = { name: 'admin', __proto__: user, show() { super.show(this);//调用父类的方法,this指向当前类 } } console.log(admin); admin.show(); </script></body></html>
为什么子类constructor中执行super:
<!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> <script> // function User(name) { // this.name = name; // } // function Admin(...args) { // User.call(this, ...args); // // User.apply(this,args); // } // let a = new Admin('admin'); // console.log(a); //子类没有constructor时,系统默认会使用super调用父类的constructor // class User { // constructor(name) { // this.name = name; // } // } // class Admin extends User { // } // let a = new Admin('admin'); // console.log(a); //子类中有constructor时,必须使用super用父类的constructor class User { constructor(name) { this.name = name; } } class Admin extends User { constructor() { super(); } } let a = new Admin('admin'); console.log(a); </script></body></html>
使用super访问父类方法:
<!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> <script> // class Controller { // total(data) { // return data.reduce((t, c) => t + c.price, 0); // } // } // class Lesson extends Controller { // constructor(data) { // super(); // this.data = data; // } // result() { // return { // totalPrice: super.total(this.data) // }; // } // } // let lessons = [ // { name: 'name1', price: 48 }, // { name: 'name2', price: 56 }, // { name: 'name3', price: 33 }, // ]; // let l = new Lesson(lessons); // console.log(l.result()); //多层继承 class Common { total(data) { return data.reduce((t, c) => t + c.price, 0); } } class Controller extends Common { } class Lesson extends Controller { constructor(data) { super(); this.data = data; } result() { return { totalPrice: super.total(this.data) }; } } let lessons = [ { name: 'name1', price: 48 }, { name: 'name2', price: 56 }, { name: 'name3', price: 33 }, ]; let l = new Lesson(lessons); console.log(l.result()); </script></body></html>
方法的重写:
<!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> <script> class Common { total(data) { return data.reduce((t, c) => t + c.price, 0); } getByKey(key) { return this.data.filter(item => item.name.includes(key)); } } class Controller extends Common { } class Lesson extends Controller { constructor(data) { super(); this.data = data; } result() { return { totalPrice: super.total(this.data) }; } //方法重写 getByKey(key) { return super.getByKey(key).map(item => item.name); } } let lessons = [ { name: 'html', price: 48 }, { name: 'html5', price: 56 }, { name: 'css3', price: 33 }, ]; let l = new Lesson(lessons); console.log(l.result()); console.log(l.getByKey('html')); </script></body></html>
静态继承原理:
<!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> <script> // function User() { } // User.name = 'user'; // User.show = function () { // console.log('show'); // } // function Admin() { } // Admin.__proto__ = User; // console.log(Admin.name); // Admin.show(); //作为函数的prototype和作为对象的__proto__ class User { static name = "user"; static show() { console.log('show'); } } class Admin extends User { } console.dir(Admin); </script></body></html>
使用instanceof检测对象实现:
<!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> <script> // function User() { } // function Admin() { } // Admin.prototype = Object.create(User.prototype); // let a = new Admin; // console.log(a instanceof Admin); // console.log(a instanceof User); // console.log(a.__proto__ == Admin.prototype); // User // console.log(Admin.prototype.__proto__ == User.prototype); // console.log(a.__proto__.__proto__ == Admin.prototype.__proto__); // console.log(a.__proto__.__proto__.__proto__ == Object.prototype); // console.log(a.__proto__.__proto__.__proto__.__proto__); //null // console.log(Object.prototype.__proto__ == null); // function checkPrototype(obj, constructor) { // if (!obj.__proto__) return false; // if (obj.__proto__ == constructor.prototype) return true; // return checkPrototype(obj.__proto__, constructor); // } // console.log(checkPrototype(a, Admin)); // console.log(checkPrototype(a, User)); // console.log(checkPrototype(a, Object)); //作为函数的prototype和作为对象的__proto__ class User { } class Admin extends User { } let a = new Admin; console.dir(a instanceof Admin); console.dir(a instanceof User); </script></body></html>
isPrototypeOf检测继承关系:
<!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> <script> // let a = {} // let b = { // __proto__: a //b的原型是a // } // console.log(a.isPrototypeOf(b));//检测a是不是b的原型 class Common { } class Admin extends Common { } let a = new Admin; console.log(Admin.prototype.isPrototypeOf(a)); console.log(Common.prototype.isPrototypeOf(a)); console.log(Admin.isPrototypeOf(a));//必须是对象进行判断 </script></body></html>
内置类继承的原型实现:
<!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> <script> function Arr(...args) { args.forEach(item => this.push(item)); console.log(this); this.first = function () { return this[0]; } this.max = function () { return this.sort((a, b) => b - a)[0]; } } Arr.prototype = Object.create(Array.prototype); let a = new Arr(1, 44, 66, 88, 3); console.log(a.first()); console.log(a.max()); </script></body></html>
使用继承增强内置类:
<!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> <script> class Arr extends Array { //可省略 // constructor(...args) { // super(...args); // } first() { return this[0]; } max() { return this.sort((a, b) => b - a)[0]; } add(item) { this.push(item); } remove(value) { let pos = this.findIndex(item => item == value); this.splice(pos, 1); } } let a = new Arr(1, 44, 66, 88, 3); // console.log(a.first()); // console.log(a.max()); a.push('cyy'); console.log(a); a.remove(44); console.log(a); </script></body></html>
mixin混合模式使用技巧:
<!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> <script> let Tool = { max(key) { return this.data.sort((a, b) => b[key] - a[key])[0]; } }; let Arr = { count(key) { return this.data.reduce((t, c) => t + c[key], 0); } }; let lessons = [ { name: 'html', price: 100, click: 46 }, { name: 'css', price: 44, click: 75 }, { name: 'js', price: 22, click: 395 }, ]; class Lesson { constructor(lessons) { this.lessons = lessons; } get data() { return this.lessons; } } Object.assign(Lesson.prototype, Tool, Arr); //继承Tool类的方法 let l = new Lesson(lessons); console.log(l.max('click')); console.log(l.max('price')); console.log(l.count('price')); console.log(l.count('click')); </script></body></html>
灵活的动画处理类:
<!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> .s1 { width: 200px; display: flex; flex-direction: column; } dt { background: orange; } dt:first-child { border-radius: 5px 5px 0 0; } dd { background: lightblue; margin: 0; height: 40px; overflow: hidden; } dd:last-child { border-radius: 0 0 5px 5px; } </style></head><body> <div class="slide s1"> <dt>html</dt> <dd>html-html</dd> <dt>css</dt> <dd>css-css</dd> <dt>js</dt> <dd>js-js</dd> </div> <script> class Anima { constructor(el) { this.el = el; this.defaultHeight = this.height; this.isShow = true; this.timeout = 5; } get height() { return window.getComputedStyle(this.el).height.slice(0, -2) * 1;//去除后面的px,*1是转数值类型 } set height(height) { this.el.style.height = height + 'px'; } hide(callback) { this.isShow = false; let id = setInterval(() => { if (this.height <= 0) { clearInterval(id); callback && callback(); return; } this.height = this.height - 1; }, this.timeout); } show(callback) { this.isShow = true; let id = setInterval(() => { if (this.height >= this.defaultHeight) { clearInterval(id); callback && callback(); return; } this.height = this.height + 1; }, this.timeout); } } // let el = document.querySelector('.s1'); // let anim = new Anima(el); // console.log(anim); // anim.hide(() => { // console.log('隐藏结束~'); // anim.show(() => { // console.log('展示结束~'); // }); // }); class Slide { constructor(el) { this.el = document.querySelector(el); this.links = this.el.querySelectorAll('dt'); this.panels = [...this.el.querySelectorAll('dd')].map(item => new Panel(item)); // console.log(this.panels); this.bind(); } bind() { this.links.forEach((item, i) => { item.addEventListener('click', () => { // console.log(i); // console.log('click'); this.action(i); }) }) } action(i) { Panel.hideAll(Panel.filter(this.panels, i), () => { this.panels[i].show(); }); } } class Panel extends Anima { static num = 0; static hideAll(items, callback) { if (Panel.num > 0) return; //有动画正在执行,则不继续执行 items.forEach(item => { Panel.num++; item.hide(() => { Panel.num--; }); }); callback && callback(); } static filter(items, i) { return items.filter((item, index) => index != i); } } let s = new Slide('.s1'); </script></body></html>
原文转载:http://www.shaoqun.com/a/493300.html
贝贝网:https://www.ikjzd.com/w/1321
心怡:https://www.ikjzd.com/w/1327
锦桥纺织网:https://www.ikjzd.com/w/2469
class声明类的语法:<script>//classcc{}//console.log(typeofcc);//letcc=class{};//console.log(typeofcc);//classUser{//show(){//console.log('show');//}//};//letu=newUser();//u.show();//functionLes
prime:prime
巴克莱银行:巴克莱银行
深圳特产是什么?哪里有深圳特产卖?:深圳特产是什么?哪里有深圳特产卖?
亚马逊listing关联销售,这些套路你都知道吗?:亚马逊listing关联销售,这些套路你都知道吗?
国庆去什刹海旅游有什么好玩的:国庆去什刹海旅游有什么好玩的
Comments
Post a Comment