函数类型
如何定义一个string类型的变量? const/let 变量名 : 类型 = 值
例如: let v : string = 'alice';
而函数也可以当成这样的定义
javascript
function foo() {
console.log('好久不见, 甚是想念!');
}
可以当成这样的 let foo : Function = new Function( ... )
这个Function(...)内部的内容就是我们定义在函数中的逻辑
所以foo就是一个变量. 它的类型是Function, 当然为了方便理解, 我简化了 它的参数, 它的返回值
不过这个Function很有意思, 我们可以通过foo()
这样的形式, 执行 之前定义在 {} 内部的程序.
随着语言的演进, 我们有了这种定义函数对象的语法 const / let 函数名 = 箭头函数
例如 let bar : Function = () => { console.log('海内存知己, 天涯若比邻') } 当然这样的写法也和上面一样, 我们可以通过 bar() 调用
使用Function我们似乎不能明确这个函数它可以接受什么参数, 他会返回什么类型值, 所以我们又有这样的定义 let bar : (参数) => 返回值类型 = 函数值
例如 let bar : () => void = () => { console.log('海内存知己, 天涯若比邻') }
如果希望执行函数内部的逻辑, 我们可以 bar()
这样的方式
this?
这里我们忽略 this 的严谨定义, 我们只给出如何判断的经验
方法调用时, 谁在方法前面, 那this就是谁.
例如
javascript
class Bar{
func(){ console.log(this === undefined ? 'undefined' : '有值') }
constructor() {
}
}
const bar = new Bar();
const fn : Function = bar.func;
bar.func() // this为bar对象
fn() // this为undefined
在TS中, 我们可以通过 函数变量.bind(this)
这种方式绑定this. 不过这种方式在arkts中不允许使用, 但有时为了翻阅一些转译后的TS代码, 我们还是要懂它的意思
全局Builder的传递问题
定义一个全局的builder函数, 例如
scss
@Builder
export function foo() {
Row()
.width('100%')
.height('100%')
.backgroundColor($r('app.color.corn_flower_blue'));
}
生成的ts文件为
javascript
export function foo(parent = null) {
// 注意这里的 调用
(parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender) => {
Row.create();
...
}, Row);
Row.pop();
}
他需要一个parent, 这个parent在调用的时候会传递
调用
less
@Entry
@Component
struct Index {
build() {
Column() {
Child(
{
more: () => {foo()}
}
);
}
...;
}
}
@Component
struct Child {
@Require
@BuilderParam
more: () => void;
build() {
Column() {
this.more();
}
...;
}
}
生成
typescript
...
class Index extends ViewPU {
constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
// Index是Page, 一般而言它的Parent是 undefined
super(parent, __localStorage, elmtId, extraInfo);
...;
}
...
initialRender() {
this.observeComponentCreation2((elmtId, isInitialRender) => {
Column...
}, Column);
{
this.observeComponentCreation2((elmtId, isInitialRender) => {
if (isInitialRender) {
// 这里的this是 Index 实例对象, 所以Child的parent是Index obj
let componentCall = new Child(this, {
more: () => { foo(); }
}, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/Index.ets", line: 10, col: 7 });
ViewPU.create(componentCall);
let paramsLambda = () => {
return {
more: () => { foo(); }
};
};
componentCall.paramsGenerator_ = paramsLambda;
}
...
}, { name: "Child" });
}
Column.pop();
}
...
}
class Child extends ViewPU {
constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
// parent = index obj
super(parent, __localStorage, elmtId, extraInfo);
if (typeof paramsLambda === "function") {
this.paramsGenerator_ = paramsLambda;
}
this.more = undefined;
// 对属性进行赋值
this.setInitiallyProvidedValue(params);
this.finalizeConstruction();
}
setInitiallyProvidedValue(params: Child_Params) {
if (params.more !== undefined) {
// params.more = () => { foo() }
this.more = params.more;
}
}
...
private __more;
initialRender() {
this.observeComponentCreation2((elmtId, isInitialRender) => {
...
}, Column);
// 调用more时, 绑定当前的this实例. 相当于 () => {foo()}.bind(this)
// 相当于 () => {foo()}.bind(this)(), foo()函数内部的this在严格模式下为undefined.
this.more.bind(this)();
Column.pop();
}
rerender() {
this.updateDirtyElements();
}
}
// 初始化 Index
registerNamedRoute(() => new Index(undefined, {}), ...});
现在换成传递函数变量的方式, 不使用箭头函数.
typescript
...
class Index extends ViewPU {
constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
// Index的parent依旧是undefined
super(parent, __localStorage, elmtId, extraInfo);
...
}
...
initialRender() {
...;
{
this.observeComponentCreation2((elmtId, isInitialRender) => {
if (isInitialRender) {
// 初始化 child
// parent依旧是Index obj
let componentCall = new Child(this, {
more: foo
}, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/Index.ets", line: 10, col: 7 });
...
}, { name: "Child" });
}
Column.pop();
}
...
}
class Child extends ViewPU {
// parent 是 Index obj
constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
super(parent, __localStorage, elmtId, extraInfo);
...
this.setInitiallyProvidedValue(params);
}
setInitiallyProvidedValue(params: Child_Params) {
// params.more = foo
if (params.more !== undefined) {
// this.more = foo
this.more = params.more;
}
}
...
private __more;
initialRender() {
this.observeComponentCreation2((elmtId, isInitialRender) => {
...
}, Column);
// 调用的时候, this.more.bind(this)相当于给foo传递了一个this.
// 相当于 foo.bind(this)(); 此时foo函数内部的this就是Child这个实例对象.
this.more.bind(this)();
Column.pop();
}
rerender() {
this.updateDirtyElements();
}
}
registerNamedRoute(() => new Index(undefined, {}), "", ...);
所以直接通过箭头函数使用全局builder函数, 会出现 undefined.属性的问题
需要注意的是, 实际运行时, 鸿蒙的ets是编译成abc这种中间格式的字节码. 同时方舟编译器很厉害的地方在于他的确给JS做了一套AOT (携带类型信息)到机器码.
可以在这里进行测试