Skip to main content

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;
})
}
}