前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端转Flutter - 对照Javascript学Dart

前端转Flutter - 对照Javascript学Dart

作者头像
MudOnTire
发布2019-10-15 10:44:27
2.7K0
发布2019-10-15 10:44:27
举报
文章被收录于专栏:MudOnTireMudOnTire

最近在学flutter,发现flutter的编程语言Dart和Javascript有诸多相似,对于前端开发者而已好处在于有JavaScript经验学习Dart会快一些,缺点在于容易搞混这两种语言。因此在学习的过程中记录了一下Javascript和Dart的对比,方便记忆。

1. 程序入口(Entry Point)

Javascript:

JS不像很多语言有一个main()函数作为程序入口,JS并没有标准的程序入口,JS会从代码的第一行开始执行(在执行之前会有一些预处理的工作,比如变量提升和函数提升)。在实际项目中我们通常会有一个index.js这样的入口文件。

Dart:

Dart有一个标准的程序入口:

代码语言:javascript
复制
main(){
}

2. 数据类型(Data Types)

Javascript:

JS 有 8 种内置数据类型,分别为:

  • 基本类型:
    • Boolean:布尔类型,有两个值truefalse
    • Null:空类型,只有一个值null
    • Undefined:变量未初始化则为Undefined类型
    • Number:数字类型,取值范围为-(2^53-1) ~ 2^53 - 1,可以为整数和小数
    • Bigint:表示任意精度的整数,如const x = 2983479827349701793697123n
    • String:字符串类型,可用 "", '', ``表示。其中``用于字符串模板,比如:`1 + 2 = ${1+2}`
    • Symbol:符号类型,用于定义匿名且唯一的值,一般用作 Object 属性的 key
  • Object

其中 7 个基本类型的值是不可变的(immutable value)。Object 用来定义复杂数据类型,JS内置了一些复杂类型比如:FunctionDateArrayMapSet等。

Dart:

Dart 也有 8 种内置数据类型:

  • Boolean:布尔类型,有两个值truefalse
  • Number:数字类型,又分为int和double类型
    • int:整型,取值范围为-2^63 ~ 2^63 - 1
    • double:64位双精度浮点型
  • String:字符串类型,可用"", ''表示。与 JS 类似,可使用模板语法'${expression}',当expression是一个标识符时可省略{}
  • List:相当于 Javascript 中的 Array,例如:var arr = [1, 2, 3]
  • Set:与 JavaScript 的 Set 类似,表示无序且无重复元素的集合,例如:var countries = {'china', 'usa', 'russia', 'german'}
  • Map:与 JavaScript 的 Map 类似,表示一组键值对的集合,其中键必须唯一,键和值都可以为任意类型,例如: var gifts = { 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' };
  • Runes:表示字符串的 UTF-32 编码值(Unicode 为世界上所有书写系统中使用的每个字母,数字和符号定义了唯一的数值。由于 Dart 字符串是 UTF-16 编码的序列,因此在字符串中表示 32 位 Unicode 值需要特殊的语法),例如: Runes input = new Runes('\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}'); print(new String.fromCharCodes(input)); // ♥ ? ? ? ? ?
  • Symbol:与 JS 的 Symbol 不同,Dart 引入 Symbol 的意义在于在压缩代码后(压缩代码一般会修改标识符的名称,如用a, b, c代替原有 class、function、variable 的名称),依然能通过标识符的 Symbol 去访问相关的成员。

与 JS 不同的是 Dart 种所有类型都是 class,所有的值都是 class 的实例,而所有的 class 都继承于Object类。

3. 变量(Variables)

(1). 变量定义和赋值(Creating and assigning variables)

JavaScript:

JS中的变量为动态类型,定义变量不需要也无法指定类型。

代码语言:javascript
复制
var name = 'Javascript';

变量可任意赋值其他类型的值。

代码语言:javascript
复制
name = 123; // 正确

Dart:

Dart中的变量为静态类型,定义变量需要指定类型,或者由编译器进行类型推断。

代码语言:javascript
复制
String name = 'Dart'; // 指定类型
var name2 = 'flutter'; // 推断类型为String

变量类型一旦确定则不能赋值其他类型的值。

代码语言:javascript
复制
name = 123; // 错误

如果不想指定类型或者类型未知,可以使用dynamic定义动态类型的变量:

代码语言:javascript
复制
dynamic name = 'something';

(2). 默认值(Default Values)

Javascript:

若变量未初始化,默认值为undefined

Dart:

不管何种类型,默认值都为null

(3). 真假值(Truthy and Falsy Values)

Javascript:

在 Javascript 中有七种值会被判定为假值,除此之外都是真值,其中假值分别为:

  1. false:关键词false
  2. 0:数字 0
  3. 0n:BigInt 0
  4. '', "", ``:空字符串
  5. null:空值
  6. undefined:初始值
  7. NaN:not a number

Dart:

只有布尔值true是真值,其余都是假值。

4. 常量(Constants)

Javascript:

ES6 中引入了const来定义常量。

代码语言:javascript
复制
const name = 'JavaScript';

Dart:

Dart 中有两种方式定义常量:finalconst

区别在于:

  • final:final定义的常量只在使用时才会初始化和分配内存
  • const:const用于定义编译时常量(compile-time constant),即在编译时就初始化,且值为不变值(constant value,比如基本数据类型和String)。
  • final可以用于类实例的属性(instance variable)而const不可以
代码语言:javascript
复制
final pi = 3.1415926;
const g = 9.8;

5. 函数(Functions)

在JS和Dart中,函数都是 “first-class object”,意味着函数可以像普通对象一样赋值给变量、作为参数传递。

(1). 普通函数

Javascipt:

代码语言:javascript
复制
function fn(a, b){
  return a + b;
}

Dart:

代码语言:javascript
复制
int sum(int a, int b){
  return a + b;
}

或者省略掉返回值(会降低可读性,不推荐):

代码语言:javascript
复制
sum(a, b){
  return a + b;
}

(2). 匿名函数(anonymous function)

javascript:

JS中匿名函数有多种用途:

  1. 赋值给变量:
代码语言:javascript
复制
var sum = function(a, b) { return a + b };
  1. 作为函数的参数:
代码语言:javascript
复制
setTimeout(function () {
  console.log('hello world');
}, 1000);
  1. 用于IIFE(Immediately Invoked Function Expression):
代码语言:javascript
复制
(function () {
  console.log('hello world');
})();

Dart:

Dart同样支持匿名函数,且用法与JS类似。

  1. 赋值给变量:
代码语言:javascript
复制
Function sum = (int a, int b) {
  return a + b;
};
  1. 作为函数的参数:
代码语言:javascript
复制
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

(3). 箭头函数(arrow functions)

Javascript:

ES6 中引入了箭头函数:

代码语言:javascript
复制
(a, b) => {
  return a + b;
}

或者简写为:

代码语言:javascript
复制
(a ,b) => a + b;

Dart:

Dart 中也有类似的语法:

代码语言:javascript
复制
int sum(int a, int b) => a + b;

或者,省略返回值和参数类型:

代码语言:javascript
复制
sum(a, b) => a + b;

Dart 和 JS 中箭头函数的区别在于:

  1. JS 中箭头函数都是匿名的,但 Dart 中可以指定名称,当然也可以匿名,比如作为参数传入的时候。
  2. Dart 的箭头函数只能用在函数体为单个表达式的情况,比如下面写法是不允许的:
代码语言:javascript
复制
int sum(int a, int b) => {
  int c = a + b;
  return c;
}

(4). 命名参数(named parameters)

JavaScript:

ES6 中引入了参数解构的特性(parameter destructuring)。通过传入一个对象,并对其进行解构赋值来实现命名参数的特性。示例如下:

代码语言:javascript
复制
function sum({ a, b }) {
  return a + b;
}

sum({ a: 3, b: 4 }); // 7

Dart:

Dart原生支持命名参数:

代码语言:javascript
复制
int sum({int a, int b}) {
  return a + b;
}

sum(a: 3, b: 4); // 7

(5). 可选参数(optional parameters)

JavaScript:

JS中所有的参数都是可选参数。这可以理解为JS的特性也可以说是设计缺陷,毕竟有时候漏传参数又不报错容易导致各种问题。

Dart:

在Dart中,常规的参数都是必传的,而命名参数和位置参数(positional parameter)都可以是可选参数。当然方法体中需要增加容错逻辑,已防止可选参数不传导致的报错。

  1. 可选命名参数:
代码语言:javascript
复制
int sum({int a, int b}) {
  if (b == null) b = 0;
  return a + b;
}

sum(a: 3); // 3
sum(a: 3, b: 4); // 7
  1. 可选位置参数:
代码语言:javascript
复制
int sum(int a, [int b, int c]) {
  if (b == null) b = 0;
  if (c == null) c = 0;
  return a + b + c;
}

sum(3); // 3
sum(3, 4); // 7
sum(3, 4, 5); // 12

(6). 参数默认值(default parameters)

JavaScript:

JS中实现参数默认有新旧两种方法:

  1. 判断参数是否为undefined,如果是,则赋值为默认值:
代码语言:javascript
复制
function sum(a, b){
  if(typeof a === 'undefined') a = 0;
  if(typeof b === 'undefined') b = 0;
  return a + b;
}

sum(); // 0
sum(3); // 3
sum(3,4); // 7
  1. 使用ES6的默认参数特性(default parameters):
代码语言:javascript
复制
function sum(a = 0, b = 0){
  return a + b;
}

sum(); // 0
sum(3); // 3
sum(3,4); // 7

Dart:

Dart中也支持默认参数,但是只有命名参数和位置参数可以设置默认值:

  1. 命名参数:
代码语言:javascript
复制
int sum({int a, int b = 0}) {
  return a + b;
}

sum(a: 3); // 3
sum(a: 3, b: 4); // 7
  1. 位置参数:
代码语言:javascript
复制
int sum(int a, [int b = 0, int c = 0]) {
  return a + b + c;
}

sum(3); // 3
sum(3, 4); // 7
sum(3, 4, 5); // 12

6. 闭包(Closure)

闭包本质上也是函数,放在和函数并列的位置讲是为了凸显闭包的重要性,也方便大家阅读。

JS和Dart都有闭包,本质上是因为它们都使用词法作用域(Lexical Scope)且可以在函数内部再定义函数。所谓的词法作用域又叫静态作用域(Static Scope),也是大部分编程语言采用的机制,即作用域仅由代码的本文结构确定,比如内层大括号中可以访问外层大括号中定义的变量,而外层大括号不能访问内层大括号中定义的变量。与词法作用域相对的是动态作用域(Dynamic Scope),动态作用域不取决于代码的文本结构而是程序的执行状态、执行上下文。

当在函数内部再定义函数,而内部函数使用了外部函数的变量、参数,当外部函数返回后内部函数仍然保存了这些变量、参数。此时内部函数就成为了一个闭包。

JS和Dart中的闭包用法也几乎一样,示例:

JavaScript:

代码语言:javascript
复制
function makeAdder(addBy) {
  return (x) => addBy + x;
}

var add2 = makeAdder(2);
var add4 = makeAdder(4);

add2(3); // 5
add4(3); // 7

Dart:

代码语言:javascript
复制
Function makeAdder(num addBy) {
  return (num x) => addBy + x;
}

var add2 = makeAdder(2);
var add4 = makeAdder(4);

add2(3); // 5
add4(3); // 7

7. 类(Class)

Class是面向对象编程语言的核心特性,JavaScript虽然是函数式语言,但在ES6中还是引入了class。JavaScript的class本质上是基于原型继承的封装,是语法糖而已,并不是真正的面向对象继承模型的实现。而Dart天生就是面向对象的语言,所以Dart的class相比JS更加的强大和完善。

本文只比较JS和Dart的class都有的特性,而Dart的其他特性大家看 官方文档 更合适。

(1). 定义class

JavaScript:

JS中定义一个class,有两种方式:类声明(class declaration)和类表达式(class expression)。我们一般都会使用类声明。

类声明:

代码语言:javascript
复制
class Rectangle {}

类表达式:

代码语言:javascript
复制
var Rectangle = class {}

Dart:

而Dart中只支持类声明的方式,语法和JS一致:

代码语言:javascript
复制
class Rectangle {}

(2). 构造函数

JavaScript:

JS中class的构造函数为统一的constructor函数,每个class只能定义一个构造函数。也可以不定义,这时会使用一个默认的构造函数。

代码语言:javascript
复制
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Dart:

Dart中,构造函数名称和类名相同,而且初始化成员变量之前需要先定义。

代码语言:javascript
复制
class Rectangle {
  num width, height;

  Rectangle(num height, num width) {
    this.height = height;
    this.width = width;
  }
}

为了减少先定义再初始化成员变量的繁琐,Dart提供了语法糖来简化这个过程:

代码语言:javascript
复制
class Rectangle {
  num width, height;
  Rectangle(this.width, this.height);
}

与JS不同的是Dart的class能定义多个构造函数,被称为命名构造函数(named constructor),例如下面的Rectangle.square()

代码语言:javascript
复制
class Rectangle {
  num width, height;

  Rectangle(this.width, this.height);

  Rectangle.square() {
    width = 100;
    height = 100;
  }
}

(3). 构造函数的继承

JavaScript:

JS中class的构造函数可以继承,当子类未定义构造函数时默认会使用父类的构造函数:

代码语言:javascript
复制
constructor(...args) {
  super(...args);
}

而子类也可以通过调用父类的构造函数创建:

代码语言:javascript
复制
class Square extends Rectangle {}

const square = new Square(100, 100);

Dart:

Dart中,构造函数是不能继承的! 这是Dart区别于其他很多高级语言的地方。但是当子类未定义任何构造函数时会默认使用父类的无参构造函数(no-argument constructor)。

如果要在子类中使用和父类一样的构造函数,必须在子类中再次定义,例如这样是不行的:

代码语言:javascript
复制
class Rectangle {
  num width, height;

  Rectangle();

  Rectangle.size(width, height) {
    this.width = width;
    this.height = height;
  }
}

class Square extends Rectangle {}

var square = Square.size(100, 100);

需要在子类中再定义一个.size()构造函数:

代码语言:javascript
复制
class Square extends Rectangle {
  Square.size(size) {
    width = size;
    height = size;
  }
}

var square = Square.size(100);

或者也可以重定向到父类的构造函数:

代码语言:javascript
复制
class Square extends Rectangle {
  Square.size(size) : super.size(size, size);
}

(4). 成员变量

JavaScript:

JS中成员变量无需定义就能使用,但是为了类结构更清晰还是推荐先定义。成员变量可以在定义时初始化,也可以只定义而不初始化,例如:

代码语言:javascript
复制
class Rectangle {
  height = 0;
  width;
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}

Private变量:

成员变量默认是公共的(public),也可以定义为私有(private),只需在变量名前面加#

代码语言:javascript
复制
class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {    
    this.#height = height;
    this.#width = width;
  }
}

Static变量:

JS的class还支持静态(static)变量,静态变量只会创建一份,由所有的实例公用,适合存放固定不变的值。例如:

代码语言:javascript
复制
class ClassWithStaticField {
  static staticField = 'static field';
}

Dart:

Dart中的成员变量定义方式和JS类似,可以只声明也可以声明+初始化:

代码语言:javascript
复制
class Rectangle {
  num width;
  num height = 100;
}

Private变量:

同样Dart中也可以定义private变量,与JS在变量名之前加#不同,Dart在前面加_。但Dart中的private是相对于library,而不是class。

Static变量:

Dart也支持定义静态变量:

代码语言:javascript
复制
class Queue {
  static const initialCapacity = 16;
}

print(Queue.initialCapacity); // 16 

(5). 成员函数

和成员变量类似,成员函数也分为public、private、static。

JavaScript:

JS中成员函数默认为public,比如:

代码语言:javascript
复制
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  getArea() {
    return this.height * this.width;
  }
}

Private方法:

定义private的成员函数也在函数名前面加#就行了:

代码语言:javascript
复制
class Rectangle {
  #getArea() {
    return this.height * this.width;
  }
}

Static方法:

定义Static的成员函数只需在函数名前面加static关键词:

代码语言:javascript
复制
class DemoClass {
    static #privateStaticMethod() {
        return 42;
    }

    static publicStaticMethod() {
        return DemoClass.#privateStaticMethod();
    }
}

Dart:

Dart中class的成员函数定义和JS类似:

代码语言:javascript
复制
class Rectangle {
  num width;
  num height = 200;

  Rectangle(this.width, this.height);

  num getArea() {
    return width * height;
  }
}

var rect = Rectangle(30, 40);
rect.getArea(); // 1200

Private方法:

与变量一样,方法名前面加_也会被认定为私有方法。

Static方法:

静态方法的定义也是在前面加上static关键词。

代码语言:javascript
复制
import 'dart:math';

class Point {
  num x, y;
  Point(this.x, this.y);

  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

8. 异步编程(Asynchronous Programming)

使用Dart进行异步编程总会有似曾相识感,和JS一样都可以使用回调函数、和Promise如出一辙的Future还有async/await语法。

(1). 回调函数(Callback Function)

Javascript:

代码语言:javascript
复制
function fn(callback) {
  setTimeout(callback, 1000);
}

fn(() => { console.log('hello world') });

Dart:

代码语言:javascript
复制
import 'dart:async';

fn(Function callback){
  Timer(Duration(seconds: 1), callback);
}

fn((){
  print('hello world');
});

(2). Promise 和 Future

和 Javascript 中的Promise类似,Dart 提供了Future用于表示异步操作最终完成的结果。

Javascript:

代码语言:javascript
复制
function getIP() {
  return fetch('https://httpbin.org/ip')
    .then(res => res.json())
    .then(resJson => {
      const ip = resJson.origin;
      return ip;
    });
}

getIP()
  .then(ip => console.log(`my ip is ${ip}`))
  .catch(err => console.error(err));

Dart:

代码语言:javascript
复制
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<String> getIP() {
  return http.get('https://httpbin.org/ip').then((res) {
    String ip = jsonDecode(res.body)['origin'];
    return ip;
  });
}

getIP().then((ip) => print('my ip is $ip')).catchError((error) => print(error));

(3). Async 和 Await

ES2017中引入的async/await语法进一步提升了异步编程的体验,用同步语法进行异步编程,比如:

JavaScript:

代码语言:javascript
复制
async function getIP() {
  const res = await fetch('https://httpbin.org/ip');
  const resJson = await res.json();
  const ip = resJson.origin;
  return ip;
}

async function main() {
  try {
    const ip = await getIP();
    console.log(`my ip is ${ip}`);
  } catch (err) {
    console.error(err);
  }
}

main();

Dart:

Dart的async/await语法几乎和JS相同,与JS的async方法返回Promise对象类似,Dart的async方法返回一个Future对象。

代码语言:javascript
复制
void main() async {
  Future<String> getIP() async {
    final res = await http.get('https://httpbin.org/ip');
    String ip = jsonDecode(res.body)['origin'];
    return ip;
  }

  try {
    final ip = await getIP();
    print('my ip is $ip');
  } catch (err) {
    print(err);
  }
}

有未涉及到的JS和Dart的语法对比,欢迎大家补充,我会及时更新。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 程序入口(Entry Point)
  • 2. 数据类型(Data Types)
  • 3. 变量(Variables)
    • (1). 变量定义和赋值(Creating and assigning variables)
      • (2). 默认值(Default Values)
        • (3). 真假值(Truthy and Falsy Values)
        • 4. 常量(Constants)
        • 5. 函数(Functions)
          • (1). 普通函数
            • (2). 匿名函数(anonymous function)
              • (3). 箭头函数(arrow functions)
                • (4). 命名参数(named parameters)
                  • (5). 可选参数(optional parameters)
                    • (6). 参数默认值(default parameters)
                    • 6. 闭包(Closure)
                    • 7. 类(Class)
                      • (1). 定义class
                        • (2). 构造函数
                          • (3). 构造函数的继承
                            • (4). 成员变量
                              • (5). 成员函数
                              • 8. 异步编程(Asynchronous Programming)
                                • (1). 回调函数(Callback Function)
                                  • (2). Promise 和 Future
                                    • (3). Async 和 Await
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档