Javascript教程第十四章:类--简化面向对象开发
Javascript教程第十四章:类--简化面向对象开发
类的内部操作实际上就是原型操作 类语法糖本质上就是上面提到的构造函数,constructor是函数的特殊值,方法会自动添加到构造函数的原型当中
一.类(简化面向对象开发)
类的内部操作实际上就是原型操作 类语法糖本质上就是上面提到的构造函数,constructor是函数的特殊值,方法会自动添加到构造函数的原型当中
1.class声明类的语法
class User{
    constructor(name){
        this.name = name;
    }
    getName(){
        return this.name;
    }
}
//在class语法当中添加的方法会默认添加到原型当中,并且设置为不可遍历,并且默认使用严格模式,所以函数中的this是默认为undefineed
2.class中的方法和静态方法
class User{
    show(){
        console.log("prototype.method")
    }
    static show(){
        console.log("__proto__.method")
    }
}s
User.show();            //默认添加至__proto__.method
new User().show();      //默认添加至prototype.method
3.静态属性之课程管理类
let data = [
    {name:"js",price:188},
    {name:"css",price:88},
    {name:"java",price:288},
]
class Lessons{
    constructor(data){
        this.model = data;
    }
    price(){
        return this.model.price;
    }
    name(){
        return this.model.name;
    }
    //批量处理使用static
    static createBatch(data){
        return data.map((item) => new Lessons(item))
    }
    //获取最高价格,对所有数据进行操作,使用静态方法
    static maxPrice(data){
        return data.sort((a,b) => (b.price - a.price))[0].price;
    }
}
4.class中使用命名规则保护属性的方法
1.规范一:
在类内部以_开头的通常为私有属性,且表示只能通过对象方法访问的属性,开发者应该遵循而不应该随意修改
class User{
    _url = "https://houdunren.com"
    constructor(name){
        this.name = name;
    }
    set url(newValue){
        //正则验证网址
        if(!/^https?:/i.test(newValue)){
            throw new Error("错误网址")
        }
        this._url = newValue;
    }
    get url(){
        return this._url;
    }
}
let hd = new User("hd")
// hd.url = "sss"                       //报错:错误网址
hd.url = "https://www.baidu.com"
console.log(hd.url);                    //https://www.baidu.com
上面我们通过set和get属性访问器来对私有属性进行了保护,但是我们仍然可以人为的修改_url,下面我们使用Symbol来定义protected
(1).使用Symbol保护属性
这种方式可以在本类及其子类中调用,我们将Symbol作为对象的属性名,调用set在其中压入需要被保护的值,这样我们外部就无法通过属性名称来直接获取到值,只能通过get,当然我们也可以给外部开放API
const protect = Symbol();
class User{
_url = "https://houdunren.com"
constructor(name){
this[protect] = {}
}
set url(newValue){
if(!/^https?:/i.test(newValue)){
throw new Error("错误网址")
}
this[protect].url = newValue;
}
get url(){
return this[protect].url;
}
}
let hd = new User("hd")
// hd.url = "sss" //报错:错误网址
hd.url = "https://www.baidu.com"
console.log(hd.url); //https://www.baidu.
(2).使用WeakMap保护属性
接下来我们通过WeakMap的不可迭代性来保护属性
const host = new WeakMap();
class User{
    _url = "https://houdunren.com"
    constructor(name){
        this.name = name;
        host.set(this,"houdunren")
    }
    set url(newValue){
        if(!/^https?:/i.test(newValue)){
            throw new Error("错误网址")
        }
        host.set(this,newValue)
    }
    get url(){
        return host.get(this);
    }
}
2.规范二:private私有属性使用
只能在本类中使用
class User{
    #host = "www.houdunren.com"
    constructor(name){
        this.name = name;
        this.#check(name)
    }
    set host(url){
        this.#host = url
    }
    //注意,方法定义私有的时候必须定义成变量形式
    #check = ()=>{
        if(this.name.length < 5){
            throw new Error ("名字不能小于五位") 
        }  
        return true;
    }
}
5.super在多重继承中的魅力
super只是进行原型攀升,this一直指向调用的对象,super调用上级原型的方法时,必须定义为show(),而不能定义成函数格式show:function(){}
6.使用类封装类似Jquery的隐藏显示效果
class Animation{
    constructor(el){
        this.el = el;
        this.isShow = true;
        this.defaultHeight = this.height;
    }
    set height(height){
        this.el.style.height = height + 'px';
    }
    get height(){
        return window.getComputedStyle(this.el).height.slice(0,-2)*1
    }
    hide(callback){
        this.isShow = false;
        let id = setInterval(() => { 
            if(this.height <= 0){
                clearInterval(id);
                callback && callback();
                return;
            }
            this.height = this.height - 1;
        }, 10);
    }
    show(callback){
        this.isShow = true;
        let id = setInterval(() => {
            if(this.height >= this.defaultHeight){
                clearInterval(id);
                callback && callback();
                return;
            }
            this.height = this.height + 1;
        }, 10);
    }
}
7.滑动效果和面板类动画
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((linksItem,index) => {
            linksItem.addEventListener("click",()=>{
                this.action(index);
            })
        });
    }
    //点击事件动作
    action(index){
        //隐藏后执行回调函数进行显示,防止动画异步
        Panel.hideAll(Panel.filter(this.panels,index),()=>{
            this.panels[index].show()
        });
    }
}
//面板类
class Panel extends Animation{
    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,index){
        return items.filter((item,i) => {
            return i != index;
        })
    }
}