编程语言通识与JS语言设计

75 阅读4分钟

借鉴自然语言的体系,所谓语言,是应当包括“语法、语义和语用”三个方面的。具体在计算机系统中实现某种语言时,如果在语言陈述时无法确定而必须在计算机执行时才能确定这三者之间的关系,则称该语言是动态语义的(反之则称为静态语义的)。

从计算范型的角度讲语言分成命令式语言、函数式语言、逻辑式语言、面向对象程序设计语言。

程序设计语言的分离及其与计算机语言的关系:

image-20221014001105308

JavaScript 也是语言不通分类间相互作用的产物,它既同时是说明式和命令式语言,又兼具串行和并行语言的特征。有着这样交叉分类特性的语言,通常被称为“多范型语言(Multi-paradigm Programming Language)”。

JavaScript 的语源(设计思想)来自AWK(脚本语言,关联数组)、C、HyperTalk(macOS 上的一种脚本语言)、Self(原型继承系统)。

最早的动态语言,据说是1960 年由Kenneth E.Iverson 在IBM 设计的APL,和同时期在贝尔实验室的D.J.Farber、R.E.Griswold 和F.P.Pllensky 三人设计的SNOBOL。这两种语言的共同特性表现为:动态类型声明和动态空间分配。

AWK 的设计思想受动态数据类型语言SNOBOL 的影响。

  • JS 是嵌入式的语言

JS 的早期实现,以及现在主要的应用都是嵌入在浏览器中、以浏览器为宿主的。但这不代表JS 必须是一个嵌入式引擎。在一些解决方案中,JS 也可以作为通用语言来实现系统。事实上,JS 引擎和语言本身,并不依赖“嵌入”的某些特性。

  • JS 用作页面包含语言(HTML Embedded、ServerPage)

JS 的主要实现的确如此,如在HTML 中使用<Script>标签来装载脚本代码,以及在ASP 中使用JScript 语言等。但是,这种特性是应用的依赖,而非语言的依赖。大多数JS 引擎都提供一种Shell 程序,可以直接从命令行或系统中装载脚本并执行,而无须依赖宿主页面。

  • 是解释而非编译

    • JS 是解释执行的,它并不能编译成二进制文件—的确存在一些JS 的编码系统和中间代码转换,但并没有真正的编译器。
  • 可以重写标识符

    • 可以随时重写除关键字以外的标识符,以重新定义系统特性。重写是一种实现,其效果便是“动态绑定”。
  • 使用动态类型系统

    • JS 在运算过程中会根据运算符的需求或者系统默认的规则转换操作数的数据类型。此外,变量在声明时是无类型的,直到它被赋予某个有类型含义的值。所以JS 即是弱类型,也是动态类型的。
  • 支持动态执行

    • JS 提供eval() 函数,用于动态解释一段文本,并在当前上下文环境中执行。
  • 支持丰富的数据外部表示

    • 即使不使用JSON,也可以将一个变量序列化成字符串,包括为任何数据类型定制它的外部表示方法。

语言按语法分类:

  • 非形式语言

中文、英文

  • 形式语言(乔姆斯基谱系)

    • 0型 无限制文法
    • 1型 上下文相关文法
    • 2型上下文无关文法
    • 3型正则文法

产生式(BNF)

  • 用尖括号括起来的名称来表示语法结构名

  • 语法结构分成基础结构和需要用其他语法结构定义的复合结构

    • 基础结构称终结符
    • 复合结构称非终结符
  • 引号和中间的字符表示终结符

  • 可以用括号

    • 表示重复多次
  • |表示或

    • 表示至少一次
 <Number> = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
 <DecimalNumber> = "0" | (("1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9") <Number>*)
 <Expression> = <DecimalNumber> | <Expression> "+" <DecimalNumber>
 ​
 <PrimaryExpression> = <DecimalNumber> | "(" <LogicalExpression> ")"
 ​
 <MultiplicativeExpression> = <PrimaryExpression> | <MultiplicativeExpression> "*" <PrimaryExpression> | <MultiplicativeExpression> "/" <PrimaryExpression>
 ​
 <AdditiveExpression> = <MultiplicativeExpression> | <AdditiveExpression> "*" <MultiplicativeExpression> | <AdditiveExpression> "/" <MultiplicativeExpression>
 ​
 <LogicalExpression> = <AdditiveExpression> | <LogicalExpression> "*" <AdditiveExpression> | <LogicalExpression> "/" <AdditiveExpression>

通过产生式理解乔姆斯基谱系

现代语言的特性

  • C++ 中,* 可能表示乘号或指针,具体是哪个,取决于星号前面的标识符是否被声明为类型(非形式语言)
  • VB 中,< 可能是小于号,也可能是XML 直接量的开始,取决于当前位置是否可以接收XML 直接量(1型文法)
  • Python 中,行首的tab 符和空格会根据上一行的行首空白以一定规则被处理成虚拟终结符indent 或者decent(非形式语言)
  • JavaScript 中,/ 可能是除号,也可能是正则 表达式开头,处理方式类似于VB,字符串模版中也需要特殊处理 },还有自动插入分号规则(2型文法)

形式语言——用途

  • 数据描述语言:JSON HTML XAML SQL CSS
  • 编程语言:C C++ C# Python Ruby Perl Lisp T-SQL Clojure Haskell JavaScript

形式语言——表达方式

  • 声明式语言:JSON HTML XAML SQL CSS Lisp Clojure Haskell
  • 命令型语言:C C++ Java C# Python Ruby Perl JavaScript

图灵完备性

  • 命令式——图灵机

    • goto
    • if和while
  • 声明式——lambda

    • 递归

动态与静态

  • 动态:

    • 在用户的设备/在线服务器上
    • 产品实际运行时
    • Runtime
  • 静态:

    • 在程序员的设备上
    • 产品开发时
    • Compile time

类型系统

  • 动态类型系统与静态类型系统

  • 强类型与弱类型

    • String + Number
    • String == Boolean

C++ 是弱类型,有隐式转换

  • 复合类型

    • 结构体
     {
         a: T1
         b: T2
     }
    
    • 函数签名
     (T1, T2) ⇒ T3
    
  • 子类型

    • 逆变/协变

一般命令式编程语言

Atom: Identifier Literal

Expression: Atom Operator Punctuator

Statement: Expression Keyword Punctuator

Structure: Function Class Process Namspace ...

Program: Program Module Package Library

fileformat.info/info/unicod…

 <script>
     for (let i = 0; i < 128; i++) {
         document.write(i + "<span style='background-color: lightgreen'>" + String.fromCharCode(i) + "</span><br/>")
     }
 ​
 let \u5389\u5bb3 = 1
 console.log(厉害)
 ​
 </script>

【参考资料】

《JavaScript 语言精髓与编程实践》第3版 章节2、章节4( 4.1-4.3)