This article is the third in the series of "A JSer's Dart Learning Log". This series of articles mainly aims to explore the similarities and differences between JS and Dart, while reviewing and consolidating JS while smoothly transitioning to the Dart language.
Since the author is still a beginner to Dart, his understanding may be superficial and one-sided. If you know the worms, I hope you can correct me.
Unless otherwise specified, the JS in this article contains all the features from ES5 to ES2021, and the Dart version is 2.0 or higher.Before ES6 came out, the widely popular JS object-oriented programming used prototype chain instead of using classes. Developers need to have sufficient understanding of relevant features and follow some default rules to barely simulate a generally usable " kind". Even if ES6 introduces the
class
keyword to make up for it, it still needs to be improved as a new generation of JS infrastructure.
In contrast, Dart's support for classes is much more complete and powerful.
1. Similar overall structure
In the two languages, the grammatical structures used to define classes are highly similar, mainly including
class
, class names, and members{}
> /* Both JS and Dart */ > class ClassName { > attrA; > attrB = 1; > > methodA(a, b){ > // do something > this.attrA = a; > this.attrB = b; > } > }
2. Constructor
Similarities
- The constructor is called when the class is instantiated, and is used to process instantiation parameters, initialize instance attributes, etc.;
- Use
super
access the superclass's constructor; - When there is no superclass or the constructor of the superclass has no parameters, the constructor can be omitted. When the subclass of the omitted constructor is instantiated, the superclass's constructor will be implicitly called.
the difference
1. constructor
vs SameName
- The constructor in JS is
constructor
; - , which is the same function as the class name .
> /* JS */ | /* Dart */
> class Point{ | class Point{
> constructor(){ | Point(){
> } | }
> } | }
Specific properties of Dart constructor
1. Named constructor
In Dart you can declare multiple named constructors for a class to express a clearer intent , such as
Map
object to an instance:> class PointCanBeEncode{ > int x = 0; > > // 名为 `eval` 的命名式构造函数 > Point.eval(Map<String, dynamic> map){ > x = map['x']; > } > > encode(): Map<String, dynamic>{ > return { > 'x': this.x > } > } > }
Of course, since JS is a very flexible language, we can also
JS
the static method ofDart
into a named constructor similar to 06164057625d1b.
2. Syntax sugar for attribute assignment
In most cases, the role of the constructor includes given value as an instance attribute . Dart provides a very convenient syntactic sugar for this situation:
> /* Dart */ | /* Also Dart */ > class Point { | class Point { > Point(this.x, this.y); | Point(x, y){ > } | this.x = x; > | this.y = y; > | } > | }
↑ You can see that the code on the left is obviously much more concise.
3. Initialization list
Dart can initialize instance variables before the constructor is executed:
class Point { final double x, y, distanceFromOrigin; Point(double x, double y) : x = x, y = y, distanceFromOrigin = sqrt(x * x + y * y) { print('still good'); } }
The execution of the initialization list is actually even earlier than the execution timing of the parent class constructor.
4. Redirection constructor
Dart can have multiple constructors, and you can redirect one constructor to another:
class Point { double x, y; Point(this.x, this.y); Point.alongXAxis(double x) : this(x, 0); }
Except for the default parameters, I didn't see any usage scenarios. I tried
alongXAxis
it seems that there is no function body. . .
5. Constant Constructor
If the objects generated by the class are constant, you can change them to compile-time constants when generating these objects. You can in front of the class's constructor plus
const
keyword and ensure that all instance variables arefinal
to implement this function.class ImmutablePoint { // 所有变量均为 final final double x, y; // 构造函数为 const const ImmutablePoint(this.x, this.y); }
6. Factory Constructor
- JS is a very flexible language. When the constructor does not return a value, it can be regarded as returning a new instance, but at the same time the constructor can also return any value as a new instance;
- In Dart, you can use the
factory
keyword to declare a constructor with a return value.
> /*************** 分别用两种语言实现单例模式 *****************/
> /* JS */ | /* Dart */
> class A { | class A {
> static single; | static var single;
> | A();
> constructor() { | factory A.single(){
> if(!A.single) { | if(single == null) {
> A.single = this; | single = A();
> } | }
> return A.single; | return single;
> } | }
> } | }
> var instance = new A(); | var instance = A.single();
this
cannot be accessed within the factory constructor.
7. Abstract class
- Use the
abstruct
keyword to declare abstract classes. Abstract classes are often used to declare interface methods and sometimes have specific method implementations.
The abstract method will be mentioned below. The abstract method can only be used in the abstract class .
3. Use
Similarities
- You can use the
new
keyword to instantiate the class; - Use
.
visit members; - Use the
extends
keyword to extend the class and inherit its properties.
> /* Both JS and Dart */
> var instance = new ClassName('propA', 42);
> instance.attrA; // 'propA'
the difference
1. Dart can omit the keyword new
new
keyword of the Dart instantiation class can be omitted, and the class can be initialized like a function:> var instance = ClassName('propA', 42);
;
- The
class of ES5 is also a function. Omitting the
new
keyword is equivalent to executing this function, while the ES6 class is no longer a function. Omitting thenew
keyword will cause an error.
2. Dart named constructor
With the "named constructor", an instance can be created in a more flexible way, such as quickly mapping an attribute of
Map
> var instance = PointCanBeEncode.eval({'x': 42});
If you need to store and transfer the instance, you can instance through the 161640576261f8 instance -> Map/List -> JSON string solution, and then use the JSON string -> Map/List -> new instance method to serialize it. recover".
3. Dart's compile-time constant instance
The constant constructor can instantiate compile-time constants, reducing the burden at runtime:
var a = const ImmutablePoint(1, 1);
;
- And JS has no compile-time constants at all.
The side shows that the constructors of primitive types are constant constructors.
4. Override the members of the superclass
- In JS, the static methods of the subclass can
super.xxx
members of the subclass will override the members of the superclass with the same name, but the subclass can call the members of the superclasssuper.xxx
members, and the first inconstructor
callsuper
); In
Dart
, use the@override
annotation to mark the method of rewriting the superclass (the actual test found that you can compile without writing the annotations, Lint will give a prompt, which should be related to the environment configuration).> /* JS */ | /* Dart */ > class Super{ | class Super{ > test(){} | test(){} > } | } > class Sub{ | class Sub{ > /* just override it */ | @override > test(){ | test(){ > super.test(); | super.test()'; > } | } > } | }
Dart's mixin
When declaring a class in Dart, use the
with
keyword to mix in aconstructor
, which can bemixin
keyword:mixin Position{ top: 0; left: 0; } class Side with Position{ }
Four. Member attributes and member methods
Similarities
- Inside the member function, use
this
access the current instance, and use the dot (.
) to access the members; - Use
static
keywords to define static members; Definition
getter
andsetter
:> /* JS */ | /* Dart */ > class Test { | class Test { > #a = 0; | private a = 0; > get b(){ | get b(){ > return this.#a; | return this.a; > } | } > set b(val){ | set b(val){ > this.#a = a; | this.a = val; > } | } > } | }
。
the difference
1. The closed scope of the class
- The JS class has no scope, so access members must use
this
; - Dart's class has a closed scope, and other members can be directly accessed in member functions without specifying
this
.
> /* JS */ | /* Dart */
> const a = 3; | const a = 3;
> class Test{ | class Test{
> a = 1; | a = 1;
> test(){ | test(){
> console.log(a === this.a); | print('${a == this.a}');
> /* 'false' */ | // 'true'
> } | }
> } | }
2. Private variables/attributes
- The private members of the class instance in JS are
#
, and this prefix should also be used when accessing; - The private members of the instance in Dart are
_
can be accessed directly in the "class scope".
> /* JS */ | /* Dart */
> class Test{ | class Test{
> #secret = 1234; | _secret = 1234;
> test(){ | test(){
> console.log(this.#secret); | print('${_secret}');
> } | }
> } | }
Private members of JS are a very "young" attribute. Prior to this, naming private members with underscores was a widely accepted convention by the JS community.
ES ultimately did not handpicked_
as a private member's statement scheme, we do not adoptJava
andTS
usedprivate
, instead of using#
number syntax.
In Dart, the#
syntax is used for the literal value ofSymbol
3. Operator overloading
Dart supports overloaded operators, and developers can customize logic for operations between instances, such as vector operations:
class Vector{ final double x, y; const Vector(this.x, this.y); Vector operator +(Vector obj) => Vector(obj.x + x, obj.y + y); }
The addition of vectors can be written as
const c = a + b + c
.
With operator overloading, some very intuitive grammars can be defined. For example, use
&&
and||
find the intersection and union of a set and a graph.JS does not support operator overloading, so in a vector operation scenario similar to the above, we need to customize some methods to perform operations between instances. For example, the addition of multiple vectors may be written as:
const d = a.add(b).add(c)
;const d = Vector.add(a, b, c)
。
4. Abstract methods
- The instance method of the abstract class
Getter
method, and theSetter
method in Dart can all be abstract, define an interface method and do not do the specific implementation, let the class that implements it implement the method , the abstract method can only Exists in the abstract class .
5. call
method and callable class instance
- Only functions can be called in JS. When we expect to implement "stateful" functions (such as incremental ID generators), we usually use function external variables or functions to return inner functions (using the nature of closures);
In Dart,
call
method is deployed, and its instance can be called as a function, and thecall
method of the instance is called:> /* JS */ | // Dart > const IdGen = () => { | class IdGen { > let seed = 0; | int _seed = 0; > return () => { | call(){ > return ++seed; | return ++_seed; > } | } > }; | } > const idGen = IdGen(); | final idGen = IdGen(); > console.log(idGen()); | print(idGen()); > // 1 | // 1
。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。