全局Builder函数传递的问题

函数类型

如何定义一个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 (携带类型信息)到机器码.

可以在这里进行测试

gitee.com/openharmony...

相关推荐
怀男孩3 小时前
鸿蒙NEXT开发之开屏广告实现
华为·harmonyos
MardaWang4 小时前
HarmonyOS开发,解决Kill server failed 报错问题
华为·harmonyos
冬冬小圆帽4 小时前
鸿蒙编译器安装运行教程
华为·harmonyos
李坤6 小时前
鸿蒙-封装吸边可拖拽视图
harmonyos·arkts·arkui
别说我什么都不会6 小时前
OpenHarmony源码分析之分布式软总线:authmanager模块(1)/设备认证连接管理
分布式·操作系统·harmonyos
二流小码农7 小时前
鸿蒙开发:远场通信服务rcp会话问题
android·ios·harmonyos
SuperHeroWu78 小时前
【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解
华为·app·harmonyos·鸿蒙·har·hsp·hap
Bruce_Liuxiaowei9 小时前
HarmonyOS Next~HarmonyOS应用开发工具之AppGallery Connect
华为·harmonyos
东林知识库9 小时前
鸿蒙NEXT项目实战-百得知识库05
华为·harmonyos
别说我什么都不会10 小时前
OpenHarmony源码分析之分布式软总线:os_adapter模块解析
分布式·harmonyos