22 个 Flutter 开发者必知必会的 Dart 面试题(2020)

PHP

Dart 是一门面向对象语言,但是它采用基于类的编程。它只允许单一继承,语法风格接近C语言。随着 Flutter 广泛应用,Dart 作为 Flutter 的推荐语言慢慢的进入开发者视野。在 2018 - 2019 一年时间内,Dart 的使用率狂增 532%。2020 作为 Flutter 开发者的你准备好迎接新的挑战了吗?下面是整理了一些常见的 Dart 面试中可能会被问及的问题。

Q1: 什么是 Dart ?Flutter 为什么推荐使用它?

话题: Flutter
难度: ⭐⭐

Dart 是一个用于 Flutter App 开发的 面向对象, 垃圾回收 的编程语言。它由 Google 开源并维护,并且被应用在 Google 所有内部、外部的社区应用上。之所以 Flutter 将 Dart 作为首选语言,原因有以下几点:

AOT 与 JIT 说明补充

  • Dart 是 AOT ([Ahead Of Time])运行前编译,几乎所有的 Flutter 都可以用 Dart 编写。使用 AOT 语言的优点就是使 Flutter 具有更好的性能,而且几乎所有组件都可以自定义。
  • Dart 也可以通过 JIT (Just In Time) 进行编译,以缩短开发周期,优化开发流程(典型的应用就是 Flutter 的热重载)。
  • Dart 允许 Flutter 使用 JSX 或者 XML 之类的作为界面构建布局的声明语言,这使得程序更易读和理解。由于使用这种通用的语言作为布局的声明,使得 Flutter 可以很简单的就可以时间布局的替换与修改。

🔗 源码地址: hackernoon.com

Q2: 什么是 Fat 箭头函数? 在 Dart 中什么场景下会使用它?

话题: Flutter
难度: ⭐⭐

当你的方法只有一个表达式作为返回值的时候,你可以使用它的简化方式实现,一个形似 (){ return expression; }的语句。

当你的代码只有单行的时候可以省略大括号。

在 (=>) 和 (;)之间只能包含一个表达书,不能出现语句。例如: if 不能用在此处,但是 conditional 表达式可以,下面是一个例子:

// 普通方法
void function1(int a) {
  if (a == 3) {
    print('arg was 3');
  } else {
    print('arg was not 3');
  }
}

// 箭头函数
void function2(int a) => print('arg was ${a == 3 ? '' : 'not '}3');

🔗 Source: stackoverflow.com

Q3: Dart中的可选参数和必填参数是如何区分的?

Topic: Flutter
Difficulty: ⭐⭐⭐

必填参数

Dart 需要必填参数来完成函数或者方法的定义。

findVolume(int length, int breath, int height) {
 print('length = $length, breath = $breath, height = $height');
}

findVolume(10,20,30);

可选参数

  • 可选参数必须放在必填参数之后
  • 在 Flutter/Dart 中, 有三种实现方式:
    • 命名
      • 通过 [] 定义
      • 例如. getUrl(int color, [int favNum])
    • 位置
      • 通过 ‘{}’ 定义
      • 例如. getUrl(int color, {int favNum})
    • 设置默认值
      • 设置参数默认值
      • 例如. getUrl(int color, [int favNum = 6])

🔗 Source: stackoverflow.com

Q4: 名称可选参数和位置可选参数的区别?

话题: Flutter
难度: ⭐⭐⭐

两者都属于可选参数:

位置可选参数:

  • 通过 [ ] 包裹的是位置可选参数。例如:

    getHttpUrl(String server, String path, [int port=80]) {
      // ...
    }
    
  • 你可以定义多个位置可选参数:

     getHttpUrl(String server, String path, [int port=80, int numRetries=3]) {
       // ...
     }
    

    上述代码中: portnumRetries 都是可选参数,并且具有默认值。你可以不传递第三个第四个参数,并成功调用getHttpUrl。但是,你如果想要传递第四个参数,则第三个也不能省略,因为位置可选参数以位置作为判断依据。

名称可选参数:

  • 通过 { } 包裹的参数叫名称可选参数.

    getHttpUrl(String server, String path, {int port = 80}) {
      // ...
    }
    
  • 同样,你也可以指定多个名称可选参数:

     getHttpUrl(String server, String path, {int port = 80, int numRetries = 3}) {
       // ...
     }
    

    名称可选参数不会受到位置约束,只要在调用getHttpUrl 之后执行其名称即可。

     getHttpUrl('example.com', '/index.html', numRetries: 5, port: 8080);
     getHttpUrl('example.com', '/index.html', numRetries: 5);
    

🔗 Source: stackoverflow.com

Q5: 怎么理解 Flutter/Dart 中的 Stream?

话题: Flutter
难度: ⭐⭐⭐

  • Dart异步编程的两个特性 FutureStream

  • stream 就是事件流或者管道,是一些的 ‘异步’ 事件。它会在上一个事件完成时通知你进行下一个事件。

  • Streams 无论用什么方式创建,都会以相同的方式返回并使用: asynchronous for loop( await for)。例子:

    Future<int> sumStream(Stream<int> stream) async {
      var sum = 0;
      await for (var value in stream) {
        sum += value;
      }
      return sum;
    }
    
  • Streams 提供 asynchronous 序列化的数据。

  • 该序列化数据包含了用户生成的时间和重文件中读取的数据。

  • 你可以通过 await forlisten()来处理 Stream API 返回的数据流。

  • Streams 提供了错误相应的处理方法。

  • Streams 有两种方式: single subscription(订阅) 和 broadcast(广播)。

🔗 源码: dart.dev

Q6: 说明下 Streams 两种类型?

话题: Flutter
难度: ⭐⭐⭐

下面是两种 Streams 类型说明:

  1. Single subscription streams(单一订阅)

    • 最常见,最基本的 streams 实现方式。
    • 它的数据大部分是 sequence of events。单一订阅必须以正确的顺序交付事件,并且中间不能有任何异常。
    • 这是当你在读取文件或接受网络请求的时候产生的 stream 。
    • 这样的流不具备幂等性,再次接收可能会不同于上次的请求。
    • 当你开始监听,数据将被提取并以块的形式提供。
    • Broadcast streams(广播)
    • 适用于可以一次处理一个的单个消息。例如,这种流可用于浏览器中的鼠标事件。
    • 您可以随时开始收听这样的流,并且在收听时会触发事件。
    • 多个收听者可以同时收听,您可以在取消上一个订阅后稍后再次收听。

🔗 源码: dart.dev

Q7: 什么是空感知运算符 ?

话题: Flutter
难度: ⭐⭐⭐

  • Dart 提供了一些操作符,以方便处理可能为null的值。

  • 这其中一个 ??= 赋值运算符,该运算符仅在变量值为空的时候才为其赋值,使用如下:

     int a; // 定义了变量,并未赋值,所以这里变量值为 null
     a ??= 3;
     print(a); // <-- 打印 3.
    
     a ??= 5;
     print(a); // <-- 依然打印 3.
    
  • 另一个空感知运算符 ?? ,在表达式值不为 null 的时候,它会返回左侧表达式的值,否则返回右侧表达式的值:

    print(1 ?? 3); // <-- 打印 1.
    print(null ?? 12); // <-- 打印 12.
    

🔗 来源: dart.dev

Q8: 怎么来监测判定一个异步 viod 方法已经执行完成呢?

话题: Flutter
难度: ⭐⭐⭐

修改返回类型为 Future<void>.

Future<void> save(Folder folder) async {  
   .....
}

然后你可就可以使用 await save(...);save().then(...); 来判断了。

🔗 Source: stackoverflow.com

Q9: 如何在 Dart 中将异步函数声明为变量?

话题: Flutter
难度: ⭐⭐⭐

在普通函数基础之上,dart 提供了一个Future 语法糖。只要变更该函数返回类型为一个 Future 就可以了:

class Example {
  Future<void> Function() asyncFuncVar;
  Future<void> asyncFunc() async => print('Do async stuff...');

  Example() {
    asyncFuncVar = asyncFunc;
    asyncFuncVar().then((_) => print('Hello'));
  }
}

void main() => Example();

🔗 源码: stackoverflow.com

Q10: 如何填充 Dart List?

话题: Flutter
难度: ⭐⭐⭐

代码:

final List<Ball> _ballList =[Ball(),Ball(),Ball(),Ball(),Ball(),]

怎样才能部多次执行 Ball() ,又能生成多个 Ball()呢?


这里可以使用 collection-for ,他会生成 Ball()的多个不同实例。

final List<Ball> _ballList = [
  for (var i = 0; i < 5; i += 1) Ball(),
];

如果需要多个 Ball()的相同实例,可以使用 List.filled 这种更简便的方法:

final List<Ball> _ballList = List<Ball>.filled(5, Ball());

🔗 源码: stackoverflow.com

Q11: whenCompleted() 与 then() 的异同?

话题: Flutter
难度: ⭐⭐⭐

  • .whenComplete将在 Future 没有错误的情况下完成的时候触发,而 .then 会返回一个新的 Future ,根据其结果然后通过 onValue (成功的返回) 或者 onError (失败,带有错误的返回) 来处理。
  • .whenCompleted 是 “finally“。

🔗 源码: stackoverflow.com

Q12: 在 Flutter/Dart 中,如何获取两 list 的不同?

Topic: Flutter
Difficulty: ⭐⭐⭐

假定你有 list [1,2,3,4,5,6,7][3,5,6,7,9,10].那么该如何获取两者之间的不同呢?既 [1, 2, 4]


你可以这样做:

List<double> first = [1,2,3,4,5,6,7];
List<double> second = [3,5,6,7,9,10];
List<double> output = first.where((element) => !second.contains(element));

或者这样:

List<double> first = [1,2,3,4,5,6,7];
List<double> second = [3,5,6,7,9,10];
List<double> output = [];

first.forEach((element) {
    if(!second.contains(element)){
    output.add(element);
}
});

// output list 应该就是你想要的结果

无论哪种情况都需要遍历该 larger list.

🔗 源码: stackoverflow.com

Q13: 解释下 async, await 在 Flutter/Dart 中的应用?

话题: Flutter
难度: ⭐⭐⭐⭐

async(Asynchronous)允许你同时进行多项工作。下面是以下常见异步应用场景:

  • 通过网络接口获取数据。
  • 数据库写入操作。
  • 从文件读取数据。

在 Dart 中的异步操作,你可以使用 Futureasyncawait 关键字来实现。

通过 asyncawait 关键字声明一个异步函数,并等待其返回结果。在使用 asyncawait 的时候,请注意一下几点:

  • 异步功能是基于 async 关键字,所以必须添加该关键字。
  • await 关键字仅在 async 声明的函数中起作用。

在第一个 asyncawait 关键字之间的代码是立即执行的。

下面是个例子:

import 'dart:async';

class Employee {
  int id;
  String firstName;
  String lastName;

  Employee(this.id, this.firstName, this.lastName);
}

void main() async {
  print("getting employee...");
  var x = await getEmployee(33);
  print("Got back ${x.firstName} ${x.lastName} with id# ${x.id}");
}

Future<Employee> getEmployee(int id) async {
  //通过颜值两秒来模拟服务器请求时间延迟
  await Future<Employee>.delayed(const Duration(seconds: 2));
  //构建一个员工信息,并返回
  var e = new Employee(id, "Joe", "Coder");
  return e;
}

🔗 Source: dart.dev

Q14: Flutter/Dart 中 Future 如何使用?

话题: Flutter
难度: ⭐⭐⭐⭐

  • A Future 用于表示可能会出现的错误或误差。 * Future * 可以注册通过回调处理,当相应的错误被抛出的时候你就可以捕获并处理它了。例如:(译者注:作为一个phper,从php角度出发,这就是try catch吧)

    Future<int> future = getFuture();
    future.then((value) => handleValue(value))
          .catchError((error) => handleError(error));
    
  • 如果异常不在预期之内,将会抛出类型为 Future<void> 的异常。

    • Future * 是异步操作,并且存在两种状态:

      1. 第一种状态 Uncompleted。该状态表示当您调用 asynchronous 函数时,它返回的是一个未完成的 Future。Future 正在等待函数的 asynchronous 操作完成或将错误抛出。
      2. *Completed 如果 asynchronous 操作成功,则将来以一个值完成。否则,它会以错误完成。

🔗 源码: api.dart.dev

Q15: Dart\Flutter 中 Future 和 Stream 的异同?

话题: Flutter
难度: ⭐⭐⭐⭐

相同点:

  • FutureStream 都属于异步操作。
  • 两者都有一定的潜在价值。

不同点:

  • Stream is a combination of Futures.
  • Future 有且只有一个响应值,而 Stream可能会有多个响应值。

🔗 源码: medium.com

Q16: Dart AOT 是如何工作的?

话题: Flutter
难度: ⭐⭐⭐⭐

  • Dart源代码将被翻译成汇编文件,然后汇编器会将汇编文件编译成用于不同体系结构的二进制代码。
  • 对于移动应用程序,源代码针对多个处理器ARM,ARM64,x64以及两个平台(Android和iOS)进行编译。这意味着每种支持的处理器和平台组合都有多个结果二进制文件。

🔗 源码: flutterbyexample.com

Q17: 操作符 ?? 和 ? 的异同。

话题: Flutter
难度: ⭐⭐⭐⭐

??

  • 这是一个 空赋值操作符,当左侧表达式为 null 的时候才会返回右侧的表达式,否则返回其左侧的表达式:
print(1 ?? 3); // <-- 打印 1.
print(null ?? 12); // <-- 打印 12.

?.

  • 这是个条件属性访问符,用于访问可能为空的对象或者属性:

  • 单个表达式中可以使用多个 ?.

    myObject?.someProperty?.someMethod()
    

    如果 myObjectmyObject.someProperty 为 null,则上述代码返回 null (并且永远不会调用someMethod())。

🔗 源码: flutter.dev

Q18: Dart 中 async 和 async* 的异同?

话题: Flutter
难度: ⭐⭐⭐⭐

  • async 返回一个 Futureasync* 将返回 Stream
  • async 关键词可应用于某些执行时间较长的方法。他会以 Future 的形式返回。
  • 如果您希望返回多个值您可以用 async*,他将返回结果以 Stream 的形式返回 。
  • async* 使用返回 Stream 并提供了一些可以以 yield 关键字返回值的语法糖。

🔗 源码: stackoverflow.com

Q19: Dart 中如何比较两个不同的日期?

话题: Flutter
难度: ⭐⭐⭐⭐

您可以通过将另一个日期转换为utc并将其与isAtSameMomentAs方法进行比较来实现。下面是一个 Demo:

void main(){
  String dateTime = '2020-02-03T08:30:00.000Z';
  int year = 2020;
  int month = 2;
  int day = 3;
  int hour = 8;
  int minute = 30;

  var dt = DateTime.utc(year,month,day,hour,minute);

  print(DateTime.parse(dateTime).isAtSameMomentAs(dt));
}

🔗 源码: stackoverflow.com

Q20: Dart “non-nullable by default” 是什么意思?

话题: Flutter
难度: ⭐⭐⭐⭐

  • Non-nullable by default 意味着 Dart 中声明的的任何变量不能为null
  • 不可以在没赋值之前访问该变量。
  • 另外,变量不能被赋值为 null

具体看例子:

void main() {
  String word;
  print(word); // 报错

  word = 'Hello, ';
  print(word); // 合法
}
void main() {
  String word;

  word = null; // 进制
  world = 'World!'; // 允许
}

🔗 源码: stackoverflow.com

Q21: 在 Dart/Flutter 中 ._() 方法是什么意思?

话题: Flutter
难度: ⭐⭐⭐⭐

  • 在 Dart 中,以下划线开头的函数表明该函数是私有的。
  • 形如 Class._(); 的函数可能是一个构造函数 (在 Flutter 中,也可能是某个对象的副本的构造函数,如:AnotherClass.copy(...);).
  • 形如 Class._(); 不是必须的,除非你想要在构造函数中执行某些操作。

🔗 Source: stackoverflow.com

Q22: Dart 中如何将 List 转换为 Map?

话题: Flutter
难度: ⭐⭐⭐⭐

你可以使用 Map.fromIterable:

var result = Map.fromIterable(l, key: (v) => v[0], value: (v) => v[1]);

或者 collection-for (从 Dart 2.3 开始支持此方法):

var result = { for (var v in l) v[0]: v[1] };

🔗 源码: stackoverflow.com

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://dev.to/fullstackcafe/22-dart-int...

译文地址:https://learnku.com/app/t/46584

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 1

好文! 用了那么久,不总结,真的容易忘,而且也表达不了那么多的知识点

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!