여러분, Flutter 프레임워크에서 사용되는 언어 Dart에 대해서 들어보셨나요?
개발자라면 JavaScript, Python, Java 등 다른 언어를 이미 접해 보셨을 거라고 생각합니다
저는 그 중에 JavaScript를 주로 사용해 왔고 이번에 Dart를 처음 접하게 되었는데요, JavaScript를 이미 알고 있는 개발자의 시선에서 본 Dart를 정리하면서 학습 콘텐츠를 만들면 재미있겠다는 생각이 들어 이 글을 작성해 보았습니다
특히 Flutter에 흥미가 있는 프론트엔드 개발자라면 재미있게 읽으실 것 같아요 😉
이 글은 JavaScript를 이미 알고 Dart는 처음 접하는 개발자들을 대상으로 작성하였으며, 말 그대로 찍먹이기 때문에 깊이 있는 내용이 아닐 수 있습니다. 물론 JavaScript에 대한 지식이 없다면 이해 불가능한 수준도 아닙니다.
Dart
Dart는 모든 플랫폼에서 빠른 앱을 위한 클라이언트 최적화 객체 지향 언어입니다
공식 문서에서는 다음 3가지 특징을 소개하고 있습니다
- UI 최적화: 사용자 인터페이스 생성 요구에 특화된 구조로 개발
- 생산적인 개발: 핫 리로드로 실행 중인 앱에서 즉시 결과 확인 가능
- 모든 플랫폼: 모바일, 데스크톱 및 백엔드용 ARM 및 x64 머신 코드, 웹용 JavaScript로 컴파일
모든 플랫폼 개발? 웹용 JavaScript로 컴파일? 🙄
이 글은 Dart를 중점적으로 다루지만 Flutter에 대한 설명을 빼놓을 수는 없는데요, Dart로 구동되는 Flutter는 인기 있는 다중 플랫폼 UI 툴킷으로, iOS, Android, macOS, Windows, Linux 및 웹에서 실행되는 UI를 빌드하기 위한 도구 및 라이브러리를 제공하는 프레임워크입니다
즉, Flutter로 웹을 대상으로 하는 앱을 개발한다면 웹 컴파일러는 Dart를 JavaScript로 변환합니다!
벌써 Dart와 JavaScript가 많은 특징을 공유할 것이라는 예감이 들지 않나요? 🤓
Variable
DartPad에서 다음 내용을 실습해 볼 수 있습니다.
가장 먼저 Dart의 변수에 대해서 알아보겠습니다!
void main() {
print("hello world");
}
JavaScript와 달리 모든 Dart 프로그램은 main 함수라는 Entry point에서 출발해야 합니다
void main() {
var food1 = "pizza"; // 방법1
String food2 = "chicken"; // 방법2
food1 = "hamburger";
}
기본적으로 var 키워드를 사용할 수 있고, 타입을 명시해서 선언할 수도 있습니다
JavaScript의 var 키워드는 블록 스코프와 TDZ가 적용되지 않아 사용이 지양되는데요, Dart에서는 그럴 걱정 없이 var 남발이 가능합니다! 재할당도 가능하기 때문에 Dart의 var가 JavaScript의 let과 비슷하다고 볼 수 있겠네요
그렇다면 JavaScript의 const 변수는 Dart에서 어떻게 선언할까요?
void main() {
final name = "pizza";
name = "ham"; // 수정 불가
}
var 대신 final 키워드를 사용해주면 됩니다!
void main() {
const name = "tom"; // 컴파일 시점에 바뀌지 않는 값
final username = fetchAPI(); // 컴파일 시점에 바뀌는 값
}
주의할 점은, Dart에서도 const 키워드가 지원되는데 이는 컴파일 이전에 이미 확정된 상수 값만 취급하기 때문에 JavaScript의 const 키워드와는 다릅니다. API로부터 받아오거나 사용자 입력 값은 final로 선언해줍니다
void main() {
String? name = "hello";
name = null;
if (name != null) name.isNotEmpty; // 방법1
name?.isNotEmpty; // 방법2
}
추가적으로 Dart는 개발자의 null 값 참조를 방지하는 null safety가 기본적으로 지원됩니다
모든 변수는 non-nullable하며 별도의 조건(null 값이 될 수도 있음)을 확인해 주어야 사용이 가능합니다
TypeScript의 Non-null assertion operator와 비슷하네요 🤔
void main() {
late final String name;
print(name); // name 변수에 접근 불가
}
이 외에도 선언한 변수에 값을 나중에 할당하겠다는 의미인 late 키워드도 있습니다
비교적 최근에 생긴 언어인 만큼 세련된 기능을 많이 가지고 있다는 생각이 드네요 😎
Data Type
데이터 타입들을 조금 더 자세히 알아볼까요?
Dart 역시 JavaScript와 비슷한 객체 기반의 언어로, 다양한 메소드가 지원됩니다
void main() {
String name = "tom";
bool alive = true;
int age = 10; // 정수
double money = 52.55; // 실수
num x = 12;
num y = 1.2;
}
기본 타입은 JavaScript와 거의 비슷하지만 숫자 타입의 정수/실수 구분이 가능합니다
void main() {
var giveMeFive = true;
var item = [
1,
2,
3,
4,
if (giveMeFive) 5,
];
List<int> numbers = [
1,
2,
3,
4,
];
}
JavaScript의 배열과 비슷한 List 타입입니다. 내부에 if/for 문 사용이 가능하며, 타입 명시가 가능한 차이점이 있습니다
void main() {
var player = {
"name": "yee",
"age": 23,
};
Map<String, String> player2 = {
"name": "yee",
"age": "23",
};
}
Dart는 Map 타입이 JavaScript의 객체와 비슷하며, 마찬가지로 타입 명시가 가능합니다
Dart에서 Object 타입은 TypeScript의 any와 비슷한 최상위 타입 개념이라고 하네요 👀
void main() {
var numbers = {1, 2, 3, 4};
Set<int> numbers2 = {1, 2, 3, 4};
}
단순히 중괄호로 감싸면 모든 값이 유일한 Set 타입을 선언할 수 있습니다
Function
다음으로 Dart의 함수를 간단하게 알아보겠습니다
String sayHello(String name) => "Hello $name";
void main() {
print(sayHello("yee"));
}
파라미터/반환 값의 타입을 명시에 함수를 선언할 수 있으며, arrow function이 지원됩니다!
더 나아가 Dart의 함수 파라미터는 두 가지 옵션이 있습니다 🙃
String sayHello(String name, int age, [String? country = "korea"]) =>
"$name / $age / $country";
void main() {
print(sayHello("yee", 23));
}
첫 번째로 순서대로 인수를 입력하는 방식인 positional parameter입니다. null safety를 위해 기본적으로 required 상태이며, 초기 값을 지정해준다면 optional positional parameter 선언도 가능합니다! 일반적이지만, Dart에서 주로 사용되는 방식은 아니라고 하네요
String sayHello(
{required String name, int age = 23, required String country}) =>
"$name / $age / $country";
void main() {
print(sayHello(name: "yee", age: 23, country: "Korea"));
}
다음으로 함수 선언부에서 매개변수를 중괄호로 묶어 인수에도 이름을 붙일 수 있는 named parameter입니다. null safety를 위해 초기값을 지정하거나 인수를 넣도록 required를 붙여줘야 하며, Dart에서 주로 사용되는 방식입니다!
Class
JavaScript 역시 클래스가 있지만, Dart의 클래스는 거의 필수적으로 사용되기 때문에 중요도가 더 높은 편입니다
Flutter 개발에 위젯과 API 모델을 클래스로 분리하는 패턴이 권장되기 때문이기도 합니다 🥸
class Player {
final String name = "yee";
int age = 23;
void sayHi() {
print("Hi my name is $name");
}
}
void main() {
var player = Player();
player.sayHi();
}
new 키워드를 생략하는 등 약간의 차이가 있지만, JavaScript의 클래스를 알고 있다면 이해가 어렵지 않습니다
class Player {
final String name;
int age, xp;
String team;
Player({
this.name = "default",
required this.age,
required this.team,
required this.xp,
});
void sayHi() {
print("Hi my name is $name");
}
}
void main() {
var player1 = Player(
name: "yee",
age: 23,
team: "blue",
xp: 1200,
);
var player2 = Player(
name: "봙봙",
age: 3,
team: "red",
xp: 150,
);
player1.sayHi();
player2.sayHi();
}
constructor method(생성자 함수)의 이름은 클래스 이름과 같아야 하며, constructor 역시 함수이기 때문에 named parameter 활용이 가능합니다!
class Player {
final String name;
int age, xp;
String team;
Player({
this.name = "default",
required this.age,
required this.team,
required this.xp,
});
Player.createBluePlayer({required String name, required int age})
: this.name = name,
this.age = age,
this.team = "blue",
this.xp = 0;
Player.createRedPlayer(String name, int age)
: this.name = name,
this.age = age,
this.team = "red",
this.xp = 0;
void sayHi() {
print("Hi my name is $name");
}
}
void main() {
var player1 = Player.createBluePlayer(
name: "yee",
age: 23,
);
var player2 = Player.createRedPlayer("봙봙", 3);
player1.sayHi();
player2.sayHi();
}
Dart에서 constructor를 여러 개 만들고 싶다면 위와 같이 named constructor를 선언해줄 수 있습니다. 콜론(:) 이후 원하는 매개변수만 할당 및 기본 값을 초기화 해줍니다
class Player {
final String name;
int xp;
String team;
Player.fromJson(Map<String, dynamic> playerJson)
: name = playerJson['name'],
xp = playerJson['xp'],
team = playerJson['team'];
void sayHi() {
print("Hi my name is $name from $team team");
}
}
void main() {
var apiData = [
{
"name": "A",
"team": "blue",
"xp": 0,
},
{
"name": "B",
"team": "red",
"xp": 0,
},
{
"name": "C",
"team": "blue",
"xp": 0,
},
];
apiData.forEach((playerJson) {
var player = Player.fromJson(playerJson);
player.sayHi();
});
}
named constructor는 API fetching 및 데이터 모델링에서 이렇게 fromJson 패턴으로 활용됩니다
Dart에도 추상 클래스나 상속의 개념이 존재하지만 Flutter에서는 잘 활용되지 않는다고 하네요 🫥
class Strong {
final double strengthLevel = 1500.99;
}
class QuickRunner {
void runQuick() {
print("ruuuuun!!");
}
}
enum Team { blue, red }
class Player with Strong, QuickRunner {
Team team;
Player({
required this.team,
});
void sayHi() {
String team = this.team.name;
print("I'm from $team team (strength: $strengthLevel)");
}
}
class Horse with QuickRunner {}
void main() {
var yee = Player(
team: Team.blue,
);
var horse = Horse();
yee.sayHi();
yee.runQuick();
horse.runQuick();
}
마지막으로 소개 드리고 싶은 개념은 mixin입니다. 생성자가 없는 클래스를 의미하며, Flutter에서 프로퍼티나 메소드 모음을 여러 클래스에 전달해 재사용하려는 목적으로 활용됩니다!
이 외에도 QQ Operator나 Cascade Notation, Typedef, Enum 등 편리한 기능들이 많지만..
이 이상은 찍먹이 아닌 것 같아 이만 줄이도록 하겠습니다 🫠
긴 글 읽어 주셔서 감사합니다!! 🙇
궁금하거나 더 자세한 내용은 Dart 공식문서를 참고해주세요! 은근슬쩍 영업
재미있게 보셨다면 블로그나 글또 Slack에 감상을 남겨주세요!
새로운 의견이나 오류 정정, 피드백은 언제나 환영입니다 😽
가능하다면 다음은 React 개발자와 Flutter 찍먹하기로 돌아오겠습니다~!
'Languages > Dart' 카테고리의 다른 글
[노마드코더] #5 Classes (0) | 2023.01.12 |
---|---|
[노마드코더] #4 Functions (0) | 2023.01.09 |
[노마드코더] #3 Data Types (0) | 2023.01.09 |
[노마드코더] #2 Variables (0) | 2023.01.08 |
[노마드코더] #1 Introduction (0) | 2023.01.04 |