javascript 语言特性
核心特点
- 解释型
- 弱类型
- 脚本语言
- 单线程
- 异步与事件循环
- 事件驱动和非阻塞I/O
- 面向对象(基于原型)
- 函数是一等公民
解释型
解释型语言:你可以理解为现炒菜,写好代码->直接运行。(解释器边解释边执行)
优点
- 无需显示编译,即时执行
- 跨平台(语言本身不具备跨平台的特性,依赖解释器/虚拟机实现)
- 灵活性与动态性(可以快速迭代)
- 调试方便(不需要重新编译)
缺点
- 执行速度相对于编译执行要慢一点(但是绝大多数浏览器的瓶颈不在解释执行,而是在网络上)
- 源代码通常需要分发/暴漏(通常是代码混淆、压缩增加阅读难度)
编译型
编译型语言:你可以理解为预制菜。写好代码 -> 编译 -> 运行可执行文件
特点:
- 编译器需要全部编译成平台相关的机器码
- 运行速度快
- 依赖平台
- 迭代更新周期长(适合长期稳定)
- 编译时可处理完成大多数错误
- 不会暴露源码
弱类型(动态类型)
javascript选择弱类型(动态类型)的原因,主要时考虑到解释型特性,快速迭代需求,以及降低门槛的设计哲学紧密相关。
优点
- 降低学习门槛(和取名javascript类似,便于快速推广)
- 支持快速原型开发(不浪费时间在类型声明和转化上,和HTML语言一脉相承,统一协调)
- 适应web的动态特性(用户输入和数据格式可能随时发生变化,需要灵活应对)
- 避免中断的机制(try-catch,避免类型错误导致整个崩溃)
缺点
- 类型错误出现运行时
- 调试困难(难以追踪,需要断点调试)
- 性能开销更大
- 重构困难,没有运行根本不知道合适何地类型被更换
TypeScript
随着javascript的普及应用。弱类型已经不是那么被需要,而且因为隐式的类型转化造成维护成本的攀升。但是由于历史原因(不能因为版本更新,就对以前的项目进行全盘否定),浏览器支持的底层运行时仍然保持弱类型。
脚本语言
“脚本语言”并非一个严格的技术标准,而是一个基于设计目的和使用方式的归类。其核心特征是:
- 控制与粘合:脚本语言通常不是用来“创造”一个全新的独立系统,而是用来控制、协调或“粘合” 其他已经存在的、更复杂的组件或应用程序。
- 解释执行:通常是解释型语言,无需独立的编译步骤,由宿主环境的解释器直接读取源代码并执行。
- 高层抽象:提供了高级、简洁的语法,专注于要完成的任务逻辑,而非底层细节(如内存管理)。
- 快速开发与迭代:语法灵活(常为动态类型),编写简单,修改后能立刻看到结果,非常适合自动化、快速原型和交互式任务。
javascript 设计之初就是为了作为浏览器的控制脚本使用。
- 他的执行依赖浏览器提供的环境:渲染引擎、网络请求、DOM和BOM。
- 执行模式:解释执行
- 核心特点:动态类型以及高层抽象(不会设计内存管理以及线程管理等底层功能)
- 适合快速迭代。
单线程
原因:
- 单线程模型大大降低了入门门槛。
- 多线程会造成:竞态条件、死锁、线程同步、复杂的调试
- 避免DOM操作冲突(出口只有用户界面)
- 允许多线程同时操作DOM,会出现数据不一致、渲染错乱等问题
但是单线程主要面对的挑战:线程阻塞
解决方案:事件循环+异步回调
现代浏览器:也支持了提供了web Workers多线程的解决方案,但是由于出口只有用户界面,所以多线程方案不支持DOM操作
异步回调与事件循环
异步回调
异步回调是JavaScript处理非阻塞操作的核心机制。
JavaScript是单线程的,意味着只有一个执行栈,不能因为同步任务的执行等待过程,而阻塞线程。
web的等待本质:(通常阻塞javascript线程的不是语言的执行。而是等待其他线程任务的结果)
- 网络请求
- 用户输入
- 定时任务
- 文件读写
回调函数就是一个被作为参数传递,并在特定条件满足时被调用的函数。
当其他线程任务完成后,通过事件循环机制将回调函数的任务加入到队列中,等待执行栈调用执行。
事件循环(任务排队机制)
事件循环是JavaScript的异步任务调度器,它在执行栈清空后,首先清空所有微任务队列,然后从宏任务队列中取出一个任务执行,如此循环;若所有队列为空,则进入休眠等待新任务到来。
事件驱动和非阻塞I/O
事件驱动是一种编程范式,程序的执行流程由事件(如用户操作、系统消息、网络请求完成等)的发生来驱动,而不是按照预定的顺序执行。
- 基于回调函数:事件发生时调用预先注册的回调函数
- 异步处理:不阻塞主线程,继续执行后续代码
- 事件循环机制:JavaScript 引擎使用事件循环处理事件队列
非阻塞I/O 指的是在进行输入/输出操作时,不会阻塞程序执行线程,而是立即返回,让程序可以继续执行其他任务。
- 高并发性能:单线程可以处理大量并发连接
- 资源高效:不需要为每个连接创建新线程
- 响应性好:主线程不会被阻塞,保持响应性
- 适合I/O密集型应用:如Web服务器、API服务
主要问题
- CPU密集型任务:会阻塞事件循环
- 回调地狱:多层嵌套的回调难以维护
- 错误处理复杂:异步错误传播困难
面向对象(基于原型)
我们通常说JavaScript是基于原型的面向对象语言,这与基于类的语言(如Java、C++)不同。在JavaScript中,对象可以直接继承其他对象,而不需要类的概念。
但是,ES6引入了类的语法,但这只是语法糖,底层仍然是基于原型的继承。
主要特性:
- 原型链:每个对象都有一个原型对象,对象从原型对象继承属性和方法。
- 构造函数:用于创建对象的函数,通常与new操作符一起使用。
- 实例:通过构造函数创建的对象称为实例,实例共享构造函数的原型对象上的属性和方法。
函数是一等公民
在编程语言中,一等公民(First-class Citizen) 指的是该语言中的实体(如变量、函数等)具有以下能力:
- 可以被赋值给变量
- 可以作为参数传递给函数
- 可以作为函数的返回值
- 可以存储在数据结构中
- 具有自己的身份标识(名称)
函数编程的基石
- 高阶函数
- 柯里化(Currying)
- 函数组合(Function Composition)
JavaScript 中"函数是一等公民"这一特性意味着:
- 函数拥有最高的灵活性:可以像任何其他值一样被传递和使用
- 支持高阶函数:函数可以作为参数和返回值,实现强大的抽象能力
- 实现函数式编程范式:支持纯函数、不可变性、函数组合等概念
- 创建闭包:函数可以捕获和记住其创建时的上下文
- 实现各种设计模式:如工厂模式、策略模式、装饰器模式等
这一特性是 JavaScript 强大表现力的核心,使得它能够:
- 轻松处理异步操作(回调、Promise、async/await)
- 实现简洁的事件驱动编程
- 创建灵活的可复用代码模块
- 支持现代前端框架(React、Vue、Angular)的函数式组件和 hooks