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 ...
随机推荐
- .NET Core中延迟单例另一种写法【.NET Core和.NET Framework的beforefieldinit差异】
1.BeforeFieldInit是什么 前段时间在反编译代码时无意间看到在类中有一个BeforeFieldInit特性,处于好奇的心态查了查这个特性,发现这是一个关于字段初始化时间的特性[提前初始化 ...
- 错误 103 未能加载文件或程序集“Telerik.Web.UI”或它的某一个依赖项。磁盘空间不足。 (异常来自 HRESULT:0x80070070)
运行vs2010时出现错误: 错误 103 未能加载文件或程序集“Telerik.Web.UI”或它的某一个依赖项.磁盘空间不足. (异常来自 HRESULT:0x80070070) 处理方式:清理C ...
- 【原创】一个线程oom,进程里其他线程还能运行吗?
引言 这题是一个网友@大脸猫爱吃鱼给我的提问,出自今年校招美团三面的一个真题.大致如下 一个进程有3个线程,如果一个线程抛出oom,其他两个线程还能运行么? 先说一下答案,答案是还能运行 不瞒大家说, ...
- IntelliJ IDEA(四) :Settings(上)
前言 IDEA是一个智能开发工具,每个开发者的使用习惯不同,如何个性化自己的IDEA?我们可以通过Settings功能来设置.Settings文件是IDEA的配置文件,通过他可以设置主题,项目,插件, ...
- mybatis-高级结果映射之一对多
目录 1 数据准备 1.2 实体类, 接口和XML 2 一对多映射 2.1 collection集合映射 2.1.1 创建结果实体类 2.1.2 创建结果集 2.1.3 创建对应的方法和XML 2.1 ...
- RabbitMQ 发布订阅
互联网公司对消息队列是深度使用者,因此需要我们了解消息队列的方方面面,良好的设计及深入的理解,更有利于我们对消息队列的规划. 当前我们使用消息队列中发现一些问题: 1.实际上是异步无返回远程调用,由发 ...
- 两次console.log打印值不同
var a=[1,2,3] console.log(a); a[2]=10; console.log(a); // 打印结果 // (3) [1, 2, 3] // (3) [1, 2, 10] // ...
- 十二、存token获取token刷新token发送header头
//测试token //获取token function setToken(data){ var storage = window.localStorage; if(!storage){ alert( ...
- POJ - 1177 线段树
POJ - 1177 扫描线 这道题也算是一道扫描线的经典题目了. 只不过这道题是算周长,非常有意思的一道题.我们已经知道了,一般求面积并,是如何求的,现在我们要把扫描线进行改造一下,使得能算周长. ...
- 微信小程序学习笔记以及VUE比较
之前只是注册了一下微信小程序AppID,随便玩了玩HelloWorld!(项目起手式),但是最近看微信小程序/小游戏,崛起之势不可阻挡.小程序我来了!(果然,一入前端深似海啊啊啊啊啊~) 编辑器: S ...