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

  1. class Todo {
  2. @observable title = "";
  3. @observable finished = false;
  4. }

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

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

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

  1. class Car {
  2. color = 'red';
  3. }

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

  1. class Car {
  2. constructor() {
  3. this.color = 'red';
  4. }
  5. }

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

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

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

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

  1. class Car {
  2. static country = 'china';
  3. }

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

  1. class Car {
  2. static country = 'china';
  3. static getCountry = () => {
  4. return Car.country;
  5. }
  6. }

  现在就用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就可以了。

  1. const path = require('path');
  2.  
  3. module.exports = {
  4. module: {
  5. rules:[
  6. {
  7. test: /\.js$/,
  8. include: path.join(__dirname, 'src'),
  9. use: {
  10. loader: 'babel-loader',
  11. options: {
  12. plugins: ['transform-class-properties']
  13. }
  14. }
  15. }
  16. ]
  17. }
  18. }

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

  1. class Car {
  2. color = 'red';
  3. getColor = () => {
  4. return this.color;
  5. }
  6. static country = 'china';
  7. static getCountry = () => {
  8. return Car.country;
  9. }
  10. }
  11.  
  12. console.log(new Car().getColor())
  13. 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 好了。其次,装饰器是一个函数,它有默认参数, 那我们先声明两个函数, 一个作用到类上,一个作用到方法上,最后,装饰器作用到类中,用通过@函数名实现了。那基本框架如下:

  1. @time
  2. class Numberic {
  3.  
  4. @readonly
    add (num) {
      let sum = 0
      for (let index = 0; index < num; index++) {
        sum = sum + index;
      }
      return sum;
    }
  1. }
  2.  
  3. // 由于time函数,是装饰类的,所以它自动会获取到一个target参数,我们可以打印一下target,就是类本身
  4. function time(target) {
  5. console.log(target);
  6. }
  7. // 由于readonly是作用到类的方法上的,所以它获取到3个参数。
  8. function readonly(target, key, descriptor) {
  9. console.log(target);
  10. console.log(key);
  11. console.log(descriptor);
  12. }

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

  先来看time是怎么写的?

  1. function time(target) {
  2. const desc = Object.getOwnPropertyNames(target.prototype);
  3. for (let key of desc) {
  4. if (key === 'constructor') {
  5. continue;
  6. }
  7. const func = (target.prototype)[key];
  8.  
  9. if (typeof func === 'function') {
  10. Object.defineProperty(target.prototype, key, {
  11. value: function(...args) {
  12. console.time('time');
  13. let ret = func.apply(this, args);
  14. console.timeEnd('time');
  15. return ret;
  16. }
  17. })
  18. }
  19. }
  20. }

  在类中定义的方法,实际上都是定义在类的原型上,所以要对定义在类中所有方法都进行增强,就要在原型上先获得这些方法, 由于装饰的函数,自动会获得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 装饰器。

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

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

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

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

  1. function readonly(target, key, descriptor) {
  2. console.log(descriptor);
  3.  
  4. }

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

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

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

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

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

  1. 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. linux内存源码分析 - 内存回收(整体流程)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 当linux系统内存压力就大时,就会对系统的每个压力大的zone进程内存回收,内存回收主要是针对匿名页和文 ...

  2. Wireshark抓包分析TCP 3次握手、4次挥手过程

    Wireshark简介 更多有关Wireshark的教程.软件下载等,请见:http://www.52im.net/thread-259-1-1.html,本文只作简要介绍. 1Wireshark 是 ...

  3. Winform下透明Panel

    网上很多写着透明Panel的方法,都是把BackColor属性设置为透明,然后指定Parent,实验了一下,对于部分情况下,是可用的,例如下层本身有自带的控件,但是,如果是用Graphic绘制的内容, ...

  4. UI 前端参考

    :http://amazeui.org/ :http://www.dcloud.io/index.html :https://weui.io/ :http://m.sui.taobao.org/get ...

  5. Spring Cloud Config 分布式配置中心【Finchley 版】

    一. 介绍 1,为什么需要配置中心? 当服务部署的越来越多,规模越来越大,对应的机器数量也越来越庞大,靠人工来管理和维护服务的配置信息,变得困难,容易出错. 因此,需要一个能够动态注册和获取服务信息的 ...

  6. 关于eclipse tomcat 无法启动(8080,8005,8009端口被占用)的解决方法,附 eclipse tomcat 与 tomcat 并存方式

    eclipse 在编译运行时 新建的tomcat连接始终为stopped状态,描述为8080,8005,8009端口被占用. 这是因为在装完tomcat后,tomcat服务已启动,而eclipse仅仅 ...

  7. Codeblocks 遇到的问题 Cannot open output file, permission denied

    Codeblocks下运行C++的程序时,偶尔会出现  Cannot open output file, permission denied 的问题,导致不能够编译. 在 Stack Overflow ...

  8. Full Regularization Path for Sparse Principal Component Analysis

    目录 背景 Notation Sparse PCA Semidefinite Relaxation Low Rank Optimization Sorting and Thresholding 背景 ...

  9. 几个jdbc小技巧

    版本:jdk:1.6mysql-connector-5.0.8 1.如何用jdbc判断某个基本表是否存在 一种比较“笨”的方法:    try{         stmt.executeQuery( ...

  10. HTTPS的SSL证书配置

    SSL证书 TOMCAT7.0部署_百度经验https://jingyan.baidu.com/article/7082dc1c65066be40a89bda8.html SSL证书安装指引 - 青春 ...