JavaScript面向对象和模块化基础(一)

418 阅读5分钟

主要知识点

  • ES6中类的使用
  • ES6静态方法和属性,ES2020私有方法和属性
  • ES6中继承extends、super
  • ES2020新特性
  • ES6中模块化import、export

面向对象主要是一种思维方式,将程序的共性组装成一个对象,在从对象中抽离成一个类研究他们之间共性的一种思考方式。所以可能最后程序结果可以没有变化,但是编写代码的思考方式会和面向过程的第一步做什么,第二步做什么的思维方式不一样。这样做可以让代码的扩展性更强,复用性更强

类的基本使用

  • 通过的类的关键字创建一个类。同时要给出一个构造方法,里面一般会存储这个类的的属性成员
  • 类中还可以有成员特有的方法,这个方法会放在Object prototype 的公共空间中,这样可以节省空间。不需要再构造函数中声明这个成员特有的方法。
  • 使用的时候只需new 一个实例。构造函数中的this 指向这个实例。同 . 运算符可以访问到类的属性成员和特有方法
  • 类实际上是一个函数, console.log(typeof Cat); // function
class Cat{
	    constructor(name) { //类的的属性成员
	        this.name = name;
	        this.age = 1;
	        this.sex = "female";
        }
        voice(){ //成员特有的方法 
	        console.log("喵");
		}
	}

	let cat = new Cat('小花');
    console.log(cat.name,cat.age,cat.sex);
	cat.voice();
	console.log(cat); //结果如下图
//小花 1 female 
//喵
  • console.log(cat);

s6roct.png

类的静态成员(es6)和私有成员(es2020)

  • 类的静态成员是属于类本身的成员,它不需要实例化直接 类名.成员 就可以使用。static 关键词来声明静态成员

    	//静态成员
    	class Cat{
    	    static nickname = "吸猫薄荷会上瘾";
    	    constructor(name) {
    	        this.name = name;
    	        this.age = 1;
    	        this.sex = "female";
            }
            static jump (){
                console.log("i can jump");
    		}
            voice(){
    	        console.log("喵");
    		}
    	}
    
        console.log(Cat.nickname);
    	Cat.jump();
    
  • 类的私有成员是属于类私有的成员,它不允许外部访问,但是可以通过公有方法访问。# 关键词来声明私有成员

    • 外部访问私有属性会返回undefined;
    • 私有成员可以是方法或者变量
    • 如果你封装库里面不想暴露属性,可以使用私用成员
    	//私有成员
    	class Cat{
    		#nickname = "吸猫薄荷会上瘾";
    	    constructor(name) {
    	        this.name = name;
    	        this.age = 1;
    	        this.sex = "female";
            }
    		#jump (){
                console.log("i can jump");
    		}
            voice(){
    	        console.log("喵");
    			this.#jump();
    		}
    		getNickname(){
    	        return this.#nickname;
    		}
    	}
        let cat = new Cat('小花');
        //console.log(cat.nickname); //undefined  webstorm tip: 没有 #-语法无法引用 private 成员
        console.log(cat.getNickname());
        cat.voice();
    

类的继承

通过extends 关键字继承父类。

  • 子类的构造函数要使用super(参数)继承父类的构造方法。注意,子类的属性要写在super后面

  • 如果子类的方法和父类方法同名那么就会重写父类的方法,如果不想重写父类的方法可以在方法中super.方法名执行父类的方法。

  • 私有成员不能继承

        //继承
        class Father {
            constructor(height) {
                this.name = 'baba';
                this.age = 30;
                this.height = height;
            }
            run(){
                console.log('run...')
    		}
        }
    
        class Son extends Father{
            constructor(height) {
                super(height);
                this.hobby = 'read books';
            }
            run(){
                super.run();
                console.log('Son run');
    		}
    	}
    
    	let son = new Son('183cm');
        console.log(son.name,son.age,son.height,son.hobby);
        son.run();
    
    //result
    baba 30 183cm read books
    run...
    Son run
    
    

ES2020新特性

  • 合并空运算符(ES2020)

    有时候我们想取到空值,但是传统判断语法中,空值默认为false,就会取默认值不会取到我们想要的空值。那么通过 ??空值运算符就可以取到

    let str = 0;
    let res = str || 1;
    console.log(res);   // 1;
    
    let str = 0;
    let res = str ?? 1;
    console.log(res);  // 0
    
    
  • 可选的链接操作(ES2020)

    如果要访问对象的深层嵌套属性,则必须通过很长的布尔表达式去检查每个嵌套级别中的属性。必须检查每个级别中定义的每个属性,直到所需的深度嵌套的属性为止。

    如果在任何级别的对象中都有 undefined 或 null 的嵌套对象,如果不进行检查,那么的程序将会崩溃。这意味着我们必须检查每个级别,以确保当它遇到 undefined 或 null 对象时不会崩溃。

    **使用可选链运算符,只需要使用 ?. 来访问嵌套对象。**而且如果碰到的是 undefined 或 null 属性,那么它只会返回 undefined。

    let person = {};
    console.log(person.myname?.age) //undefined
    

ES6模块化import、export

  • 旧的模块化
    • AMD
    • CMD

简单的说就是,我们实现一个应用时(不管是web、桌面还是移动端),通常都会按照不同的功能,分割成不同的模块来编写,编写完之后按照某种方式组装起来成为一个整体,最终实现整个系统的功能。

模块化的特性:

  • 模块化防止变量的污染。

  • 各个模块可独立工作,即便单组模块出现故障也不影响整个系统工作

  • 各模块按需自动加载。确保每个模块高效运行,又能节约资源,提高效率。

esm模块

运用ES6模块化 需要把script 加上type="module"属性。说明这个script是可以使用模块的

export

  • export default 只能声明一次,他是一个默认导出口。

  • export + 变量 、方法可以多个。

  • 导出方式

    export let name =  obj.name; //导出变量
    export let danceFn =  dance;  //导出函数
    export let c = ()=>{console.log("I am c function...")} //导出函数(新增)
    export default obj;
    

    partA.js

const obj = {
    name: 'Lily',
    age : 20,
    height: '160cm'
}
function dance() {
    console.log('hobby dance');
}

export let name =  obj.name; //导出变量
export let danceFn =  dance;  //导出函数
export let c = ()=>{console.log("I am c function...")} //导出函数(新增)
export default obj;

import

  • import关键词 后面跟着变量 然后声明关键字from后面接路径。
  • 变量的必须是 export 中有声明导出的变量
  • as关键词可以将导入的变量更变名字
  • *关键词可以将所有声明导出的变量存在一个 Module {Symbol(Symbol.toStringTag): "Module"}对象中。里面有全部的声明导出的变量。
<script type="module">
	import obj from './js/PartA.js';
    import {name,danceFn} from './js/PartA.js';
    import * as person from './js/PartA.js'
    console.log(obj);
    console.log(name,danceFn);
    console.log(person)
</script>

//

s6jGm6.png

按需导入(es2020)

  • 方法一 链式操作的方法。它调用import 后会返回一个promise对象。然后这个promise对象de response方法可以拿到所有导出的变量和方法 得到的是一个 Module {Symbol(Symbol.toStringTag)对象

    document.onclick = function () {
    		import ('./js/PartA.js').then(res => console.log(res));
        }
    
  • 方法二 async await 方法 用异步的操作写成同步的方法

document.onclick =async function(){
  
    let res = await import("./fn.js");
    console.log(res);
}

面向对象和模块化需求分析思路(实例)

例子:取自王者荣耀

需求:玩家用户名登录,登录后显示用户名和该用户拥有的英雄。点击英雄后显示技能和皮肤按钮,可以选择皮肤。

思考:

sc8301.png

github 王者小案例