写给初学者的 HarmonyOS 教程 -- 状态管理(@State/@Prop/@Link 装饰器)

@State 装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI 会发生对应的渲染改变(类似 Compose 的 mutablestateof )。

@Prop 装饰的变量可以和父组件建立单向的同步关系。@Prop 装饰的变量是可变的,但是变化不会同步回其父组件。

@Lin k装饰的变量可以与其父组件中对应的数据源建立双向数据绑定。

@State 装饰器使用规则

@State变量装饰器说明
装饰器参数
同步类型不与父组件中任何类型的变量同步
允许装饰的变量类型Object、class、string、number、boolean、enum 类型,以及这些类型的数组。
类型必须被指定。
不支持 any,不支持简单类型和复杂类型的联合类型,不允许使用 undefined 和 null。
被装饰变量的初始值必须本地初始化

@State 装饰器使用场景

装饰简单类型的变量

@Entry
@Component
struct Index {
  @State count: number = 0;

  build() {
    Column() {
      Button() {
        Text(`click times: ${this.count}`).margin(20)
      }
      .onClick(() => {
        this.count += 1;
      })
      .width('100%')
    }
    .margin(20)
    .height('100%')
  }
}

当状态变量 count 改变时,查询到只有 Button 组件关联了它;执行 Button 组件的更新方法,实现按需刷新。

运行效果:
在这里插入图片描述

装饰 class 对象类型的变量

@State 除了可以装饰简单类型的变量以外,好可以装修 class 对象,比如,我们在代码里面定义一个 class 类:

class Model {
  public value: string;

  constructor(value: string) {
    this.value = value;
  }
}

@Entry
@Component
struct Index {
  @State count: number = 0;

  build() {
    Column() {
      MyComponent({ count: 1, increaseBy: 2 }).margin(20)
      MyComponent({ title: new Model('Hello, World 2'), count: 7 }).margin(40)
    }
    .width('100%')
  }
}

@Component
struct MyComponent {
  @State title: Model = new Model('Hello World');
  @State count: number = 0;
  private increaseBy: number = 1;

  build() {
    Column() {
      Text(`${this.title.value}`)
      Button(`Click to change title`).onClick(() => {
        // @State 变量的更新将触发上面的 Text 组件内容更新
        this.title.value = this.title.value === 'Hello ArkUI' ? 'Hello World' : 'Hello ArkUI';
      }).margin(20)

      Button(`Click to increase count=${this.count}`).onClick(() => {
        // @State 变量的更新将触发该 Button 组件的内容更新
        this.count += this.increaseBy;
      })
    }
  }
}

运行效果:

在这里插入图片描述

可以发现:第一个 MyComponent 内部状态的更改是不会影响第二个 MyComponent。

@Prop 装饰器使用规则

@Prop变量装饰器说明
装饰器参数
同步类型单向同步:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,
子组件@Prop变量的修改不会同步到父组件的状态变量上
允许装饰的变量类型string、number、boolean、enum 类型。
不支持 any,不允许使用 undefined 和 null。
必须指定类型。
在父组件中,传递给 @Prop 装饰的值不能为 undefined 或者 null
被装饰变量的初始值允许本地初始化

要理解 @Prop 变量值初始化和更新机制,有必要了解父组件和拥有 @Prop 变量的子组件初始渲染和更新流程。

1. 初始渲染:

⇒ 执行父组件的 build() 函数将创建子组件的新实例,将数据源传递给子组件;

⇒ 初始化子组件 @Prop 装饰的变量。

2. 更新:

⇒ 子组件 @Prop 更新时,更新仅停留在当前子组件,不会同步回父组件;

⇒ 当父组件的数据源更新时,子组件的 @Prop 装饰的变量将被来自父组件的数据源重置,所有 @Prop 装饰的本地的修改将被父组件的更新覆盖。

@Prop 装饰器使用场景

父组件 @State 到子组件 @Prop 简单数据类型同步

@Entry
@Component
struct Index {
  @State parentValue: number = 10;

  build() {
    Column() {
      Text(`父组件传递数据 ${this.parentValue}`).margin(20)
      // 父组件的数据源的修改会同步给子组件
      Button(`加一个 + 1`).onClick(() => {
        this.parentValue += 1;
      })
      // 父组件的修改会同步给子组件
      Button(`减一个 -1`).onClick(() => {
        this.parentValue -= 1;
      }).margin(20)

      CountDownComponent({ subValue: this.parentValue, costOfOneAttempt: 2 })
    }
    .width('100%')
  }
}

@Component
struct CountDownComponent {
  @Prop subValue: number;
  costOfOneAttempt: number = 1;

  build() {
    Column() {
      if (this.subValue > 0) {
        Text(`子组件获取到的数据: ${this.subValue}`).margin({ top: 50 })
      } else {
        Text('Over!').margin({ top: 50 })
      }
      // @Prop 装饰的变量不会同步给父组件
      Button(`子组件内部操作`).onClick(() => {
        this.subValue -= this.costOfOneAttempt;
      }).margin(20)
    }
  }
}

运行效果:

在这里插入图片描述

解读下代码:

  1. CountDownComponent 子组件首次创建时其 @Prop 装饰的 subValue 变量将从父组件 @State 装饰的 parentValue 变量初始化;
  2. 按“+1”或“-1”按钮时,父组件的 @State 装饰的 parentValue 值会变化,这将触发父组件重新渲染,在父组件重新渲染过程中会刷新使用 parentValue 状态变量的 UI 组件并单向同步更新 CountDownComponent 子组件中的 subValue 值;
  3. 更新 subValue 状态变量值也会触发 CountDownComponent 的重新渲染,在重新渲染过程中,评估使用 subValue 状态变量的 if 语句条件(this.subValue > 0),并执行 true 分支中的使用 subValue 状态变量的 UI 组件相关描述来更新 Text 组件的 UI 显示;
  4. 当按下子组件 CountDownComponent 的“子组件内部操作”按钮时,其 @Prop 变量 subValue 将被更改,但是 subValue 值的更改不会影响父组件的 parentValue 值;
  5. 父组件的 parentValue 值会变化时,父组件的修改将覆盖掉子组件 CountDownComponent 中 subValue 本地的修改。

父组件 @State 数组项到子组件 @Prop 简单数据类型同步

@Entry
@Component
struct Index {
  @State arr: number[] = [1,2,3];

  build() {
    Column() {
      Child({value: this.arr[0]})
      Child({value: this.arr[1]})
      Child({value: this.arr[2]})

      Divider().height(5)

      ForEach(this.arr,
        item => {
          Child({value: item})
        },
        item => item.toString()
      )

      Divider().height(5)

      Text('replace entire arr')
        .fontSize(40)
        .onClick(()=>{
          // 两个数组都包含项“3”。
          this.arr = this.arr[0] == 1 ? [3,4,5] : [1,2,3];
        })
    }
    .width('100%')
  }
}

@Component
struct Child {
  @Prop value: number;

  build() {
    Text(`${this.value}`)
      .fontSize(50)
      .onClick(()=>{this.value++})
  }
}

看下效果:

在这里插入图片描述

页面显示正常,接下来有意思的事情就发生了,我们看下实操效果:

在这里插入图片描述

方便你看到前后效果,我们对比下前后的结果图:

在这里插入图片描述

让我们来分析下这个数值变化:

  1. 在子组件 Child 中做的所有的修改都不会同步回父组件 Index 组件,所以即使 6 个组件显示都为 6,但在父组件 Index 中,this.arr 保存的值依旧是 [1,2,3]。
  2. 点击 replace entire arr,this.arr[0] == 1 成立,将 this.arr 赋值为 [3, 4, 5];
  3. 因为 this.arr[0] 已更改,Child({value: this.arr[0]}) 组件将 this.arr[0] 更新同步到实例 @Prop 装饰的变量。Child({value: this.arr[1]}) 和 Child({value: this.arr[2]}) 同理。
  4. this.arr 的更改触发 ForEach 更新,this.arr 更新的前后都有数值为 3 的数组项:[3, 4, 5] 和[1, 2, 3]。根据 diff 算法,数组项“3”将被保留,删除“1”和“2”的数组项,添加为“4”和“5”的数组项(关于 ForEach 的这个特性,不懂的可以查看 写给初学者的 HarmonyOS 教程 – 循环渲染(ForEach))。这就意味着,数组项“3”的组件不会重新生成,而是将其移动到第一位。所以“3”对应的组件不会更新,此时“3”对应的组件数值为“6”,ForEach最终的渲染结果是“6”,“4”,“5”。

从父组件中的 @State 类对象属性到 @Prop 简单类型的同步

class Book {
  public title: string;
  public pages: number;
  public readIt: boolean = false;

  constructor(title: string, pages: number) {
    this.title = title;
    this.pages = pages;
  }
}

@Component
struct ReaderComp {
  @Prop title: string;
  @Prop readIt: boolean;

  build() {
    Row() {
      Text(this.title)
      Text(`... ${this.readIt ? '已阅读' : '还没读'}`)
        .onClick(() => this.readIt = true)
    }
  }
}

@Entry
@Component
struct Index {
  @State book: Book = new Book('《 肖生克的救赎 》', 765);

  build() {
    Column() {
      ReaderComp({ title: this.book.title, readIt: this.book.readIt }).margin(20)
      ReaderComp({ title: this.book.title, readIt: this.book.readIt }).margin(20)
      ReaderComp({ title: this.book.title, readIt: this.book.readIt }).margin(20)
      ReaderComp({ title: this.book.title, readIt: this.book.readIt }).margin(20)
    }
    .width('100%')
  }
}

代码很简单,不用过多解释,直接看效果:

在这里插入图片描述

@Prop 本地初始化不和父组件同步

为了支持 @Component 装饰的组件复用场景,@Prop 支持本地初始化,这样可以让 @Prop 是否与父组件建立同步关系变得可选。当且仅当 @Prop 有本地初始化时,从父组件向子组件传递 @Prop 的数据源才是可选的。

下面的示例中,子组件包含两个 @Prop 变量:

  1. @Prop customCounter 没有本地初始化,所以需要父组件提供数据源去初始化 @Prop,并当父组件的数据源变化时,@Prop 也将被更新;
  2. @Prop customCounter2 有本地初始化,在这种情况下,@Prop 依旧允许但非强制父组件同步数据源给 @Prop。
@Component
struct MyComponent {
  @Prop customCounter: number;
  @Prop customCounter2: number = 5;

  build() {
    Column() {
      Row() {
        Text(`From Main: ${this.customCounter}`).width(90).height(40).fontColor('#FF0010')
      }

      Row() {
        Button('子组件本地修改 !').width(180).height(60).margin({ top: 10 })
          .onClick(() => {
            this.customCounter2++
          })
      }.height(100).width(180)

      Row() {
        Text(`Custom Local: ${this.customCounter2}`).width(90).height(40).fontColor('#FF0010')
      }
    }
  }
}

@Entry
@Component
struct Index {
  @State mainCounter: number = 10;

  build() {
    Column() {
      Row() {
        Column() {
          Button('修改数值').width(480).height(60).margin({ top: 10, bottom: 10 })
            .onClick(() => {
              this.mainCounter++
            })
        }
      }

      Row() {
        // customCounter 必须从父组件初始化,因为 MyComponent 的 customCounter 成员变量缺少本地初始化;此处,customCounter2 可以不做初始化。
        MyComponent({ customCounter: this.mainCounter })
        // customCounter2 也可以从父组件初始化,父组件初始化的值会覆盖子组件 customCounter2 的本地初始化的值
        MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
      }
    }
  }
}

效果:

在这里插入图片描述

@Link 装饰器使用规则

@Link变量装饰器说明
装饰器参数
同步类型双向同步。
父组件中 @State/@StorageLink/@Link 和子组件 @Link 可以建立双向数据同步,反之亦然。
允许装饰的变量类型Object、class、string、number、boolean、enum 类型,以及这些类型的数组。
类型必须被指定,且和双向绑定状态变量的类型相同。
不支持 any,不支持简单类型和复杂类型的联合类型,不允许使用 undefined 和 null。
被装饰变量的初始值无,禁止本地初始化。

为了了解 @Link 变量初始化和更新机制,有必要先了解父组件和拥有 @Link 变量的子组件的关系,初始渲染和双向更新的流程(以父组件为 @State 为例)。

1. 初始渲染:

执行父组件的 build() 函数后将创建子组件的新实例。初始化过程如下:

⇒ 必须指定父组件中的 @State 变量,用于初始化子组件的 @Link 变量。子组件的 @Link 变量值与其父组件的数据源变量保持同步(双向数据同步)。

⇒ 父组件的 @State 状态变量包装类通过构造函数传给子组件,子组件的 @Link 包装类拿到父组件的 @State 的状态变量后,将当前 @Link 包装类 this 指针注册给父组件的 @State 变量。

2. @Link 的数据源更新:

即父组件中状态变量更新,引起相关子组件的 @Link 的更新,处理步骤:

⇒ 通过初始渲染的步骤可知,子组件 @Link 包装类把当前 this 指针注册给父组件。父组件 @State 变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如 @Link 包装类)。

⇒ 通知 @Link 包装类更新后,子组件中所有依赖 @Link 状态变量的系统组件(elementId)都会被通知更新。以此实现父组件对子组件的状态数据同步。

3. @Link的更新:

当子组件中 @Link 更新后,处理步骤如下(以父组件为 @State 为例):

⇒ @Link 更新后,调用父组件的 @State 包装类的 set 方法,将更新后的数值同步回父组件。

⇒ 子组件 @Link 和父组件 @State 分别遍历依赖的系统组件,进行对应的 UI 的更新。以此实现子组件 @Link 同步回父组件 @State。

@Link 装饰器使用场景

简单类型和类对象类型的 @Link

以下示例中,点击父组件 ShufflingContainer 中的 “父组件: 设置红色 Button” 和 “父组件: 设置蓝色 Button”,可以从父组件将变化同步给子组件,子组件 GreenButton 和 RedButton 中 @Link 装饰变量的变化也会同步给其父组件。

class BlueButtonState {
  width: number = 0;
  constructor(width: number) {
    this.width = width;
  }
}

@Component
struct BlueButton {
  @Link blueButtonState: BlueButtonState;
  build() {
    Button('Blue Button')
      .width(this.blueButtonState.width)
      .height(120.0)
      .backgroundColor('#085DFF')
      .onClick(() => {
        if (this.blueButtonState.width < 400) {
          // 更新 class 的属性,变化可以被观察到同步回父组件
          this.blueButtonState.width += 50;
        } else {
          // 更新 class 的属性,变化可以被观察到同步回父组件
          this.blueButtonState = new BlueButtonState(200);
        }
      })
  }
}
@Component
struct RedButton {
  @Link redButtonState: number;
  build() {
    Button('Red Button')
      .width(this.redButtonState)
      .height(150.0)
      .backgroundColor('#ff0000')
      .onClick(() => {
        // 子组件的简单类型可以同步回父组件
        this.redButtonState += 20.0;
      })
  }
}
@Entry
@Component
struct ShufflingContainer {
  @State blueButtonState: BlueButtonState = new BlueButtonState(200);
  @State redButtonProp: number = 100;
  build() {
    Column() {
      // class 类型从父组件 @State 向子组件 @Link 数据同步
      Button('父组件: 设置绿色 Button')
        .onClick(() => {
          this.blueButtonState.width = (this.blueButtonState.width < 400) ? this.blueButtonState.width + 100 : 100;
        }).margin(20)
      // class 类型初始化 @Link
      BlueButton({ blueButtonState: $blueButtonState })
      Divider().height(20)
      // 简单类型从父组件 @State 向子组件 @Link 数据同步
      Button('父组件: 设置红色 Button')
        .onClick(() => {
          this.redButtonProp = (this.redButtonProp < 400) ? this.redButtonProp + 100 : 100;
        }).margin(20)
      // 简单类型初始化 @Link
      RedButton({ redButtonState: $redButtonProp })
    }.width('100%').justifyContent(FlexAlign.Center)
  }
}

运行效果:

在这里插入图片描述

数组类型的@Link

@Component
struct Child {
  @Link items: number[];

  build() {
    Column() {
      Button(`Button1: push`).onClick(() => {
        this.items.push(this.items.length + 1);
      }).margin(20)
      Button(`Button2: replace whole item`).onClick(() => {
        this.items = [100, 200, 300];
      })
    }
  }
}

@Entry
@Component
struct Parent {
  @State arr: number[] = [1, 2, 3];

  build() {
    Column() {
      Child({ items: $arr })
      Divider().height(20)
      ForEach(this.arr,
        item => {
          Text(`${item}`)
        },
        item => item.toString()
      )
    }.width('100%')
  }
}

运行效果:

在这里插入图片描述

ArkUI 框架可以观察到数组元素的添加,删除和替换。在该示例中 @State 和 @Link 的类型是相同的 number[],不允许将@Link 定义成 number 类型(@Link item : number),并在父组件中用 @State 数组中每个数据项创建子组件。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

20种常用的软件测试方法,建议先收藏再观看

软件测试在完整的项目当中算是最后一个环节&#xff0c;也是非常重要的一个环节。通过软件测试&#xff0c;我们才能得知一个程序是否符合标准。 小编整理出20种常见的软件测试方法&#xff0c;建议伙伴们先收藏再看。不敢说史上最全&#xff0c;但我办公室里十年软件测试经验…

EasyRecovery2024免费永久版手机数据恢复软件

EasyRecovery2024是一款操作安全、用户可自主操作的数据恢复方案&#xff0c;它支持从各种各样的存储介质恢复删除或者丢失的文件&#xff0c;其支持的媒体介质包括&#xff1a;硬盘驱动器、光驱、闪存、硬盘、光盘、U盘/移动硬盘、数码相机、手机以及其它多媒体移动设备。能恢…

某60区块链安全之JOP实战一学习记录

区块链安全 文章目录 区块链安全Jump Oriented Programming实战一实验目的实验环境实验工具实验原理实验内容Jump Oriented Programming实战一 实验步骤分析合约源代码漏洞Jump Oriented Programming实战一 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约中中Ju…

【Windows】永久屏蔽系统更新

永久关闭电脑更新服务 操作思路&#xff1a; 第一步 winR 输入 services.msc 回车 进入服务管理窗口第二步 进入窗口后 找到 w 开头的文件夹 并找到Windows Update 双击打开 Windows Update 将启动类型&#xff08;E&#xff09; 改为禁用 上方的 “常规” “登录” “恢…

异常处理 springboot

全局异常处理 RestcontrollerAdvice Exceptonhandler package com.it.Exception;import com.it.pojo.Result; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;/*全局异常处理器…

[HTML]Web前端开发技术7(HTML5、CSS3、JavaScript )CSS的定位机制——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

webGL开发虚拟实验室技术方案

开发虚拟实验室涉及到模拟实际实验环境和过程&#xff0c;同时提供用户互动性和学习体验。以下是一个可能的技术方案&#xff0c;用于实现这样的虚拟实验室&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合…

事务管理 springboot

事务是一组操作的集合 它是一个不可分割的工作单位 这些操作 要么同时成功要么同时失败 Spring事务管理 #Spring事务管理日志 logging: level: org.springframework.jdbc.support.JdbcTransactionManager: debug

内网穿透的应用-公网环境下移动端通过群晖管家+cpolar远程管理家中本地局域网内黑群晖设备

白嫖怪狂喜&#xff01;黑群晖也能使用群晖管家啦&#xff01; 文章目录 白嫖怪狂喜&#xff01;黑群晖也能使用群晖管家啦&#xff01;1.使用环境要求&#xff1a;2.下载安装群晖管家app3.随机地址登陆群晖管家app4.固定地址登陆群晖管家app 自己组装nas的白嫖怪们虽然也可以通…

基于SSM框架的《超市订单管理系统》Web项目开发(第五天)供应商管理,增删改查

基于SSM框架的《超市订单管理系统》Web项目开发&#xff08;第五天&#xff09;供应商管理&#xff0c;增删改查 上一次我们实现了多表关联查询&#xff0c;还有分页显示数据的功能。还完善了用户管理这一模块。 因此今天我们需要完成的是供应商管理模块&#xff0c;这一模块…

简单了解传输层协议之TCP和UDP

目录 一、什么是端口号? 二、TCP协议 2.1 TCP报文格式 2.2 三次握手 2.3 四次挥手 2.4 窗口流量控制 三、UDP协议 3.1 UDP报文格式 3.4 传输过程 一、什么是端口号? 我们自己的一台电脑上有时可能会同时运行多个进程软件来进行上网。那么当网络上的服务器响应我们电…

3 开发环境搭建

一、Ubuntu和Windows文件互传 ① 开启Ubuntu的FTP服务&#xff1a; 下载vsftpd&#xff1a;sudo apt-get install vsftpd; 打开vsftpd.conf&#xff1a;sudo nvim /etc/vsftpd.conf; 确保这两行代码没有被注释&#xff1a; 之后重启FTP服务&#xff1a; ② Windows下载FTP客…

LinuxBasicsForHackers笔记 -- 控制文件和目录权限

对于每个文件和目录&#xff0c;我们可以指定文件所有者、特定用户组以及所有其他用户的权限状态。 不同类型的用户 在Linux中&#xff0c;root用户是拥有一切权力的。 root 用户基本上可以在系统上执行任何操作。 系统上的其他用户具有有限的能力和权限&#xff0c;并且几乎…

为什么 SQL 不适合图数据库

背景 “为什么你们的图形产品不支持 SQL 或类似 SQL 的查询语言&#xff1f;” 过去&#xff0c;我们的一些客户经常问这个问题&#xff0c;但随着时间的推移&#xff0c;这个问题变得越来越少。 尽管一度被忽视&#xff0c;但图数据库拥有无缝设计并适应其底层数据结构的查询…

nodejs微信小程序+python+PHP就业求职招聘信息平台的设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之文件管理(1)》(22)

《Linux操作系统原理分析之文件管理&#xff08;1&#xff09;》&#xff08;22&#xff09; 7 文件管理7.1 文件与文件系统7.1.1 文件7.1.3 文件系统及其功能 7.2 文件的组织结构7.2.1 文件的逻辑结构7.2.2 文件的物理结构一、顺序结构&#xff08;顺序文件或连续文件&#xf…

微信小程序uni.chooseImage()无效解决方案

Bug场景&#xff1a; 微信小程序在上传图片时可以通过 uni.chooseImage()方案进行上传&#xff0c;这里不再赘述具体参数。一直项目都可以正常使用&#xff0c;突然有一天发现无法使用该方法&#xff0c;于是查了一下&#xff0c;发现是用户隐私协议问题。故记录一下解决方案。…

Linux中的网络配置

本章主要介绍网络配置的方法 网络基础知识查看网络信息图形化界面修改通过配置文件修改 1.1 网络基础知识 一台主机需要配置必要的网络信息&#xff0c;才可以连接到互联网。需要的配置网络信息包括IP、 子网掩码、网关和 DNS 1.1.1 IP地址 在计算机中对IP的标记使用的是3…

逻辑回归 使用Numpy实现逻辑回归

使用Numpy实现逻辑回归 sigmoid 函数 g ( z ) 1 ( 1 e − z ) g(z)\frac{1}{(1e^{−z} )} g(z)(1e−z)1​ # sigmoid 函数 def sigmod(z):return 1/(1np.exp(-z))线性计算与梯度下降 J ( θ ) − 1 m [ ∑ i 1 m y ( i ) l o g ⁡ ( h θ ( x ( i ) ) ) ( 1 − y ( i ) …