当前位置: 首页 > news >正文

如何在网站上做标记圈信息网站怎么优化关键词

如何在网站上做标记圈信息,网站怎么优化关键词,台州wordpress,网站开发工资低pablo.pngDecorators 是ES7中添加的JavaScript新特性。熟悉Typescript的同学应该更早的接触到这个特性,TypeScript早些时候已经支持Decorators的使用,而且提供了ES5的支持。本文会对Decorators做详细的讲解,相信你会体验到它给编程带来便利和…

pablo.png

Decorators 是ES7中添加的JavaScript新特性。熟悉Typescript的同学应该更早的接触到这个特性,TypeScript早些时候已经支持Decorators的使用,而且提供了ES5的支持。本文会对Decorators做详细的讲解,相信你会体验到它给编程带来便利和优雅。

我在专职做前端开发之前, 是一名专业的.NET程序员,对.NET中的“特性”使用非常熟悉。在类、方法或者属性上写上一个中括号,中括号里面初始化一个特性,就会对类,方法或者属性的行为产生影响。这在AOP编程,以及ORM框架中特别有用,就像魔法一样。 但是当时JavaScript并没有这样的特性。在TypeScript中第一次使用Decorators,是因为我们要对整个应用程序的上下文信息做序列化处理,需要一种简单的方法,在原来的领域模型上打上一个标签来标识是否会序列化或者序列化的行为控制,这种场景下Decorators发挥了它的威力。 后来我们需要重构我们的状态管理,在可变的类定义和不可变对象的应用间进行转换,如果使用Decorators,不论从编的便利性还是解耦的角度都产生了令人惊喜的效果。 一直想把Decorators的相关使用整理出一个通俗的文档,使用最简单的方式来阐述这一话题,一直没有下笔。无意间在网络上发现了一篇文章(https://cabbageapps.com/fell-love-js-decorators/) , 这篇文章的行文和我要表达的内容正好相符,于是拿过来做重新编辑和改编。喜欢看英文的同学可以点击链接阅读原文。

giphy.gif

1.0 装饰器模式

如果我们在搜索引擎中直接搜索“decorators”或者“装饰器”,和编程相关的结果中,会看到设计模式中的装饰器模式的介绍。

3.png

更直观的例子如下:

4.png

上图中WeaponAccessory就是一个装饰器,他们添加额外的方法和熟悉到基类上。如果你看不明白没关系,跟随我一步步地实现你自己的装饰器,自然就会明白了。下面这张图,可以帮你直观的理解装饰器。

5.gif

我们简单的理解装饰器,可以认为它是一种包装,对对象,方法,熟悉的包装。当我们需要访问一个对象的时候,如果我们通过这个对象外围的包装去访问的话,被这个包装附加的行为就会被触发。例如 一把加了消声器的枪。消声器就是一个装饰,但是它和原来的枪成为一个整体,开枪的时候消声器就会发生作用。

从面向对象的角度很好理解这个概念。那么我们如何在JavaScript中使用装饰器呢?

1.1 开始 Decorators 之旅

Decorators 是ES7才支持的新特性,但是借助Babel 和 TypesScript,我们现在就可以使用它了, 本文以TypesScript为例。

首先修改tsconfig.json文件,设置 experimentalDecorators 和 emitDecoratorMetadata为true。

{"compilerOptions": {"target": "es2015","module": "commonjs","sourceMap": true,"emitDecoratorMetadata": true,"experimentalDecorators": true},"exclude": ["node_modules",]
}

 

6.png

我们先从效果入手,然后再层层剖析。先看下面的一段代码:

function leDecorator(target, propertyKey: string, descriptor: PropertyDescriptor): any {var oldValue = descriptor.value;descriptor.value = function() {console.log(`Calling "${propertyKey}" with`, arguments,target);let value = oldValue.apply(null, [arguments[1], arguments[0]]);console.log(`Function is executed`);return value + "; This is awesome";};return descriptor;}class JSMeetup {speaker = "Ruban";//@leDecorator
    welcome(arg1, arg2) {console.log(`Arguments Received are ${arg1} ${arg2}`);return `${arg1} ${arg2}`;}}const meetup = new JSMeetup();console.log(meetup.welcome("World", "Hello"));

 

7.png

运行上面的代码,得到的结果如下:

8.png

下面我们修改代码,将第17行的注释放开。

9.png

再次运行代码,结果如下:

10.png

注意上图中左侧的输出结果,和右侧显示的代码行号。我们现在可以肯定的是,加上了 @leDecorator 标签之后,函数welcome的行为发生了改变,触发改变的地方是leDecorator函数。 根据我们上面对装饰器的基本理解,我们可以认为leDecorator是welcome的装饰器。
<b>装饰器和被装饰者之间通过 @ 符进行连接</b>。

在JavaScript层面我们已经感性的认识了装饰器,我们的代码装饰的是一个函数。在JavaScript中,一共有4类装饰器:

  • Method Decorator 函数装饰器
  • Property Decorators 熟悉装饰器
  • Class Decorator 类装饰器
  • Parameter Decorator 参数装饰器

下面我们逐一进行攻破!Come on!

11.jpg

1.2 函数装饰器

第一个要被攻破的装饰器是函数装饰器,这一节是本文的核心内容,我们将通过对函数装饰器的讲解来洞察JavaScript Decorators的本质。

通过使用 函数装饰器,我们可以控制函数的输入和输出。

下面是函数装饰器的定义:

MethodDecorator = <T>(target: Object, key: string, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | Void;

只要遵循上面的定义,我们就可以自定义一个函数装饰器,三个参数的含义如下:

  • target -> 被装饰的对象
  • key -> 被装饰的函数名
  • descriptor -> 被传递过来的属性的属性描述符. 可以通过 Object.getOwnPropertyDescriptor()方法来查看属性描述符。

关于属性描述符更详细内容 可以参考 https://www.jianshu.com/p/19529527df80。

简单来讲,属性描述符可以用来配置一个对象的某个属性的返回值,get/set 行为,是否可以被删除,是否可以被修改,是否可以被枚举等特性。为了你能顺畅的理解装饰器,我们下面看一个直观一点的例子。

打开浏览器控制台,输入如下代码:

var o, d;
var o = { get foo() { return 17; }, bar:17, foobar:function(){return "FooBar"} };d = Object.getOwnPropertyDescriptor(o, 'foo');
console.log(d);
d = Object.getOwnPropertyDescriptor(o, 'bar');
console.log(d);
d = Object.getOwnPropertyDescriptor(o, 'foobar');
console.log(d);

 

结果如下:

12.png

这里我们定义了一个对象o,定义了三个属性——foo,bar和foobar,之后通过Object.getOwnPropertyDescriptor()获取每个属性的描述符并打印出来。下面我们对value , enumerable , configurable 和 writable 做简要的说明。

  • value – >字面值或者函数/属性计算后的返回值。
  • enumerable -> 是否可以被枚举 (是否可以在 (for x in obj)循环中被枚举出来)
  • configurable – >属性是否可以被配置
  • writable -> 属性是否是可写的.

每个属性或者方法都有自己的一个描述符,通过描述符我们可以修改属性的行为或者返回值。下面关键来了:

<b>装饰器的本质就是修改描述符</b>

是时候动手写一个装饰器了。

1.2.1 方法装饰器实例

下面我们通过方法装饰器来修改一个函数的输入和输出。

function leDecorator(target, propertyKey: string, descriptor: PropertyDescriptor): any {var oldValue = descriptor.value;descriptor.value = function() {console.log(`Calling "${propertyKey}" with`, arguments,target);// Executing the original function interchanging the argumentslet value = oldValue.apply(null, [arguments[1], arguments[0]]);//returning a modified valuereturn value + "; This is awesome";};return descriptor;}class JSMeetup {speaker = "Ruban";//@leDecorator
    welcome(arg1, arg2) {console.log(`Arguments Received are ${arg1}, ${arg2}`);return `${arg1} ${arg2}`;}}const meetup = new JSMeetup();console.log(meetup.welcome("World", "Hello"));

 

在不使用装饰器的时候,输出值为:

Arguments Received are World, Hello
World Hello

启用装饰器后,输出值为:

Calling "welcome" with { '0': 'World', '1': 'Hello' } JSMeetup {} Arguments Received are Hello, World Hello World; This is awesome 

我们看到,方法输出值发成了变化。现在去看我们定义的方法装饰器,通过参数,leDecorator在执行时获取了调用对象的名称,被装饰方法的参数,被装饰方法的描述符。 首先通过oldValue变量保存了方法描述符的原值,即我们定义的welcome方法。接下来对descriptor.value进行了重新赋值。

13.png

在新的函数中首先调用了原函数,获得了返回值,然后修改了返回值。 最后return descriptor,新的descriptor会被应用到welcome方法上,此时整合函数体已经被替换了。

通过使用装饰器,我们实现了对原函数的包装,可以修改方法的输入和输出,这意味着我们可以应用各种想要的魔法效果到目标方法上。

14.gif

这里有几点需要注意的地方:

  • 装饰器在class被声明的时候被执行,而不是class实例化的时候。
  • 方法装饰器返回一个值
  • 存储原有的描述符并且返回一个新的描述符是我们推荐的做法. 这在多描述符应用的场景下非常有用。
  • 设置描述符的value的时候,不要使用箭头函数。

现在我们完成并理解了第一个方法装饰器。下面我们来学校属性装饰器。

1.3 属性装饰器

属性装饰器和方法装饰器很类似,通过属性装饰器,我们可以用来重新定义getters、setters,修改enumerable, configurable等属性。

属性装饰器定义如下:

PropertyDecorator = (target: Object, key: string) => void; 

参数说明如下:

  • target:属性拥有者
  • key:属性名

在具体使用属性装饰器之前,我们先来简单了解下Object.defineProperty方法。Object.defineProperty方法通常用来动态给一个对象添加或者修改属性。下面是一段示例:

var o = { get foo() { return 17; }, bar:17, foobar:function(){return "FooBar"} };Object.defineProperty(o, 'myProperty', {
get: function () {
return this['myProperty'];
},
set: function (val) {
this['myProperty'] = val;
},
enumerable:true,
configurable:true
});

 

16.png

在调试控制台测试上面的代码。

15.png

从结果中,我们看到,利用Object.defineProperty,我们动态添给对象添加了属性。下面我们基于Object.defineProperty来实现一个简单的属性装饰器。

function realName(target, key: string): any {// property valuevar _val = target[key];// property gettervar getter = function () {return "Ragularuban(" + _val + ")";};// property settervar setter = function (newVal) {_val = newVal;};// Create new property with getter and setter
    Object.defineProperty(target, key, {get: getter,set: setter});}class JSMeetup {//@realNamepublic myName = "Ruban";constructor() {}greet() {return "Hi, I'm " + this.myName;}}const meetup = new JSMeetup();console.log(meetup.greet());meetup.myName = "Ragul";console.log(meetup.greet());

 

17.png

在不适用装饰器时,输出结果为:

Hi, I'm Ruban
Hi, I'm Ragul

启用装饰器之后,结果为:

Hi, I'm Ragularuban(Ruban)
Hi, I'm Ragularuban(Ragul)

是不是很简单呢? 接下来是Class装饰器。

1.4 Class 装饰器

Class装饰器是通过操作Class的构造函数,来实现对Class的相关属性和方法的动态添加和修改。
下面是Class装饰器的定义:

ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction; 

ClassDecorator只接收一个参数,就是Class的构造函数。下面的示例代码,修改了类原有的属性speaker,并动态添加了一个属性extra。

function AwesomeMeetup<T extends { new (...args: any[]): {} }>(constructor: T) {return class extends constructor implements extra {speaker: string = "Ragularuban";extra = "Tadah!";}}//@AwesomeMeetup
  class JSMeetup {public speaker = "Ruban";constructor() {}greet() {return "Hi, I'm " + this.speaker;}}interface extra {extra: string;}const meetup = new JSMeetup() as JSMeetup & extra;console.log(meetup.greet());console.log(meetup.extra);

 

在不启用装饰器的情况下输出值为:

18.png

在启用装饰器的情况下,输出结果为:

19.png

这里需要注意的是,<b>构造函数只会被调用一次</b>。

下面我来学习最后一种装饰器,参数装饰器。

1.5 参数装饰器

如果通过上面讲过的装饰器来推论参数装饰器的作用,可能会是修改参数,但事实上并非如此。参数装饰器往往用来对特殊的参数进行标记,然后在方法装饰器中读取对应的标记,执行进一步的操作。例如:

function logParameter(target: any, key: string, index: number) {var metadataKey = `myMetaData`;if (Array.isArray(target[metadataKey])) {target[metadataKey].push(index);}else {target[metadataKey] = [index];}}function logMethod(target, key: string, descriptor: any): any {var originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {var metadataKey = `myMetaData`;var indices = target[metadataKey];console.log('indices', indices);for (var i = 0; i < args.length; i++) {if (indices.indexOf(i) !== -1) {console.log("Found a marked parameter at index" + i);args[i] = "Abrakadabra";}}var result = originalMethod.apply(this, args);return result;}return descriptor;}class JSMeetup {//@logMethod
    public saySomething(something: string, @logParameter somethingElse: string): string {return something + " : " + somethingElse;}}let meetup = new JSMeetup();console.log(meetup.saySomething("something", "Something Else"));

 

20.png

上面的代码中,我们定义了一个参数装饰器,该装饰器将被装饰的参数放到一个指定的数组中。在方法装饰器中,查找被标记的参数,做进一步的处理
不启用装饰器的情况下,输出结果如下:

21.png

启用装饰器的情况下,输出结果如下:

22.png

1.6 小结

现在我们已经学习了所有装饰器的使用,下面总结一下关键用法:

  • 方法装饰器的核心是 方法描述符
  • 属性装饰器的核心是 Object.defineProperty
  • Class装饰器的核心是 构造函数
  • 参数装饰器的主要作用是标记,要结合方法装饰器来使用

下面是参考文章:
https://www.typescriptlang.org/docs/handbook/decorators.html

https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Decorators.md

https://survivejs.com/react/appendices/understanding-decorators/

https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841

https://blog.wolksoftware.com/decorators-metadata-reflection-in-typescript-from-novice-to-expert-part-ii
https://github.com/arolson101/typescript-decorators


更多精彩内容,欢迎关注玄魂工作室微信订阅号。

 

24.png

转载于:https://www.cnblogs.com/xuanhun/p/8735524.html

http://www.lbrq.cn/news/2795707.html

相关文章:

  • 制作网站页面怎么做sem管理工具
  • 购物网站建设报价网站快速收录
  • 建设交通职业技术学院招聘信息网站中国科技新闻网
  • 做商城网站哪里买seo技术员
  • 政治工作网站管理建设网站seo推广公司靠谱吗
  • 台州网站搭建电商网站建设
  • 北京网站建设icp有限公司百度推广个人怎么开户
  • 网站服务器试用游戏广告推广平台
  • 自己做网站去哪买服务器seo建站技巧
  • 西安建网站价格免费学生网页制作成品
  • 做网站怎样找湖南搜索引擎推广平台
  • 个人响应式网站建设搜索引擎优化的办法有哪些
  • wordpress侧边栏目录seo单词优化
  • 网站建设的步骤教程下载2023年8月份新冠
  • 宁晋企业做网站广告关键词查询
  • 网站建设新闻发布注意什么怎么制作网站教程手机
  • 怎么自制网站dz论坛seo设置
  • 什么网站可以做项目网站关键词优化排名公司
  • 做关于什么的网站关键字排名查询
  • 巩义企业网站托管代运营公司网店代运营合同
  • 长安区网站建设小网站广告投放
  • 高新公司网站建设电话什么样的人适合做策划
  • 做h5的软件有哪些网奇seo赚钱培训
  • 网页设计证书考什么广州百度推广排名优化
  • php网站开发文档怎么制作一个简单的网页
  • 网站备案用户注销备案申请表国外网站推广平台有哪些?
  • 关于做ppt的网站有哪些内容吗镇江抖音seo
  • 高端 网站开发宁波seo在线优化方案公司
  • 如何做领券网站长沙seo全网营销
  • 网站推广效果不好原因是网页版百度
  • 打破传统课程模式,IP变现的创新玩法 | 创客匠人
  • linux-ubuntu里docker的容器portainer容器建立后如何打开?
  • ES_文档
  • C++STL-stack和queue的使用及底层实现
  • Prompt魔法:提示词工程与ChatGPT行业应用读书笔记:提示词设计全能指南
  • 【CS创世SD NAND征文】存储芯片在工业电表中的应用与技术演进