MobX基础 ----- 类的静态属性和装饰器
当我们使用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
- }
- // 由于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基础 ----- 类的静态属性和装饰器的更多相关文章
- JS面向对象(3) -- Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- java类的静态属性值获取
获取某个类实例的静态属性: public class ErrorCode { private String code; private String message; private ErrorCod ...
- ES6入门六:class的基本语法、继承、私有与静态属性、修饰器
基本语法 继承 私有属性与方法.静态属性与方法 修饰器(Decorator) 一.基本语法 class Grammar{ constructor(name,age){ //定义对象自身的方法和属性 t ...
- python的类的 静态属性 类方法 静态方法
一.静态属性 静态属性说的就是数据属性 1.定义一个房间的类,求下这个房间的面积 class Room: def __init__(self,name,ower,width,length,heigh) ...
- java新手笔记11 类的静态属性、方法(单例)
1.Person类 package com.yfs.javase; public class Person { String name;//每个对象上分配 与对象绑定 int age; char se ...
- python - class类 (二) 静态属性/类方法/静态方法
静态属性: #静态属性 = 数据属性 (@property) class mianji(): def __init__(self,x,y): self.x = x self.y = y #类的函数方法 ...
- spring为类的静态属性实现注入
我们知道,正常情况下,spring的一个bean要依赖其他资源,如properties或其他bean,直接利用@Value或@Autowired就可以了.这两个注解就相当于spring applica ...
- PHP类知识----静态属性和方法
<?php class mycoach { public $name="陈培昌"; CONST hisage =; ; private $favorite = "喜 ...
- python学习之类和实例的属性;装饰器@property
无论是类还是实例,一切皆是对象. Python是强动态语言,和java在这点上有所不同. class Ab(): a = 666 # 定义类对象Ab,自带属性a,值为666 # 使用Ab.__dict ...
随机推荐
- linux内存源码分析 - 内存回收(整体流程)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 当linux系统内存压力就大时,就会对系统的每个压力大的zone进程内存回收,内存回收主要是针对匿名页和文 ...
- Wireshark抓包分析TCP 3次握手、4次挥手过程
Wireshark简介 更多有关Wireshark的教程.软件下载等,请见:http://www.52im.net/thread-259-1-1.html,本文只作简要介绍. 1Wireshark 是 ...
- Winform下透明Panel
网上很多写着透明Panel的方法,都是把BackColor属性设置为透明,然后指定Parent,实验了一下,对于部分情况下,是可用的,例如下层本身有自带的控件,但是,如果是用Graphic绘制的内容, ...
- UI 前端参考
:http://amazeui.org/ :http://www.dcloud.io/index.html :https://weui.io/ :http://m.sui.taobao.org/get ...
- Spring Cloud Config 分布式配置中心【Finchley 版】
一. 介绍 1,为什么需要配置中心? 当服务部署的越来越多,规模越来越大,对应的机器数量也越来越庞大,靠人工来管理和维护服务的配置信息,变得困难,容易出错. 因此,需要一个能够动态注册和获取服务信息的 ...
- 关于eclipse tomcat 无法启动(8080,8005,8009端口被占用)的解决方法,附 eclipse tomcat 与 tomcat 并存方式
eclipse 在编译运行时 新建的tomcat连接始终为stopped状态,描述为8080,8005,8009端口被占用. 这是因为在装完tomcat后,tomcat服务已启动,而eclipse仅仅 ...
- Codeblocks 遇到的问题 Cannot open output file, permission denied
Codeblocks下运行C++的程序时,偶尔会出现 Cannot open output file, permission denied 的问题,导致不能够编译. 在 Stack Overflow ...
- Full Regularization Path for Sparse Principal Component Analysis
目录 背景 Notation Sparse PCA Semidefinite Relaxation Low Rank Optimization Sorting and Thresholding 背景 ...
- 几个jdbc小技巧
版本:jdk:1.6mysql-connector-5.0.8 1.如何用jdbc判断某个基本表是否存在 一种比较“笨”的方法: try{ stmt.executeQuery( ...
- HTTPS的SSL证书配置
SSL证书 TOMCAT7.0部署_百度经验https://jingyan.baidu.com/article/7082dc1c65066be40a89bda8.html SSL证书安装指引 - 青春 ...