当我们使用MobX的时候,首先要声明一个store, 用来保存状态,它的最基本的语法 如下:

class Todo {
    @observable title = "";
    @observable finished = false;
}

  其中 @observable 是装饰器写法, title= ''; 是实例属性的新的写法,这两个语法是es7 中的提案,但都没有被采纳, 之所以被使用,是因为有babel 时进行转译。

  首先看一下类的实例属性的新写法, 这是ES7 中关于静态属性的一个提案, 在这个提案对实例属性和静态属性规定了新的写法。

  1,对于实例属性来说, 如果在使用的时候,就要对它进行初始化,那么可以直接在类的定义中用赋值方式进行初始化。

class Car {
    color = 'red';
}

  这样,我们就声明了一个实例属性color,并且它的初始值为 'red';  如果用以前的写法,我们要在类中定义constructor构造函数,然后在构造函数中写实例属性,

class Car {
    constructor() {
        this.color = 'red';
    }
}

  可以发现,新的ES7 提案,大大简化了写法。

  2, 不光是实例属性,实例方法也可以用这种赋值的方法进行初始化, 如果学习过react, 你可以已经见过这种写法了。

class Car {
    color = 'blue';
    // 直接用赋值的方法,对实例方法进行初始化
    getColor = () => {
        return this.color;
    }
}

  3, 静态属性就是在实例属性的前面加上static关键字, 它表示这个属性属于整个类,用类名加属性名进行读取。

class Car {
    static country = 'china';
}

  4,静态方法,就是在方法前面加上static, 也示表示它属于这个类。

class Car {
    static country = 'china';
    static getCountry = () => {
        return Car.country;
    }
}

  现在就用babel进行转译,使它能够在生产环境中使用,为了通用性,我们使用webpack 进行配置。现在是webpack4, 我们也使用一下。新建mobx文件夹,npm init -y 生成package.json文件,安装依赖, 这里要注意,webpack4 把命令行抽离成了一个单独的包webpack-cli,所以安装webpack时,要安装webpack-cli, 否则不能使用webpack打包命令。

npm install webpack webpack-cli webpack-cli --save-dev.  对类进行转译,用到一个babel核心插件 babel-plugin-transform-class-properties. npm install babel-core babel-loader babel-plugin-transform-class-properties --save-dev. 再来写webpack.config.js, 这里比原来要简单,因为webpack4 提出一个零配置概念。默认入口文件 src/index.js, 输出文件 dist/main.js 文件,

同时提供了一个mode 配置选项,用来表示生产环境还是测试环境,那么webpack.config.js中只写module就可以了。

const path = require('path');

module.exports = {
    module: {
        rules:[
            {
                test: /\.js$/,
                include: path.join(__dirname, 'src'),
                use: {
                    loader: 'babel-loader',
                    options: {
                        plugins: ['transform-class-properties']
                    }
                }
            }
        ]
    }
}

  现在建立入口文件, 新建src目录,再在里面新建index.js文件, 把上面的代码都写到里面。

class Car {
    color = 'red';
    getColor = () => {
        return this.color;
    }
    static country = 'china';
    static getCountry = () => {
        return Car.country;
    }
}

console.log(new Car().getColor())
console.log(Car.getCountry())

  现在就执行打包命令了, 在package.json文件中的scripts字段中,写上 "build": "webpack  --mode production",  --mode production , 就是在webpack4要求指定的mode 参数。npm run build 执行打包命令,完成后,可以看到多了个dist目录,里面有一个main.js文件,因为它是一个js 文件,我们直接用node 执行一下就好了,node main.js 可以看到l输出了 red, china,打包没有问题,说明也编译成功了。

  现在再来看装饰器,它的主要作用是来装饰一个类或类中的属性或方法,也就是说,它只能作用在class上,目的呢,则是对这个类,或属性方法,进行功能增强。怎么进行增强呢?  这就要说到装饰器的本质,它本身是一个函数,当js在进行编译的时候,会为这个函数注入默认的参数,如果作用到类上,则这个函数自动会获取到一个target的参数,表示这个类本身。

如果作用属性或方法上,则会为函数注入3个参数,target, key, descriptor, target 表示这个装饰的函数所属的对象,key 表示装饰的函数名称,descriptor, 装饰的函数的描述符,这三个参数和Obeject.defineProperty 的三个属性一致,为哪个对象的,哪个属性,设置怎么样的descriptor. 当函数获取到参数以后,就可以在函数内作任意的操作,所以可以进行增强。装饰器的语法是怎么样的,它是怎么作用到类上。语法其实很简单,就是在函数名的前面加@, 然后放到类或方法的上面,和java的注解一样。现在我们来体验一个装饰器,不过还是要先配置一个webpack, 装饰器的编译依赖一个核心插件,babel-plugin-transform-decorators-legacy. npm install 安装完成后,在webapck.config.js中的plugins进行配置。

  好了,基础搭建已经完成,我们就来学习装饰器了,首先装饰器要作用在类上,我们要先定义在一个类,名字就叫Numberic 好了。其次,装饰器是一个函数,它有默认参数, 那我们先声明两个函数, 一个作用到类上,一个作用到方法上,最后,装饰器作用到类中,用通过@函数名实现了。那基本框架如下:

@time
class Numberic {

    @readonly
    add (num) {
      let sum = 0
      for (let index = 0; index < num; index++) {
        sum = sum + index;
      }
      return sum;
    }
}

// 由于time函数,是装饰类的,所以它自动会获取到一个target参数,我们可以打印一下target,就是类本身
function time(target) {
    console.log(target);
}
// 由于readonly是作用到类的方法上的,所以它获取到3个参数。
function readonly(target, key, descriptor) {
    console.log(target);
    console.log(key);
    console.log(descriptor);
}

  这两个装饰器time, readonly 要对它装饰的类或函数起到什么增强作用呢? time, 我们来计算类的原型上所有方法的执行时间.  readonly, 则表示这个方法不可以被复写。

  先来看time是怎么写的?

function time(target) {
    const desc = Object.getOwnPropertyNames(target.prototype);
    for (let key of desc) {
        if (key === 'constructor') {
            continue;
        }
        const func = (target.prototype)[key];

        if (typeof func === 'function') {
            Object.defineProperty(target.prototype, key, {
                value: function(...args) {
                    console.time('time');
                    let ret = func.apply(this, args);
                    console.timeEnd('time');
                    return ret;
                }
            })
        }
    }
}

  在类中定义的方法,实际上都是定义在类的原型上,所以要对定义在类中所有方法都进行增强,就要在原型上先获得这些方法, 由于装饰的函数,自动会获得target, 所以target.prototype就可以获得原型。由于原型是一个对象,所以获取它上面的方法,就要获取到对象的属性,然后进行遍历。所以time函数的第一个句,就是用getOwnPropertyNames获取整个原型对象的属性名,这里打印一下,可以知道结果,是一个数组["constructor", "add"], 注意这里不要使用keys 方法,因为Object.keys()获取的是一个对象上的可枚举属性,而在原型上定义的方法,都是不可以枚举的,如果使用Object.keys(), 这里将会得到空数组。Object.getOwnProperyNames 可以获取到对象的非枚举属性,所以在这里使用没有问题。

  然后使用了for of 对["constructor", "add"]数组进行编历,首先要去除构造函数,因为构造函数用来创建对象的,所以使用了 if (key === 'constructor') ,那么剩下的key值,就是我们想要的了,比如在这里key 为add. 我们声明了一个func变量来获取到属性值,这里也可以打印一下, 它是一个函数。

   现在获取到了原型对象上的所有属性或对应的属性值,那现在就要对它进行增强,这时你会看到, 我们是用Object.defineProperty 重新给属性定义了一个新的函数,key 就是指代我们的add, value 就是给add 重新定义的方法,在value中,我们是用apply 方法,调用了原方法func.apply ,所以原有的方法,不会消失,正常使用。但是我们在方法的调用前后,分别调用了console.time 和console.timeend 来计算时间,所以我们对原来的函数进行了增强。

  这时我们声明一个Numberic 对象,来体验一下time 装饰器。

let obj = new Numberic();
console.log(obj.add(1000));

  这时控制台上输出结果,同时输出了计算时间,看来我们的装饰器time 起作用了。

  所谓的装饰器,就是获取到对象原来定义属性,或属性值,然后用Object.defineProperty 方法重新定义新的属性或属性值,在新的属性值里面,调用原有方法的同时,增加新的功能,这样,原的方法调用了,同时增加了新的功能,所以增强了。

  现在我们再来看一个readonly装饰器,它不可复写,就设置它的属性描述符writable: false.就好了, 由于它是装饰单个方法,所以它自动会获取到descriptor 属性,它就是属性描述符。

function readonly(target, key, descriptor) {
    console.log(descriptor);

}

  这时可以看到add完整的属性描述符,writable 为true,  表示可以复写,那直接修改为false 就可以了。

function readonly(target, key, descriptor) {
    descriptor.writable = false;
}

  readonly 装饰器就写完了。我们来测试一下, 组obj增加一个add 方法,

obj.add = function() {
    console.log('add');
}

  如果如被复写,它就是调用我们新写的方法,输出add.

console.log(obj.add(1000));

  可以看到,控制台仍然输出的是1000的和,表示add函数并没有被复写。

  

MobX基础 ----- 类的静态属性和装饰器的更多相关文章

  1. JS面向对象(3) -- Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法

    相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...

  2. java类的静态属性值获取

    获取某个类实例的静态属性: public class ErrorCode { private String code; private String message; private ErrorCod ...

  3. ES6入门六:class的基本语法、继承、私有与静态属性、修饰器

    基本语法 继承 私有属性与方法.静态属性与方法 修饰器(Decorator) 一.基本语法 class Grammar{ constructor(name,age){ //定义对象自身的方法和属性 t ...

  4. python的类的 静态属性 类方法 静态方法

    一.静态属性 静态属性说的就是数据属性 1.定义一个房间的类,求下这个房间的面积 class Room: def __init__(self,name,ower,width,length,heigh) ...

  5. java新手笔记11 类的静态属性、方法(单例)

    1.Person类 package com.yfs.javase; public class Person { String name;//每个对象上分配 与对象绑定 int age; char se ...

  6. python - class类 (二) 静态属性/类方法/静态方法

    静态属性: #静态属性 = 数据属性 (@property) class mianji(): def __init__(self,x,y): self.x = x self.y = y #类的函数方法 ...

  7. spring为类的静态属性实现注入

    我们知道,正常情况下,spring的一个bean要依赖其他资源,如properties或其他bean,直接利用@Value或@Autowired就可以了.这两个注解就相当于spring applica ...

  8. PHP类知识----静态属性和方法

    <?php class mycoach { public $name="陈培昌"; CONST hisage =; ; private $favorite = "喜 ...

  9. python学习之类和实例的属性;装饰器@property

    无论是类还是实例,一切皆是对象. Python是强动态语言,和java在这点上有所不同. class Ab(): a = 666 # 定义类对象Ab,自带属性a,值为666 # 使用Ab.__dict ...

随机推荐

  1. DataX

    #!/bin/bash[ ! -d /opop ] && mkdir /opopcd /opopwget http://192.168.1.129/package/DataX/{jdk ...

  2. Nodejs mongoose 详解

    前言 Mongoose 是在nodejs环境下,对mongodb进行便捷操作的对象模型工具.本文介绍解(翻)密(译)Mongoose插件. Schema 开始我们就要讲到Schema,一个Schema ...

  3. 【LeetCode-数组篇】 1 Two Sum

    1 前言 之所以开始刷 LeetCode 上的算法题,一是快面临秋招,第二点是因为提升自己的编程能力,坚持两个月,希望博友们监督. 这个系列打算用 C# 和 Java 编程,为什么用两门语言,因为经历 ...

  4. 朱晔的互联网架构实践心得S1E4:简单好用的监控六兄弟

    朱晔的互联网架构实践心得S1E4:简单好用的监控六兄弟 [下载本文PDF进行阅读] 这里所说的六兄弟只指ELK套件(ElasticSearch+Logstash+Kibana)以及TIG套件(Tele ...

  5. 从 0 到 1 实现 React 系列 —— 2.组件和 state|props

    看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...

  6. js判断当前浏览器页面是否切换

    公司做mifi设备,ui界面很多信息需要1S钟不断异步请求更新信息,如果同时打开多个浏览器或者多个当前界面,设备1S钟会收到很多个请求,由于设备本身内存限制,会导致响应速度过慢,且会造成设备重启等. ...

  7. Python-类的组合与重用

    软件重用的重要方式除了继承之外还有另外一种方式,即:组合 组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合 1.继承的方式 通过继承建立了派生类与基类之间的关系,它是一种'是'的关系 ...

  8. 使用mysql,sql语言删除冗余信息

    这是表,我们需要操作的就是删除除了学号不同,其它信息都相同的冗余信息 思路:删除表格class3中的冗余的stu_id信息,那么接下来我们应该去筛选哪些stu_id信息是冗余的, 此时我们想到的就是利 ...

  9. 斐波那契数列yield表示

    def fib(num): n=0 a,b=0,1 while n<num: print(b) yield a,b=b,a+b n=n+1a=fib(30)next(a)next(a)  

  10. 微信开发 提示 Redirect_uri(错误10003)

    情景: 搭建完成一个网站,使用微信打开链接地址,结果报错1003 完整的错误信息: 出现这种情况一般有两种原因: 1.没有配置网页授权  我们可以根据微信的开发者文档http://mp.weixin. ...