进阶:编程语言基础概念总结

136 阅读6分钟

一. OOP 语言

一般都有一个终极父类 Object,一切对象若是没有赋值都默认 null/nil

dart 中即使变量是数字类型默认值也是 null,因为在 Dart 中一切都是对象,数字类型 也不例外。函数也是对象。

二. 变量类型

  • 整数(int)
  • 小数(float、double、Number)
  • 布尔值(Bool)
  • 字符串(String)
  • 有序数组(List、Array 等)
  • 无序数组(Set 等)
  • 键值类型(Dictionary、hash、map) ....

final表示变量只能被赋值一次;const表示变量是编译时常量,const变量默认为final变量。 字符串是由单引号或双引号包裹的字符序列, 布尔类型只包含两个对象,true和false。

三. 函数

1. 函数声明由返回值(可选)、函数名、参数列表以及函数体构成。函数体中可以继续声明函数,即局部函数。

//函数一般形式如下:
(返回值) + 函数名 + 参数列表 + (返回值){
      //goes
}
//函数参数列表形式一般如下:
 {形参, 形参, …} 

 {形参 实参 , 形参 实参, …} 

 {实参 形参 , 实参 形参, …} 

2. 函数一般分类:

(1)顶级函数:不为类、结构体服务的函数,在其外部例如 main 函数。

(2)匿名函数:没有名字的函数,这种函数被称为 匿名函数, 有时候也被称为 lambda 或者 closure 。 匿名函数可以赋值到一个变量中。

闭包(closure)是指一个函数对象,即使不在初始作用域内,也仍然能够访问其中的变量。一般是花括号括起来的代码块。 所谓闭包,即是函数中包含函数,这里的函数我们可以包含(Lambda表达式,匿名函数,局部函数,对象表达式)。函数式编程是现在和未来良好的一种编程趋势。 闭包表达式总是被大括号括着 其参数(如果存在)在 -> 之前声明(参数类型可以省略) 函数体(如果存在)在 -> 后面。

(3)高阶函数即指:将函数用作一个函数的参数或者返回值的函数。

(4)构造函数用于将类进行实例化(即创建对象),大部分语言需要配合关键字new。

3. 函数词法作用域(也称为静态作用域),即变量的作用域在定义时确定。

作用域范围由变量所处代码块(大括号)的层级决定,层级越深,作用域越小,层级越浅,作用域越大。

4. 函数返回值:函数若是一等公民,它可以存储在变量中,可以作为参数传递,可以在顶层声明。如果函数体内没有return语句,则语句return null(void)。

四. 运算符

  • 算术运算符
  • 关系运算符
  • 类型判定运算符
  • 赋值运算符
  • 逻辑运算符
  • 按位和移位运算符
  • 条件表达式)
  • 其他运算符

一般都是约定俗成,通用的,学习新语言只需要关注语言新增的,或者和通用逻辑有出入的部分

五. 控制流程语句

  • if 和 else
  • for 循环(、 for-in)
  • while 和 do-while
  • break 和 continue
  • switch 和 case
  • assert

一般都是约定俗成,通用的,学习新语言只需要关注语言新增的,或者和通用逻辑有出入的部分

六: 类

 1. OOP 语言的每个对象都是一个类的实例,所有的类都继承于 Object;(类是对象的模板,用于创建对象。类的声明是使用关键字class,所有类都直接或间接继承最顶端的Object类。)需要特别注意基础数据类型是否是对象。

特殊:Dart中任何保存在变量中的都是一个对象, 并且所有的对象都是对应一个类的实例。 无论是数字,函数和 null 都是对象。所有对象继承自 Object 类。

2. 类的变量和方法

(方法是为对象提供行为的函数。) 类中可以声明数据和函数,即对象的属性和方法。方法的调用要通过对象来完成: 调用的方法可以访问其对象的其他函数和数据。 普通的属性和方法是与对象实例绑定,它们被称之为实例变量和实例方法。 使用static修饰的属性和方法,它们与类绑定,通常称为类(静态)变量和类(静态)方法。

实例变量和实例方法、类变量和类方法,在类中都可以通过名称直接访问,实例变量和实例方法还可以通过self/this访问;在类的外部,实例变量和方法是通过实例.变量方式进行访问,而类变量和类方法必须通过类名.变量方式才能访问。

实例变量有时称为字段或属性。 方法是为对象提供行为的函数。 顶级函数/变量是指不在类或者结构体之内的函数。对于常见或广泛使用的工具和函数, 应该考虑使用顶级函数而不是静态方法。

3. 构造函数用于将类进行实例化(即创建对象),大部分语言需要配合关键字new。

4. Getter/Setter 方法(大部分语言自动实现或者需要手动实现),它们虽是方法却有跟属性一样的访问方式(oc/swift/dart/java等)。

5. 抽象类和抽象方法,没有函数体的方法,即只声明而不实现的方法被称为抽象方法,它只能出现在抽象类中。抽象类是使用abstract关键字修饰的类,它可以包含非抽象方法,可以被继承但不能被实例化。 如果希望抽象类能够被实例化,那么可以通过定义一个 工厂构造函数来实现。

6. 类(继承)

//一般形式(* 可以为 :、extends ...)
class ChildClass * FatherClass {

}

7. 为类添加功能

//分类,Mixin 等根据语言而不同:
OC: 分类(Category)
Swift: 类扩展(extension)和协议
Dart: Mixin
...

mixin是一种特殊的专门用于复用的类,通过mixin可以实现类似于多继承的效果。Dart 中 mixin 有两种书写方式,一种是使用class声明一个没有父类和构造函数的类,另一种是直接使用mixin关键字。

七:泛型

通常情况下,使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V 等。配合<>使用。 在类型安全上通常需要泛型支持, 它的好处不仅仅是保证代码的正常运行: 正确指定泛型类型可以提高代码质量。 使用泛型可以减少重复的代码。

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

//限制泛型类型
class Foo<T extends SomeBaseClass> {

八:同步异步 sync/async

不同语言的实现没有约定俗成的做法,不过找这两个关键字准没错。

Swift 的 async 简单例子:

DispatchQueue.global().async {
    DDLog("耗时操作 \(Thread.current)")
    //主队列回调
    DispatchQueue.main.async {
        DDLog("主线程更新 UI \(Thread.current)")     
    }
}  

Objective-C 的 async 简单例子:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    DDLog("耗时操作 \(Thread.current)")
    dispatch_async(dispatch_get_main_queue(), ^{
        DDLog("主线程更新 UI \(Thread.current)")     
    });
});

Dart 的 async 简单例子:

使用 Future 或 Stream 对象的函数. 这些函数在设置完耗时任务(例如 I/O 曹组)后, 就立即返回了,不会等待耗任务完成。 使用 async 和 await 关键字实现异步编程。

Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}

用技术术语来讲,如果一段代码定义的是如何做一件事的步骤,我们称之为命令式;相反,如果定义的是我们所预期的最终结果,它就是声明式。命令式编程强调精确控制过程细节;而声明式编程强调通过意图输出结果整体。

待续...