TypeScript 自定义装饰器

news2024/11/18 11:37:18
(预测未来最好的方法就是把它创造出来——尼葛洛庞帝)

在这里插入图片描述

装饰器

装饰器一种更现代的代码模式,通过使用@的形式注入在属性,寄存器,方法,方法参数和类中,比如在Angular,Nestjs和midway等流行框架中也都用到了装饰器。
官方说明
对装饰器更详细的相关说明

tc39提案

tc39提案一共分为五个阶段

Stage 0 - 设想(Strawman):只是一个想法,可能有 Babel插件。
Stage 1 - 建议(Proposal):这是值得跟进的。
Stage 2 - 草案(Draft):初始规范。
Stage 3 - 候选(Candidate):完成规范并在浏览器上初步实现。
Stage 4 - 完成(Finished):将添加到下一个年度版本发布中。

装饰器目前已经在阶段3,相信不久的将来,js中也会支持装饰器。在typescript5.0中已经完全支持了装饰器。
该提案进度更详细的相关说明

装饰器实践

tsconfig.json

{
  "compilerOptions": {
    "target": "ES6", // 为发出的JavaScript设置JavaScript语言版本,并包含兼容的库声明
    "experimentalDecorators": true, // 启用对遗留实验装饰器的实验支持
    "module": "ES6", // 指定生成的模块代码
    "esModuleInterop": true, // 发出额外的JavaScript以简化对导入CommonJS模块的支持。这为类型兼容性启用了“allowSyntheticDefaultImports”
    "moduleResolution": "node", // 指定TypeScript如何从给定的模块说明符中查找文件
    "outDir": "dist", // 为所有发出的文件指定输出文件夹
    "rootDir": "src", // 指定源文件中的根文件夹
  },
  "include": [ // 需要编译的目录文件
    "src/**/*",
  ],
  "exclude": [ // 需要排除的目录文件
    "node_modules"
  ]
}

官方更详细的配置说明

类装饰器

typescript

// 通过装饰器对类进行扩展,减少对代码侵入性和业务间的耦合性
// constructor参数为类的构造函数
const classExtends = () => {
  const ClassDecorator = (constructor: Function) => {
    console.log('ClassDecorator---');
    // 扩展类属性
    constructor.prototype.name = 'ClassDecoratorName';
    // 扩展类方法
    constructor.prototype.run = () => {
      console.log('ClassDecorator run test');
    }
  };
  interface Test {
    name: string;
    run (): void;
  }

  @ClassDecorator
  class Test {
  }
  new Test().run();
  const obj = { name: 'adsa' };
  Reflect.get(obj, 'name');
};
classExtends();

// 通过装饰器入参的形式对类进行扩展,使用参数可以对业务进行更强的定制化处理
const classExtendByParams = () => {
  const ClassDecorator = (param: string) => {
    return function (constructor: Function) {
      // 针对入参做不同的处理
      constructor.prototype.run = () => {
        if (param === 'agent') {
          console.log('classExtendByParams run agent');
        } else if (param === 'user') {
          console.log('classExtendByParams run user');
        }
      };
    }
  };
  interface Test {
    name: string;
    run (): void;
  }
  @ClassDecorator('agent')
  class Test {
  }
  new Test().run();
};
classExtendByParams();

// 通过装饰器工厂方法进行扩展,工厂方法装饰器可以和类型更好的兼容
const classExtendOfFactory = () => {
  const ClassDecorator = (param: string) => {
    return function <T extends new (...args: any[]) => any> (constructor: T) {
      return class extends constructor {
        run () {
          if (param === 'agent') {
            console.log('classExtendOfFactory run agent');
          } else if (param === 'user') {
            console.log('classExtendOfFactory run user');
          }
        };
      }
    }
  };
  const Test = ClassDecorator('user')(
    class { }
  );
  new Test().run();
};
classExtendOfFactory();

javascript

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
// 通过装饰器对类进行扩展,减少对代码侵入性和业务间的耦合性
// constructor参数为类的构造函数
const classExtends = () => {
    const ClassDecorator = (constructor) => {
        console.log('ClassDecorator---');
        // 扩展类属性
        constructor.prototype.name = 'ClassDecoratorName';
        // 扩展类方法
        constructor.prototype.run = () => {
            console.log('ClassDecorator run test');
        };
    };
    let Test = class Test {
    };
    Test = __decorate([
        ClassDecorator
    ], Test);
    new Test().run();
    const obj = { name: 'adsa' };
    Reflect.get(obj, 'name');
};
classExtends();
// 通过装饰器入参的形式对类进行扩展,使用参数可以对业务进行更强的定制化处理
const classExtendByParams = () => {
    const ClassDecorator = (param) => {
        return function (constructor) {
            // 针对入参做不同的处理
            constructor.prototype.run = () => {
                if (param === 'agent') {
                    console.log('classExtendByParams run agent');
                }
                else if (param === 'user') {
                    console.log('classExtendByParams run user');
                }
            };
        };
    };
    let Test = class Test {
    };
    Test = __decorate([
        ClassDecorator('agent')
    ], Test);
    new Test().run();
};
classExtendByParams();
// 通过装饰器工厂方法进行扩展,工厂方法装饰器可以和类型更好的兼容
const classExtendOfFactory = () => {
    const ClassDecorator = (param) => {
        return function (constructor) {
            return class extends constructor {
                run() {
                    if (param === 'agent') {
                        console.log('classExtendOfFactory run agent');
                    }
                    else if (param === 'user') {
                        console.log('classExtendOfFactory run user');
                    }
                }
                ;
            };
        };
    };
    const Test = ClassDecorator('user')(class {
    });
    new Test().run();
};
classExtendOfFactory();

方法装饰器

typescript

/**
 * 入参解释
 * target: 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
 * propertyKey: 属性的名称
 * descriptor: 属性的描述器
 */
/**
 * PropertyDescriptor参数解释
 * PropertyDescriptor的参数各项为js的属性描述符,在创建变量或方法等对象时,js会默认赋予这些描述符
 * 详细的阅读https://www.tektutorialshub.com/javascript/javascript-property-descriptors-enumerable-writable-configurable/
 * descriptor 参数
 * value 方法自身
 * writable 该方法是否可以被变更
 * enumerable 是否可以被枚举
 * configurable 决定是否可配置,如果为false,则value,writable,enumerable不能被修改
 */

// 通过装饰器对方法进行扩展,减少对代码侵入性和业务间的耦合性
const methodExtends = () => {
  const MethodDecorator = (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
    // 获取方法本身
    const method = descriptor.value;
    // 对该方法的生命周期进行操作
    descriptor.value = (...args) => {
      console.log('MethodDecorator before run');
      const data = method.call(this, args);
      console.log('MethodDecorator after run');
      return data;
    };
  };
  class Test {

    @MethodDecorator
    method () {
      return ';;;;';
    }

  }
  console.log(new Test().method());
};
methodExtends();

// 通过装饰入参的形式对方法进行扩展,使用参数可以对业务进行更强的定制化处理
const methodExtendsByParams = () => {
  const MethodDecorator = (param: string) => {
    console.log('methodExtendsByParams', param);
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
      // 获取方法本身
      const method = descriptor.value;
      // 对该方法的生命周期进行操作
      descriptor.value = (...args) => {
        console.log('before run');
        const data = method.call(this, args);
        console.log('after run');
        return data;
      };
    }
  };
  class Test {

    @MethodDecorator('user')
    method () {
      return ';;;;';
    }

  }
  console.log(new Test().method());
};
methodExtendsByParams();

javascript

/**
 * 入参解释
 * target: 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
 * propertyKey: 属性的名称
 * descriptor: 属性的描述器
 */
/**
 * PropertyDescriptor参数解释
 * PropertyDescriptor的参数各项为js的属性描述符,在创建变量或方法等对象时,js会默认赋予这些描述符
 * 详细的阅读https://www.tektutorialshub.com/javascript/javascript-property-descriptors-enumerable-writable-configurable/
 * descriptor 参数
 * value 方法自身
 * writable 该方法是否可以被变更
 * enumerable 是否可以被枚举
 * configurable 决定是否可配置,如果为false,则value,writable,enumerable不能被修改
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
// 通过装饰器对方法进行扩展,减少对代码侵入性和业务间的耦合性
const methodExtends = () => {
    const MethodDecorator = (target, propertyKey, descriptor) => {
        // 获取方法本身
        const method = descriptor.value;
        // 对该方法的生命周期进行操作
        descriptor.value = (...args) => {
            console.log('MethodDecorator before run');
            const data = method.call(this, args);
            console.log('MethodDecorator after run');
            return data;
        };
    };
    class Test {
        method() {
            return ';;;;';
        }
    }
    __decorate([
        MethodDecorator
    ], Test.prototype, "method", null);
    console.log(new Test().method());
};
methodExtends();
// 通过装饰入参的形式对方法进行扩展,使用参数可以对业务进行更强的定制化处理
const methodExtendsByParams = () => {
    const MethodDecorator = (param) => {
        console.log('methodExtendsByParams', param);
        return (target, propertyKey, descriptor) => {
            // 获取方法本身
            const method = descriptor.value;
            // 对该方法的生命周期进行操作
            descriptor.value = (...args) => {
                console.log('before run');
                const data = method.call(this, args);
                console.log('after run');
                return data;
            };
        };
    };
    class Test {
        method() {
            return ';;;;';
        }
    }
    __decorate([
        MethodDecorator('user')
    ], Test.prototype, "method", null);
    console.log(new Test().method());
};
methodExtendsByParams();

方法参数装饰器

typescript

// 通过装饰器对方法中的属性进行扩展
/**
 * target 实例自身
 * methodName 方法名
 * paramIndex 参数的下标位置
 */
const methodParamExtends = () => {
  const methodPramDecorator = (param: string) => {
    return (target: any, methodName: string, paramIndex: any) => {
      console.log('target', target, methodName, paramIndex);
      target.decoratorData = '222';
    }
  };
  class Test {
    decoratorData!: string;
    init (@methodPramDecorator('agent') type: string) {
      return type;
    }
  }
  const test = new Test();
  const data = test.init('20230611');
  console.log(data, test.decoratorData);
  return data;
};
methodParamExtends();

javascript

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
// 通过装饰器对方法中的属性进行扩展
/**
 * target 实例自身
 * methodName 方法名
 * paramIndex 参数的下标位置
 */
const methodParamExtends = () => {
    const methodPramDecorator = (param) => {
        return (target, methodName, paramIndex) => {
            console.log('target', target, methodName, paramIndex);
            target.decoratorData = '222';
        };
    };
    class Test {
        init(type) {
            return type;
        }
    }
    __decorate([
        __param(0, methodPramDecorator('agent'))
    ], Test.prototype, "init", null);
    const test = new Test();
    const data = test.init('20230611');
    console.log(data, test.decoratorData);
    return data;
};
methodParamExtends();

寄存器装饰器

typescript

// 通过装饰器对寄存器进行扩展
/**
 * target 实例自身
 * propertyKey 属性key
 * descriptor 属性描述符
 */
const setgetExtends = () => {
  const SetGetDecorator = (param: string) => {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
      const set = descriptor.set;
      const get = descriptor.get;
      descriptor.set = function (value) {
        console.log('GetDecorator before run', value);
        if (typeof value === 'string') {
          value += ` set decrator ${param}`;
        }
        set.call(this, value);
        console.log('GetDecorator after run', value);
      };
      descriptor.get = function () {
        console.log('GetDecorator before run', target);
        let data = get.call(this);
        console.log('GetDecorator after run');
        if (typeof data === 'string') {
          data += ` get decrator ${param}`;
        }
        return data;
      }
    }
  };

  class Test {

    #name: string;

    @SetGetDecorator('custom setget')
    set name (name: string) {
      this.#name = name;
    }
    get name () {
      return this.#name;
    }

  }
  const user = new Test();
  user.name = 'user';
  console.log('setgetExtends', user.name);
};
setgetExtends();

javascript

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    privateMap.set(receiver, value);
    return value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return privateMap.get(receiver);
};
// 通过装饰器对寄存器进行扩展
/**
 * target 实例自身
 * propertyKey 属性key
 * descriptor 属性描述符
 */
const setgetExtends = () => {
    var _name;
    const SetGetDecorator = (param) => {
        return (target, propertyKey, descriptor) => {
            const set = descriptor.set;
            const get = descriptor.get;
            descriptor.set = function (value) {
                console.log('GetDecorator before run', value);
                if (typeof value === 'string') {
                    value += ` set decrator ${param}`;
                }
                set.call(this, value);
                console.log('GetDecorator after run', value);
            };
            descriptor.get = function () {
                console.log('GetDecorator before run', target);
                let data = get.call(this);
                console.log('GetDecorator after run');
                if (typeof data === 'string') {
                    data += ` get decrator ${param}`;
                }
                return data;
            };
        };
    };
    class Test {
        constructor() {
            _name.set(this, void 0);
        }
        set name(name) {
            __classPrivateFieldSet(this, _name, name);
        }
        get name() {
            return __classPrivateFieldGet(this, _name);
        }
    }
    _name = new WeakMap();
    __decorate([
        SetGetDecorator('custom setget')
    ], Test.prototype, "name", null);
    const user = new Test();
    user.name = 'user';
    console.log('setgetExtends', user.name);
};
setgetExtends();

属性装饰器

typescript

// 通过属性装饰器对属性进行扩展
const paramExtends = () => {
  const ParamDecorator = (param: string) => {
    return function (target: any, key: any) {
      target[key] = param;
      console.log(`init param ${key} to ${param}`);
    }
  }
  class Test {
    @ParamDecorator('www.baidu.com')
    private url!: string;
    getName () {
      return this.url;
    }
  }
  const test = new Test();
  const data = test.getName();
  console.log('data', data);
};
paramExtends();

javascript

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
// 通过属性装饰器对属性进行扩展
const paramExtends = () => {
    const ParamDecorator = (param) => {
        return function (target, key) {
            target[key] = param;
            console.log(`init param ${key} to ${param}`);
        };
    };
    class Test {
        getName() {
            return this.url;
        }
    }
    __decorate([
        ParamDecorator('www.baidu.com')
    ], Test.prototype, "url", void 0);
    const test = new Test();
    const data = test.getName();
    console.log('data', data);
};
paramExtends();

装饰器执行顺序

示例代码

typescript

// 不同装饰器的执行顺序

const CustomClassDecorator = (constructor: Function) => {
  console.log('类装饰器');
};
const CustomMethodDecorator = (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
  console.log('方法装饰器');
};
const CustomMethodParamDecorator = (target: any, methodName: string, paramIndex: any) => {
  console.log('方法参数装饰器');
}
const CustomParamDecorator = (target: any, key: any) => {
  console.log(`参数装饰器`);
}
const CustomSetGetDecorator = (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
  console.log('寄存器装饰器');
}

@CustomClassDecorator
class Test {

  @CustomParamDecorator
  sex!: string;

  #name !: string;

  @CustomSetGetDecorator
  set name (name: string) {
    this.#name = name;
  }
  get name () {
    return this.#name
  }

  @CustomMethodDecorator
  handleName (@CustomMethodParamDecorator prefix: string) {
    return prefix + this.name;
  }

}
const instance = new Test();
const data = instance.handleName('prefix');
console.log(data);

javascript

// 不同装饰器的执行顺序
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    privateMap.set(receiver, value);
    return value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return privateMap.get(receiver);
};
var _name;
const CustomClassDecorator = (constructor) => {
    console.log('类装饰器');
};
const CustomMethodDecorator = (target, propertyKey, descriptor) => {
    console.log('方法装饰器');
};
const CustomMethodParamDecorator = (target, methodName, paramIndex) => {
    console.log('方法参数装饰器');
};
const CustomParamDecorator = (target, key) => {
    console.log(`参数装饰器`);
};
const CustomSetGetDecorator = (target, propertyKey, descriptor) => {
    console.log('寄存器装饰器');
};
let Test = class Test {
    constructor() {
        _name.set(this, void 0);
    }
    set name(name) {
        __classPrivateFieldSet(this, _name, name);
    }
    get name() {
        return __classPrivateFieldGet(this, _name);
    }
    handleName(prefix) {
        return prefix + this.name;
    }
};
_name = new WeakMap();
__decorate([
    CustomParamDecorator
], Test.prototype, "sex", void 0);
__decorate([
    CustomSetGetDecorator
], Test.prototype, "name", null);
__decorate([
    CustomMethodDecorator,
    __param(0, CustomMethodParamDecorator)
], Test.prototype, "handleName", null);
Test = __decorate([
    CustomClassDecorator
], Test);
const instance = new Test();
const data = instance.handleName('prefix');
console.log(data);

执行结果

参数装饰器
寄存器装饰器
方法参数装饰器
方法装饰器
类装饰器
prefixundefined

装饰器原理

以下代码是重写过的,方便理解和回顾。由于Reflect.decorate装饰器反射机制还不支持,且相关资料较少,所以在本文中不进行深入研究。

/**
 * Test = __decorate([ClassDecrator], Test)
 * decorators 装饰器列表
 * target 类实例
 * key 属性名称
 * desc 变量属性描述符
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  /**
   * 获取请求参数,咱本示例中,请求参数为2
   * Test = __decorate([ClassDecrator], Test)
   */
  var c = arguments.length
  // 初始化r变量
  var r = null;
  // 如果请求参数小于三个,在本示例中满足
  if (c < 3) {
    // 将类实例赋予r,也就是将Test赋给r
    r = target;
  } else {
    // 如果属性描述符为空
    if (desc === null) {
      // 返回指定属性名的描述符
      desc = Object.getOwnPropertyDescriptor(target, key);
      r = desc;
    } else {
      // 如果存在描述符,则直接赋予r
      r = desc;
    }
  }
  // 由此可见,在类装饰器下,r为类实例本身,在方法等装饰器下,r为属性描述符

  var d;
  // 是否支持es6的Reflect,暂时跳过,文章后面单独会将
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
    r = Reflect.decorate(decorators, target, key, desc)
  }
  // 如果不支持es6的Reflect,则向下执行
  else {
    // 在这里倒叙循环执行每一个装饰器,由此看出ts装饰器的执行顺序
    for (var i = decorators.length - 1; i >= 0; i--) {
      d = decorators[i];
      if (d) {
        var temp = null;
        if (c < 3) {
          temp = d(r);
        } else {
          if (c > 3) {
            temp = d(target, key, r);
          } else {
            temp = d(target, key);
          }
        }
        if (temp) {
          r = temp;
        }
      }
    }
  }
  // 如果参数大于3个,则将属性名和属性描述符赋予该实例
  if (c > 3 && r) {
    Object.defineProperty(target, key, r);
  }
  // 返回该实例实例或属性描述符
  return r;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/634020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据Doris(三十九):Spark Load 注意事项

文章目录 Spark Load 注意事项 Spark Load 注意事项 1、现在Spark load 还不支持 Doris 表字段是String类型的导入,如果你的表字段有String类型的请改成varchar类型,不然会导入失败,提示 type:ETL_QUALITY_UNSATISFIED; msg:quality not good enough to cancel 2、使用Spa…

无敌!我用【C语言】手搓出了一个体系完整的【员工管理系统】还能玩游戏听音乐?(超详细,附完整源码)

博主简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的人。 博主主页&#xff1a;陈童学哦 所属专栏&#xff1a;C语言程序设计实验项目 如果本文对你有所帮助的话&#xff0c;还希望可以点赞&#x1f44d;收藏&#x1f4c2;支持一下…

Linux——IP协议1

目录 协议头格式 如何封装和解包 如何交付&#xff08;分用&#xff09; 报头每一个字段 分片是怎么做到的 应用层解决的是数据使用的问题。 在传输层&#xff0c;网络层&#xff0c;数据链路层&#xff1a;解决的是网络通信的细节&#xff0c;将数据可靠的从A主机跨网络发…

【深入浅出 Spring Security(八)】前后端分离-使用CSRF漏洞保护详讲

CSRF 漏洞保护 一、CSRF 概述二、CSRF 攻击演示三、CSRF 防御令牌同步模式 四、前后端分离使用 CSRFCsrfFilter 源码分析源码一些方法的细究 测试 五、总结 一、CSRF 概述 CSRF&#xff08;Cross-Site Request Forgery 跨站请求伪造&#xff09;&#xff0c;也可称为一键式攻击…

乐盟互动申请纳斯达克IPO上市,募资2000万美元

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;来自北京的程序化广告平台【乐盟互动】近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&#xff0c;股票代码&#xff08;LIAI&#xff09;&…

SpringBoot社区小区物业管理停车场系统(Java+Layui+MyBatis+Python+Mysql)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;69小区 获取完整源码源文件说明文档数据库文件 项目特色 本项目使用现行主流技术与架构模式&#xff08;控制层、服务层、数据层&#xff09;代码结构清晰&#xff0c;严格遵循模块化、组件化、接口化思想&#xff1b;关…

mysq在RR级别怎么解决不可重复读和幻读

1、定义 不可重复读&#xff1a; 事务1读取一行&#xff0c;事务2然后修改或删除该行数据并且提交事务&#xff0c;事务1再次读取结果不一样&#xff1b; 幻读&#xff1a;事务1按条件读取查询数据&#xff0c;事务2按照同样的条件新增一条或多条数据并且提交事务&#xff0c…

mysql8查看大事务

文章目录 1、查看大事务的原因2、构建测试数据3、模拟大事务场景4、查询mysql的事务5、查询大事务的详情 1、查看大事务的原因 大事务的特点是执行时间长&#xff0c;长期占有锁不释放&#xff0c;导致其他想操作同一行数据的线程阻塞&#xff0c;如果客户端设置了超时时间&am…

单正态总体和双正态总体的假设检验

1.单正态总体和双正态总体的假设检验 笔者之前的相关笔记&#xff1a; 1.正态总体下常见的抽样分布 2.假设检验&#xff08;Hypothesis Testing&#xff09; 个人理解假设检验&#xff1a;先对总体参数提出一个假设值&#xff0c;利用样本信息判断这一假设是采取拒绝该假设还是…

opencv人与摄像头距离检测

参考&#xff1a; https://chtseng.wordpress.com/2018/09/18/%E5%A6%82%E4%BD%95%E4%BC%B0%E7%AE%97%E5%89%8D%E6%96%B9%E4%BA%BA%E7%89%A9%E7%9A%84%E8%B7%9D%E9%9B%A2/ WeChat_20230611160620 1、cv2加载摄像头慢解决方法&#xff0c;单独重新cv2.VideoCapture() https://b…

使用vue进行Lodop打印的一些方法

文章目录 使用Lodop进行打印的一般步骤vue中使用lodopkr-print-designer简介打印模板设计器打印预览模板设计页面安装引入 Lodop是一个JavaScript控件&#xff0c;用于在Web应用程序中进行打印操作。 使用Lodop进行打印的一般步骤 下载Lodop控件&#xff1a;首先&#xff0c;你…

对比学习做了什么?

什么是对比学习&#xff1f; 对比学习貌似处于“无明确定义、有指导原则”的状态 什么是对比学习呢&#xff1f;(这个是微信链接)全文比较长&#xff0c;但是逻辑框架还是不错的。 如果想要更快速的了解什么是对比学习或者说对比学习是怎么做的&#xff0c;可以看SimCLR这个模…

全网最详细,软件测试-性能测试岗面试题总结(大全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 描述一下你们公司…

论文阅读:Denoising Diffusion Probabilistic Models

论文阅读&#xff1a;Denoising Diffusion Probabilistic Models 最近一两年&#xff0c;在图像生成领域&#xff0c;扩散模型受到了越来越多的关注&#xff0c;特别是随着 DALL-E2 以及 Midjourney 的持续火爆&#xff0c;扩散模型也变得越来越流行&#xff0c;之前很多基于 …

C++ 参数的三种传递方式和应用场景

C 参数的三种传递方式分别是值传递、指针传递和引用传递。 值传递 值传递的实质 将实参的值&#xff08;a、b&#xff09;复制到形参(m、n)相应的存储单元中&#xff0c;即形参和实参分别占用不同的存储单元。 值传递的特点 值传递的特点是单向传递&#xff0c;即主调函数…

Java Web开发实战经典学习过程笔记

Java Web开发实战经典学习简单笔记 第一章 Java Web 开发简介 1.胖客户端程序指的是&#xff0c;当一个程序运行时需要一个单独的客户端程序支持(如&#xff1a;QQ)。瘦客户端程序在操作时不需要任何其他程序的安装(如&#xff1a;登录网上论坛&#xff0c;只需浏览器即可)。 2…

I.MX6ull UART

一 简介 UART 全称叫做串行接口&#xff0c;通常也叫做 COM 接口&#xff0c;串行接口指的是数据一个一个的顺序传输&#xff0c;通信线路简单。使用两条线即可实现双向通信&#xff0c;一条用于发送&#xff0c;一条用于接收。串口通信距离远&#xff0c;但是速度相对会低&…

Self-Attention 自注意力机制

输出形式 李宏毅讲到&#xff1a; 模型的输入是只有一种形式——词向量但是输出的形式却是不唯一的&#xff0c;主要有以下三种&#xff1a; 每一个向量对应一个输出(多对多&#xff0c;且一一对应) 每个序列只有一个输出(多对一) 一个序列对应一个序列(多对多&#xff0c;长…

MySQL 索引的10 个核心要点

文章目录 &#x1f349;1. 索引底层采用什么数据结构&#xff1f;为什么不用hash&#x1f349;2. B树与B树区别&#xff1f;为何用B树&#xff1f;&#x1f349;3. 自增主键理解&#xff1f;&#x1f349;4. 为什么自增主键不连续&#x1f349;5. Innodb为什么推荐用自增ID&…

代码随想录第59天

1.下一个更大元素II 有两种方法&#xff1a; 1.把两个一样的数组拼起来&#xff1a; // 版本一 class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {// 拼接一个新的numsvector<int> nums1(nums.begin(), nums.end());nu…