实现可观察量默认资源库行为的本机脚本类



我正在查看nativescript hello world typescript repo,我遇到了一些乏味的工作,使用nativescript的可观察量实现。

如果您查看视图模型是如何定义的,您会发现它是一个简单地扩展Observable库的类。每当为属性定义setter方法时, 您需要手动调用super.notifyPropertyChange("propertyName", propertyValue);

恕我直言,如果您有具有许多属性的视图模型,则此过程效率非常低且容易出错

有没有办法自动执行此任务?(也许有一个基类告诉任何二传手notifyPropertyChange? 如果没有,您如何处理这个问题?Observable机制还有其他实现吗?

以下是我在几个生产应用程序中使用的内容:

import { Observable } from "data/observable";
export class ObservableModel extends Observable {
constructor() {
super();
}
public get(propertyName: string) {
return this["_" + propertyName];
}
public set(propertyName: string, value) {
if (this["_" + propertyName] === value) {
return;
}
this["_" + propertyName] = value;
this.refresh(propertyName);
}
public refresh(propertyName: string) {
super.notify({
eventName: Observable.propertyChangeEvent,
propertyName,
object: this,
value: this["_" + propertyName],
});
}
}

然后,您的模型如下所示:

export class LoginViewModel extends ObservableModel {
get userName(): string { return this.get("userName"); }
set userName(val: string) { this.set("userName", val); }
get password(): string { return this.get("password"); }
set password(val: string) { this.set("password", val); }
}

当您需要使用您只使用的值时:

const vm = new LoginViewModel();
vm.userName = "jdoe";
vm.password = "$3cr3T";

更新装饰器实现:

export function ObservableProperty() {
return (target: Observable, propertyKey: string) => {
Object.defineProperty(target, propertyKey, {
get: function () {
return this["_" + propertyKey];
},
set: function (value) {
if (this["_" + propertyKey] === value) {
return;
}
this["_" + propertyKey] = value;
this.notify({
eventName: Observable.propertyChangeEvent,
propertyName: propertyKey,
object: this,
value,
});
},
enumerable: true,
configurable: true
});
};
}

型:

export class LoginViewModel extends Observable {
@ObservableProperty() public userName: string;
@ObservableProperty() public password: string;
}

它确实很冗长且容易出错。这是违反 DRY 的行为,应避免。有很多方法可以使用JavaScript干净地完成此操作。

一种方法可能是使用修饰器以通用方式自动连接所有样板文件,并保持模型类的清洁和声明性。

例如,我们可以创建以下函数

观察到的.ts

export default function<T extends Notifier<T, K>, K extends keyof T>(target: T, key: K) {
let storedValue = target[key];
const get = () => storedValue;
const set = (value: T[K]) => {
if (storedValue !== value) {
storedValue = value;
target.notifyPropertyChange(key, storedValue);
}
};
Object.defineProperty(target, key, {
get,
set,
enumerable: true,
configurable: false
});
}
export interface Notifier<T, K extends keyof T> {
notifyPropertyChange(key: K, value: T[K]): void;
}

现在我们可以使用它从模型本身中删除所有样板。我们甚至删除了吸气剂和二传手,并使用了简单的属性

模型.ts

// Stub observable class to verify inheritance works correctly (as requested)
class Observable {
notifyPropertyChange(key: string, value: {}) {
console.log(`from super: ${key} ===> ${value}`);
}
}
export class Model extends Observable {
import observed from './observed';
export class Model extends Observable {
@observed name = 'Bob';
@observed age = 38;
@observed birthdate = moment();
notifyPropertyChange<K extends keyof this>(key: K, value: this[K]): void {
super.notifyPropertyChange(key, value);
console.log(`${key} ===> ${value}}`);
}
}
const model = new Model();
model.name = 'Rob';
model.name = 'Robert';

这种方法的一些好处是

  • 它相当干燥

  • 我们有一个比手动定义 getter 和 setter 更简洁易读的模型类

  • 我们的装饰器通过要求类提供notifyPropertyChange方法并在正确的属性键上调用它来改进类型检查。如果我们违反这一点,TypeScript 将发出编译器错误

  • 用于存储值的实际变量是真正的私有变量。它仅在装饰器的闭包范围内,除非通过吸气器和设置器才能访问。这不是命名约定,它是真正的隐私,老式的JavaScript方式。

  • 我们避免引入仅用于代码共享的基类。也就是说,我们可以更喜欢组合而不是继承
  • 我们获得了内联初始值设定项和由此产生的类型推断的便利

这可以概括为装饰整个班级,使其更加干燥。

最新更新