前言
在 Flutter/Dart 开发的过程中,我们会发现,有时候调用一个Widget或者类,可以在前面加上 new
,也可以不加 new
;声明构造函数的时候,也可以加不加 const
也都不会报错。既然有两种写法,就肯定多少会有些区别。
那么,区别是什么呢?
写上和不写 new 的区别
作为一个前端(声明式的UI标记语言),声明式的写法为我们提供了很直观的AST(动态语法树),使我们可以更符合人类直觉和习惯地构建一个应用。
但如果按照常规的编程语言写法,由于每个组件(Widget)其实都是一个类(class),我们在父组件中声明包含的子组件时要使用如下的写法,每个组件调用之前都要通过 new
关键字去实例化:
……
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: new Text('hello'),
centerTitle: true,
),
body: new ListView(
children: <Widget>[
new Text('world'),
……
],
},
);
}
……
是不是有种不伦不类的感觉:既不像我们在HTML中清晰干净,又不像在后端编程中一样只包含逻辑。在UI标记语言和编程语言之间切换,还是挺烦的,也挺不优雅的。:(
所以在 Dart 2 版本中,将 new
和 const
变成了可选的。
我们只需要在组件树中,直接调用需要的组件就好了,就像一个函数一样,而不再需要多余的关键字。所以上面的代码我们可以直接重构成下面的代码:
……
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hello'),
centerTitle: true,
),
body: ListView(
children: <Widget>[
Text('world'),
……
],
},
);
}
……
你会发现,少敲了几下键盘,却带来了很大的快♂感。
所以结论是:
用不用 new
,只有 Dart 版本的区别(和手感的区别),而不会带来任何性能及其他任何东西的损耗。
const
const
关键字相对复杂一点,我们分两种情况说。
使用 const 调用组件
先贴代码:
Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(height: 8.0),
],
)
在这种情况下,使用 const
调用,会让这个子组件在父组件的状态改变时不再被渲染,即:
除了第一次渲染外,不再触发 const
调用的这个子组件的 build
方法,节省性能,提高用户体验。
但其实没啥用,所以如上文提到。在 Dart 2 中,也已经变成可选的了。
const 声明构造方法
在声明一个类/组件的构造方法时,也可以使用 const
。用了 const
的,叫“常量构造函数”。
如果一个类中,只包含使用 final
关键字声明的属性( 即实例化后不会再发生变化的属性 ),而且这个构造函数出了初始化这些属性之外什么都不做,那么你就可以用 const
关键字来声明构造函数。
我们知道,常量(或者编译时常量、运行时常量)存在的目的,就是为了减少性能损耗。同理,常量构造函数也是为了降低性能的损耗。
所以,如果你能够保证,在这个类中只设置 final
声明的属性,甚至没有属性。你就应该尽量使用常量构造函数。
常量构造函数对用于简单的、或者不可变的数据记录的类时非常有用。
但你也要注意,如果你不能保证这两点,请不要使用常量构造函数,不然调用你这个类的人会很难受:你只是删了一个 const
, 但调用者可能会完全崩溃。