零基础学习JS--基础篇--使用类

JavaScript 是一个基于原型的语言——一个对象的行为取决于它自身的属性及其原型的属性。

在 JavaScript 中,类可以看作是已有的原型继承机制的一种抽象——所有语法都可以转换为原型继承。类本身也是不过是 JavaScript 里一种普通的值,它们有其自己的原型链。事实上,大多数 JavaScript 纯函数都可用作构造函数——你可以用 new 运算符来调用一个构造函数以创建出一个新的对象。

类的概述

如果你已经有动手实践过 JavaScript 的经历,或是阅读指南一路过来,你可能已经用过类了,即便你还没有自己创建过。例如,你可能会对这个很熟悉:

const bigDay = new Date(2019, 6, 19);
console.log(bigDay.toLocaleDateString());
if (bigDay.getTime() < Date.now()) {console.log("Once upon a time...");
}

在第一行,我们创建了一个 Date 类的实例,并将其命名为 bigDay。在第二行,我们在 bigDay 实例上调用了 toLocaleDateString() 方法,并返回了一个字符串。接下来,我们对比了两个数字:一个来自于方法 getTime() 的返回值,另个一来自于对 Date 类本身的直接调用,本例为 Date.now()。 Date 是一个 JavaScript 的内建类。

从这个例子中,我们可以得到一些关于类的基本概念:

  • 类通过 new 运算符创建对象。
  • 每个对象都有一些属性(数据或方法),这些属性是由类添加的。
  • 类本身也有一些属性(数据或方法),这些属性通常用于与实例进行交互。

这些对应于类的三个关键特征:

  • 构造函数;
  • 实例方法和实例字段;
  • 静态方法和静态字段。

声明一个类

类通常通过类声明来创建。

class MyClass {// 类体...
}

在类体内,有若干特性可用。

class MyClass {// 构造函数constructor() {// 构造函数体}// 实例字段myField = "foo";// 实例方法myMethod() {// myMethod 体}// 静态字段static myStaticField = "bar";// 静态方法static myStaticMethod() {// myStaticMethod 体}// 静态块static {// 静态初始化代码}// 字段、方法、静态字段、静态方法、静态块都可以使用私有形式#myPrivateField = "bar";
}

如果你用过早于 ES6 的版本,你可能更熟悉使用函数作为构造函数。上面的模式大致可以转换为以下函数构造器:

function MyClass() {this.myField = "foo";// 构造函数体
}
MyClass.myStaticField = "bar";
MyClass.myStaticMethod = function () {// myStaticMethod 体
};
MyClass.prototype.myMethod = function () {// myMethod 体
};(function () {// 静态初始化代码
})();
构造一个类:

在声明一个类之后,你可以使用 new 运算符来创建它的实例。

const myInstance = new MyClass();
console.log(myInstance.myField); // 'foo'
myInstance.myMethod();

典型函数构造器可以使用 new 来构造,也可以不使用 new 来调用。然而,对于类的调用则必须使用 new,否则会导致错误。

const myInstance = MyClass(); // TypeError: Class constructor MyClass cannot be invoked without 'new'

构造函数

类最重要的工作之一就是作为对象的“工厂”。在类中,实例的创建是通过构造函数来完成的。

例如,我们创建一个名为 Color 的类,它代表了一个特定的颜色。用户通过传入一个 RGB (en-US) 三元组来创建颜色。

class Color {constructor(r, g, b) {// 将 RGB 值作为 `this` 的属性this.values = [r, g, b];}
}

打开你的浏览器的开发者工具,将上面的代码粘贴到控制台中,然后创建一个实例:

const red = new Color(255, 0, 0);
console.log(red);

你应该会看到如下输出:

Object { values: (3) […] }values: Array(3) [ 255, 0, 0 ]

你已经成功创建了一个 Color 实例,该实例有一个 values 属性,它是一个包含了你传入的 RGB 值的数组。这与下面的代码几乎是等价的:

function createColor(r, g, b) {return {values: [r, g, b],};
}

每一次调用 new 都将创建一个新的实例。

const red = new Color(255, 0, 0);
const anotherRed = new Color(255, 0, 0);
console.log(red === anotherRed); // false

在类的构造函数里,this 的值指向新创建的实例。你可以赋予它新的属性,或者读取已有的属性(尤其是方法——我们将在下一节中介绍)。

this 的值将自动作为 new 的结果返回。不建议从构造函数中返回任何值——因为如果你返回一个非原始类型的值,它将成为 new 表达式的值,而 this 的值将被丢弃。你可以在 new 运算符的描述中关于 new 的内容。

class MyClass {constructor() {this.myField = "foo";return {};}
}console.log(new MyClass().myField); // undefined

实例方法

如果一个类只有构造函数,那么它与一个只创建普通对象的 createX 工厂函数并没有太大的区别。然而,类的强大之处在于它们可以作为“模板”,自动将方法分配给实例。

例如,对于 Date 实例,你可以用一系列方法来获取日期的不同部分,例如年份、月份、星期几等等。你也可以通过 setX 方法来设置这些值,例如 setFullYear。

对于我们的 Color 类,我们可以添加一个方法来获取红色值:

class Color {constructor(r, g, b) {this.values = [r, g, b];}getRed() {return this.values[0];}
}const red = new Color(255, 0, 0);
console.log(red.getRed()); // 255

如果你使用方法,它将在所有实例之间共享。一个函数可以在所有实例之间共享,且在不同实例调用时其行为也不同,因为 this 的值不同。你也许好奇这个方法存储在哪里——它被定义在所有实例的原型上,即 Color.prototype,详情参阅继承与原型链。

相似的,我们也可以添加一个 setRed 方法来设置红色值:

class Color {constructor(r, g, b) {this.values = [r, g, b];}getRed() {return this.values[0];}setRed(value) {this.values[0] = value;}
}const red = new Color(255, 0, 0);
red.setRed(0);
console.log(red.getRed()); // 0; 此时也即黑色

私有字段

你或许会好奇:为什么我们要费心使用 getRed 和 setRed 方法,而不是直接访问实例上的 values 数组呢?

class Color {constructor(r, g, b) {this.values = [r, g, b];}
}const red = new Color(255, 0, 0);
red.values[0] = 0;
console.log(red.values[0]); // 0

在面向对象编程中,有一个叫做“封装”的哲学。这是说你不应该访问对象的底层实现,而是使用抽象方法来与之交互。例如,如果我们突然决定将颜色表示为 HSL 而不是 RGB:

class Color {constructor(r, g, b) {// values 现在是一个 HSL 数组!this.values = rgbToHSL([r, g, b]);}getRed() {return this.values[0];}setRed(value) {this.values[0] = value;}
}const red = new Color(255, 0, 0);
console.log(red.values[0]); // 0; 不再是 255,因为 HSL 模型下纯红色的 H 分量为 0

用户对 values 数组代表 RGB 值的假设不再成立,这可能会打破他们的代码逻辑。因此,如果你是一个类的实现者,你应该隐藏实例的内部数据结构,以保持 API 的简洁性,并防止在你做了一些“无害的重构”时,用户代码不至于崩溃。在类中,这是通过私有字段来实现的。

私有字段是以 #(井号)开头的标识符。井号是这个字段名的必要部分,这也就意味着私有字段永远不会与公共属性发生命名冲突。为了在类中的任何地方引用一个私有字段,你必须在类体中声明它(你不能在类体外部创建私有字段)。除此之外,私有字段与普通属性几乎是等价的。

class Color {// 声明:每个 Color 实例都有一个名为 #values 的私有字段。#values;constructor(r, g, b) {this.#values = [r, g, b];}getRed() {return this.#values[0];}setRed(value) {this.#values[0] = value;}
}const red = new Color(255, 0, 0);
console.log(red.getRed()); // 255

在我们将 values 字段私有化之后,我们可以在 getRed 和 setRed 方法中添加一些逻辑,而不仅仅是简单信息传递。例如,我们可以在 setRed 中添加一个检查逻辑,以确保它是一个有效的 R 值:

class Color {#values;constructor(r, g, b) {this.#values = [r, g, b];}getRed() {return this.#values[0];}setRed(value) {if (value < 0 || value > 255) {throw new RangeError("无效的 R 值");}this.#values[0] = value;}
}const red = new Color(255, 0, 0);
red.setRed(1000); // RangeError:无效的 R 值

如果我们暴露 values 属性,我们的用户就会很容易地绕过这个检查,直接给 values[0] 赋值,从而创建一个无效的颜色。但是通过良好封装的 API,我们可以使我们的代码更加健壮,防止下游的逻辑错误。

类方法可以读取其他实例的私有字段,只要它们属于同一个类即可。

class Color {#values;constructor(r, g, b) {this.#values = [r, g, b];}redDifference(anotherColor) {// #values 不一定要从 this 访问:// 你也可以访问属于同一个类的其他实例的私有字段。return this.#values[0] - anotherColor.#values[0];}
}const red = new Color(255, 0, 0);
const crimson = new Color(220, 20, 60);
red.redDifference(crimson); // 35

然而,若 anotherColor 并非一个 Color 实例,#values 将不存在(即使另一个类有一个同名的私有字段,它也不是同一个东西,也不能在这里访问)。访问一个不存在的私有字段会抛出错误,而不是像普通属性一样返回 undefined。如果你不知道一个对象上是否存在一个私有字段,且你希望在不使用 try/catch 来处理错误的情况下访问它,你可以使用 in 运算符。

class Color {#values;constructor(r, g, b) {this.#values = [r, g, b];}redDifference(anotherColor) {if (!(#values in anotherColor)) {throw new TypeError("Color instance expected");}return this.#values[0] - anotherColor.#values[0];}
}

备注: 请记住,# 是一种特殊的标识符语法,你不能像字符串一样使用该字段名。"#values" in anotherColor 会查找一个名为 "#values" 的属性,而不是一个私有字段。

方法、getter 与 setter 也可以是私有的。当你需要类内部做一些复杂的事情,但是不希望代码的其他部分调用时,它们就很有用。

getter字段

color.getRed() 和 color.setRed() 允许我们读取和写入颜色的红色值。如果你熟悉像 Java 这样的语言,你会对这种模式非常熟悉。然而,在 JavaScript 中,使用方法来简单地访问属性仍然有些不便。getter 字段允许我们像访问“实际属性”一样操作某些东西。

class Color {constructor(r, g, b) {this.values = [r, g, b];}get red() {return this.values[0];}set red(value) {this.values[0] = value;}
}const red = new Color(255, 0, 0);
red.red = 0;
console.log(red.red); // 0

这就像是对象有了一个 red 属性——但实际上,实例上并没有这样的属性!实例只有两个方法,分别以 get 和 set 为前缀,而这使得我们可以像操作属性一样操作它们。

解释一下:

在JavaScript类中,我们可以定义getter和setter方法来控制对象属性的读取和设置。在这个例子中,red 是 Color 类的一个实例对象,它具有一个名为 red 的属性。

当我们使用赋值操作符(=)来给对象的属性赋值时,实际上会调用属性的 setter 方法。在这里,red.red = 0 这行代码执行了 red 对象的 red 属性的 setter 方法,将红色分量值设置为 0

因此,在这个例子中,赋值操作 red.red = 0 调用的是 red 对象的 red 属性的 setter 方法,而不是直接修改属性值或数组。

如果一个字段仅有一个 getter 而没有 setter,它将是只读的。

class Color {constructor(r, g, b) {this.values = [r, g, b];}get red() {return this.values[0];}
}const red = new Color(255, 0, 0);
red.red = 0;
console.log(red.red); // 255

公共字段

我们已经见过了私有字段,对应地,还有公共字段。公共字段使得实例可以获得属性,且它们常常独立于构造函数的参数。

class MyClass {luckyNumber = Math.random();
}
console.log(new MyClass().luckyNumber); // 0.5
console.log(new MyClass().luckyNumber); // 0.3

公共字段几乎等价于将一个属性赋值给 this。例如,上面的例子也可以转换为:

class MyClass {constructor() {this.luckyNumber = Math.random();}
}

静态属性

在上面的 Date 例子中,我们还遇到了 Date.now() 方法,它返回当前日期。这个方法不属于任何日期实例——它属于类本身

静态属性是一组在类本身上定义的特性,而不是在类的实例上定义的特性。这些特性包括:

  • 静态方法
  • 静态字段
  • 静态 getter 与 setter

可见,我们之前见过的所有类的特性都有其静态版本。例如,对于我们的 Color 类,我们可以创建一个静态方法,它检查给定的三元组是否是有效的 RGB 值:

class Color {static isValid(r, g, b) {return r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;}
}Color.isValid(255, 0, 0); // true
Color.isValid(1000, 0, 0); // false

静态属性与实例属性的区别在于:

  • 它们有 static 前缀,且
  • 它们不能从实例中访问。
console.log(new Color(0, 0, 0).isValid); // undefined

有一个特殊结构叫做静态初始化块 (en-US),它是一个在类第一次加载时运行的代码块。

class MyClass {static {MyClass.myStaticProperty = "foo";}
}console.log(MyClass.myStaticProperty); // 'foo'

扩展与继承

类的一个关键特性(除了私有字段)是继承,这意味着一个对象可以“借用”另一个对象的大部分行为,同时覆盖或增强某些部分的逻辑。

例如,假定我们需要为 Color 类引入透明度支持。我们可能会尝试添加一个新的字段来表示它的透明度:

class Color {#values;constructor(r, g, b, a = 1) {this.#values = [r, g, b, a];}get alpha() {return this.#values[3];}set alpha(value) {if (value < 0 || value > 1) {throw new RangeError("Alpha 值必须在 0 与 1 之间");}this.#values[3] = value;}
}

然而,这意味着每个实例——即使是大多数不透明的实例(那些 alpha 值为 1 的实例)——都必须有额外的 alpha 值,这并不是很优雅。此外,如果特性继续增长,我们的 Color 类将变得非常臃肿且难以维护。

所以,在面向对象编程中,我们更愿意创建一个派生类。派生类可以访问父类的所有公共属性。在 JavaScript 中,派生类是通过 extends 子句声明的,它指示它扩展自哪个类。

下面是父类代码:

class Color {constructor(r, g, b) {this.values = [r, g, b];}get red() {return this.values[0];}set red(value) {this.values[0] = value;}
}const red = new Color(255, 0, 0);
red.red = 0;
console.log(red.red); // 0

下面是派生类代码:

class ColorWithAlpha extends Color {#alpha;constructor(r, g, b, a) {super(r, g, b);this.#alpha = a;}get alpha() {return this.#alpha;}set alpha(value) {if (value < 0 || value > 1) {throw new RangeError("Alpha 值必须在 0 与 1 之间");}this.#alpha = value;}
}

有一些事情需要注意。首先,在构造器中,我们调用了 super(r, g, b)。在访问 this 之前,必须调用 super(),这是 JavaScript 的要求。super() 调用父类的构造函数来初始化 this——这里大致相当于 this = new Color(r, g, b)super() 之前也可以有代码,但你不能在 super() 之前访问 this——JavaScript 会阻止你访问未初始化的 this

在父类完成对 this 的修改后,派生类才可以对其进行自己的逻辑。这里我们添加了一个名为 #alpha 的私有字段,并提供了一对 getter/setter 来与之交互。

派生类会继承父类的所有方法。例如,尽管 ColorWithAlpha 自身并没有声明一个 get red() getter,你仍然可以访问 red,因为这个行为是由父类指定的:

const color = new ColorWithAlpha(255, 0, 0, 0.5);
console.log(color.red); // 255

派生类也可以覆盖父类的方法。例如,所有类都隐式继承自 Object 类,它定义了一些基本方法,例如 toString()。然而,基本的 toString() 方法是出了名的无用方法,因为它在大多数情况下打印 [object Object]

console.log(red.toString()); // [object Object]

所以,我们可以覆盖它,以便在打印颜色时打印它的 RGB 值:

class Color {#values;// …toString() {return this.#values.join(", ");}
}console.log(new Color(255, 0, 0).toString()); // '255, 0, 0'

当你用 extends 时,静态方法也会继承,因此你也可以覆盖或增强它们。

class ColorWithAlpha extends Color {// ...static isValid(r, g, b, a) {// 调用父类的 isValid(),并在此基础上增强返回值return super.isValid(r, g, b) && a >= 0 && a <= 1;}
}console.log(ColorWithAlpha.isValid(255, 0, 0, -1)); // false

为什么用类

本指南到目前为止一直很实用:我们专注于如何使用类,但有一个问题尚未解答:为什么要使用类?答案是:视情况而定。

类引入了一种范式,或者说是一种组织代码的方式。类是面向对象编程的基础,而面向对象编程是建立在诸如继承和多态(特别是子类型多态)等概念之上的。

简而言之,你应该在你想要储存一些内部数据、并暴露大量方法的时候考虑使用类。例如这些内置的 JavaScript 类:

  • Map 与 Set 类存储了许多元素,你可以通过 get()set()has() 等方法访问它们。
  • Date 类以 Unix 时间戳的形式存储日期,并允许你格式化、更新与读取单独的日期元素。
  • Error 类存储了特定异常的信息,包括错误消息、堆栈跟踪、原因等。它是少数几个拥有丰富继承结构的类之一:有多个内置类(例如 TypeError 与 ReferenceError)继承自 Error。在发生错误时,这种继承允许细化错误的语义:每个错误类都代表一个特定类型的错误,可以很容易地通过 instanceof 进行检查。

JavaScript 提供了以面向对象的方式组织代码的能力,但是否并如何使用它完全取决于程序员的判断。

附:以上内容均为个人在MDN网站上学习JS的笔记,若有侵权,将在第一时间删除,若有错误,将在第一时间修改。

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

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

相关文章

JavaScript 技术100问?

JavaScript 是一种高级的、解释型的编程语言&#xff0c;通常用于为网页添加交互性和动态功能。作为 Web 开发中最重要的技术之一&#xff0c;JavaScript 在前端开发中扮演着重要角色。它可以直接嵌入到 HTML 中&#xff0c;并通过浏览器解释执行。JavaScript 的语法类似于 Jav…

2.Linux文件IO基础

Linux 文件 I/O&#xff08;Input/Output&#xff09;基础是 Linux 应用程序开发中的重要组成部分。在 Linux 系统中&#xff0c;文件 I/O 涉及到文件的读取和写入&#xff0c;以及文件描述符、系统调用等概念。以下是 Linux 文件 I/O 的基础知识&#xff1a; 1. 文件描述符 …

GEE Rgee——使用 eemont 和 geemap来进行Landsat 8数据的反演NDSI

简介 用 rgee 在 R 中使用 eemont 和 geemap来快速进行NDSI反演。 Landsat 8是一颗运行于太阳同步轨道上的遥感卫星,可以获取高分辨率的光学遥感数据,其中包括多光谱和热红外波段。NDSI(Normalized Difference Snow Index)是一种用于检测和分析雪被覆盖情况的指数。本文将…

算法刷题day25:多路归并

目录 引言概念一、鱼塘钓鱼二、技能升级三、序列 引言 关于这个多路并归蓝桥杯考的不是很多&#xff0c;如果要出的话&#xff0c;可能模型都会差不多&#xff0c;因为不会出太难的题&#xff0c;难题基本上都是贪心、DP之类的&#xff0c;所以好好刷题刷熟练就行了&#xff0…

ms office学习记录10:Excel㈣

自动填充时也可输入前几个值&#xff0c;选中单元格双击右下角黑色箭头进行填充 将填充样本行列粘贴至原列后要注意删除样本行列内容 排序与筛选 “数据”选项卡中的“排序”与“开始”选项卡中的“排序和筛选”实质相同 排序依据&#xff1a;数值内容和数值格式 “选项”…

最大的单入口空闲区域

最大的单入口空闲区域 问题描述输入输出代码实现 问题描述 找到最大的单入口空闲区域。 空闲区域是由连通的’O’组成的区域&#xff0c;位于边界的’O’可以是入口&#xff0c; 单入口空闲区域即有且只有一个位于边界的’O’作为入口的由连通的’O’组成的区域。 如果两个元素…

Docker使用之Docker Compose【入门篇】

Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。它允许用户通过一个单一的文件来定义多个容器&#xff0c;然后使用一个命令来启动、停止和管理这些容器。在本文中&#xff0c;我们将详细介绍如何使用Docker Compose进行多容器管理&#xff0c;并提供一个范例…

大数据开发(Spark面试真题-卷六)

大数据开发&#xff08;Spark面试真题&#xff09; 1、Spark HashPartitioner和RangePartitioner的实现&#xff1f;2、Spark DAGScheduler、TaskScheduler、SchedulerBackend实现原理&#xff1f;3、介绍下Sparkclient提交application后&#xff0c;接下来的流程&#xff1f;4…

查找C++中所有代码行数超过100的类成员函数

执行效果 python3 find_large_functions.py ./stage_test.cpp: StageTest::process has 106 lines. ./stage_test.cpp: StageTest::do_test_ has 172 lines.实现方法 在检测到函数开始的“可能”标志后&#xff08;比如返回类型和作用域运算符::&#xff09;&#xff0c;开始…

Vue-router

router的使用&#xff08;52&#xff09; 5个基础步骤&#xff1a; 1.在终端执行yarn add vue-router3.6.5&#xff0c;安装router插件 yarn add vue-router3.6.5 2.在文件的main.js中引入router插件 import VueRouter from vue-router 3.在main.js中安装注册Vue.use(Vue…

力扣:链表篇章

1、链表 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个节点的指针域指向null&#xff08;空指针的意思&#xff09;。 2、链表的类…

Python高级二

一、异常 1、定义 异常是在程序执行过程中出现的错误或意外情况。当程序遇到异常时&#xff0c;它会中断当前的执行流程&#xff0c;并尝试找到相应的异常处理机制来解决问题。 2、常见异常类型 SyntaxError&#xff1a;语法错误&#xff0c;通常是代码书写不符合Python语法规则…

【前端】移动端布局

目录 1.移动端特点 分辨率 二倍图 2.百分比布局 3.flex布局 3.1flex布局模型 3.2主轴对齐方式 3.3 侧轴对齐方式 3.4flex属性 1.移动端特点 PC端网页和移动端网页的不同 PC端网页&#xff1a;屏幕大&#xff0c;网页固定版心 jd.com移动端网页&#xff1a;屏幕小 没…

实战案例——Kafka集群部署

1. 规划节点 IP主机名节点192.168.100.10zookeeper1集群节点192.168.100.20zookeeper2集群节点192.168.100.30zookeeper集群节点 2. 基础准备 使用ZooKeeper集群搭建的3个节点来构建Kafka集群&#xff0c;因为Kafka服务依赖于ZooKeeper服务&#xff0c; 所以不再多创建云主机…

vue前端获取本地IP地址

新建js文件 getIpAddress.js //获取本机的IP地址 function getNetworkIp() {let ip localhost;try {const network Os.networkInterfaces();//获取本机的网路for (const iter in network) {const faces network[iter];for (const interface of faces) {if (interface.fami…

接口自动化测试的三个阶段

根本目标 测试环境中&#xff0c;保证新增接口功能正确性&#xff0c;原有接口的回归&#xff08;保证原有接口不被修改“坏”&#xff09;&#xff1b; 生产环境中&#xff0c;保证接口层面服务可用&#xff0c;功能的正确性&#xff08;保证服务挂掉时&#xff0c;及时发现…

pytorch入门

相比起keras和tensorflow,个人感觉pytorch更好一些 相比起程序语言本身,个人感觉,记住解决问题的步骤和方法更重要 import torch ttorch.tensor(1) t.size() t1torch.rand((3,4)) torch.Tensor? torch.empty((3,3)) devicetorch.device(cuda if torch.cuda.is_available() els…

Python爬网页,不确定网页的编码,不需要用第三方库

Python爬网页&#xff0c;不确定网页的编码&#xff0c;不需要用第三方库&#xff0c;自己写个判断&#xff0c;乱拳打死老师傅 detect试了&#xff0c;不好用 apparent_encoding试了&#xff0c;不好用 encoding试了&#xff0c;不好用 headers里get试了&#xff0c;不好用…

户口本怎么翻译成英文

户口本翻译件一般用于出国旅游签证、商务签证、移民留学等业务时&#xff0c;申请人所需提交的文件之一。户口本翻译件需要正规有资质的翻译机构翻译并加盖翻译专用章,这样才能得到有关部门的认可。那么&#xff0c;英国签证户口本翻译&#xff0c;中译英怎么翻译比较好&#x…

鸿蒙Harmony应用开发—ArkTS声明式开发(模态转场设置:全屏模态转场)

通过bindContentCover属性为组件绑定全屏模态页面&#xff0c;在组件插入和删除时可通过设置转场参数ModalTransition显示过渡动效。 说明&#xff1a; 从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 不支持横竖屏切换。…