首頁 web前端 js教程 使用Acorn來解析JavaScript

使用Acorn來解析JavaScript

Nov 15, 2016 am 09:56 AM
javascript

大部分情況使用正規表示式匹配就可以處理,但是一旦依賴程式碼上下文的內容時,正規或者簡單的字元解析就很力不從心了,這個時候需要一個語言解析器來獲取整一個AST(abstract syntax tree )。

然後我找到了多個使用JavaScript 編寫的JavaScript 解析器:

Esprima

Acorn

UglifyJS 2

Shift

從提交特性上都跟得上,我分別都簡單了解了一下,聊聊他們的一些狀況。

Esprima 是很經典的一個解析器,Acorn 在它之後誕生,都是幾年前的事情了。根據 Acorn 作者的說法,當時造這個輪子比較多只是好玩,速度可以和 Esprima 媲美,但是實現程式碼更少。其中比較關鍵的點是這兩個解析器出來的AST 結果(對,只是AST,tokens 不一樣)都是符合The Estree Spec 規範(這是Mozilla 的工程師給出的SpiderMonkey 引擎輸出的JavaScript AST 的規範文檔,也可以參考:SpiderMonkey in MDN)的,也就是得到的結果在很大部分上是相容的。

現在很有名的 Webpack 解析程式碼時用的也是 Acorn。

至於 Uglify,很出名的一個 JavaScript 程式碼壓縮器,其實它自帶了一個程式碼解析器,也可以輸出 AST,但是它的功能更多還是用於壓縮程式碼,如果拿來解析程式碼感覺不夠純粹。

Shift 這個沒做多少了解,只知道他定義了自己的一套 AST 規範。

Esprima 官網上有一個使用Acorn來解析JavaScript,我在chrome 上跑的結果如下:

可見,Acorn 的性能很不錯,而且還有一個Estree 的規範呢(規範很重要,我個人覺得遵循通用的規範是代碼復用的重要基礎),所以我就直接選用Acorn 來做程式碼解析了。 ,如何使用Acorn 來解析JavaScript。重要的講下:

ecmaVersion

字面意義,很好理解,就是設定你要解析的JavaScript 的ECMA 版本。 預設是ES7。是script。所以,選擇了script 則出現import/export 會報錯,可以使用嚴格模式聲明,選擇了module,則不用嚴格模式聲明,可以使用import/export 語法。會在AST 的節點中攜帶多一個loc 物件來表示目前的開始和結束的行數和列數。當年註釋內容,參數列表是:[block, text, start, end]。需要Esprima 的attachComment 的配置項,設定為true 後,Esprima 會在程式碼解析結果的節點中攜帶註解相關資訊(trailingComments 和leadingComments)。 Espree 則是利用 Acorn 的 onComment 配置來實現這個 Esprima 特性的相容。

解析器通常還會有一個取得詞法分析結果的介面:

const ast = acorn.parse(code, options)
登入後複製

tokenizer 方法的第二個參數也能夠設定 locations。

詞法結果token 和Esprima 的結果資料結構上有一定的區別(Espree 又是做了這一層的相容),有興趣了解的可以看下Esprima 的解析結果:http://esprima.org/demo /parse... 。

至於 Acorn 解析的 AST 和 token 的內容我們接下來詳述。

Token

我找了半天,沒找到關於 token 資料結構的詳細介紹,只能自己動手來看一下了。

我用來測試解析的程式碼是:

const tokens = [...acorn.tokenizer(code, options)]
登入後複製

解析出來的token 數組是一個個類似這樣的對象:

import "hello.js" 
 
var a = 2; 
 
// test 
function name() { console.log(arguments); }
登入後複製

看上去其實很好理解對不對,在type 對應的對像中,label 表示當前標識的一個類型,keyword 就是關鍵字,像是例子中的import,或是function 之類的。

value 則是目前標識的值,start/end 分別是開始和結束的位置。

通常我們需要關注的就是 label/keyword/value 這些了。其他的詳細可以參考原始碼:tokentype.js。

The Estree Spec

这一部分是重头戏,因为实际上我需要的还是解析出来的 AST。最原滋原味的内容来自于:The Estree Spec,我只是阅读了之后的搬运工。

提供了标准文档的好处是,很多东西有迹可循,这里还有一个工具,用于把满足 Estree 标准的 AST 转换为 ESMAScript 代码:escodegen。

好吧,回到正题,我们先来看一下 ES5 的部分,可以在 Esprima: Parser 这个页面测试各种代码的解析结果。

符合这个规范的解析出来的 AST 节点用 Node 对象来标识,Node 对象应该符合这样的接口:

interface Node { 
    type: string; 
    loc: SourceLocation | null; 
}
登入後複製

type 字段表示不同的节点类型,下边会再讲一下各个类型的情况,分别对应了 JavaScript 中的什么语法。

loc 字段表示源码的位置信息,如果没有相关信息的话为 null,否则是一个对象,包含了开始和结束的位置。接口如下:

interface SourceLocation { 
    source: string | null; 
    start: Position; 
    end: Position; 
}
登入後複製

这里的 Position 对象包含了行和列的信息,行从 1 开始,列从 0 开始:

interface Position { 
    line: number; // >= 1 
    column: number; // >= 0 
}
登入後複製

好了,基础部分就是这样,接下来看各种类型的节点,顺带温习一下 JavaScript 语法的一些东西吧。对于这里每一部分的内容,会简单谈一下,但不会展开(内容不少),对 JavaScript 了解的人很容易就明白的。

我觉得看完就像把 JavaScript 的基础语法整理了一遍。

Identifier

标识符,我觉得应该是这么叫的,就是我们写 JS 时自定义的名称,如变量名,函数名,属性名,都归为标识符。相应的接口是这样的:

interface Identifier <: Expression, Pattern { 
    type: "Identifier"; 
    name: string; 
}
登入後複製

一个标识符可能是一个表达式,或者是解构的模式(ES6 中的解构语法)。我们等会会看到 Expression 和 Pattern 相关的内容的。

Literal

字面量,这里不是指 [] 或者 {} 这些,而是本身语义就代表了一个值的字面量,如 1,“hello”, true 这些,还有正则表达式(有一个扩展的 Node 来表示正则表达式),如 /d?/。我们看一下文档的定义:

interface Literal <: Expression { 
    type: "Literal"; 
    value: string | boolean | null | number | RegExp; 
}
登入後複製

value 这里即对应了字面量的值,我们可以看出字面量值的类型,字符串,布尔,数值,null 和正则。

RegExpLiteral

这个针对正则字面量的,为了更好地来解析正则表达式的内容,添加多一个 regex 字段,里边会包括正则本身,以及正则的flags。

interface RegExpLiteral <: Literal { 
  regex: { 
    pattern: string; 
    flags: string; 
  }; 
}
登入後複製

Programs

一般这个是作为跟节点的,即代表了一棵完整的程序代码树。

interface Program <: Node { 
    type: "Program"; 
    body: [ Statement ]; 
}
登入後複製

body 属性是一个数组,包含了多个 Statement(即语句)节点。

Functions

函数声明或者函数表达式节点。

interface Function <: Node { 
    id: Identifier | null; 
    params: [ Pattern ]; 
    body: BlockStatement; 
}
登入後複製

id 是函数名,params 属性是一个数组,表示函数的参数。body 是一个块语句。

有一个值得留意的点是,你在测试过程中,是不会找到 type: "Function" 的节点的,但是你可以找到 type: "FunctionDeclaration" 和 type: "FunctionExpression",因为函数要么以声明语句出现,要么以函数表达式出现,都是节点类型的组合类型,后边会再提及 FunctionDeclaration 和 FunctionExpression 的相关内容。

这让人感觉这个文档规划得蛮细致的,函数名,参数和函数块是属于函数部分的内容,而声明或者表达式则有它自己需要的东西。

Statement

语句节点没什么特别的,它只是一个节点,一种区分,但是语句有很多种,下边会详述。

interface Statement <: Node { }
登入後複製

ExpressionStatement

表达式语句节点,a = a + 1 或者 a++ 里边会有一个 expression 属性指向一个表达式节点对象(后边会提及表达式)。

interface ExpressionStatement <: Statement { 
    type: "ExpressionStatement"; 
    expression: Expression; 
}
登入後複製

BlockStatement

块语句节点,举个例子:if (...) { // 这里是块语句的内容 },块里边可以包含多个其他的语句,所以有一个 body 属性,是一个数组,表示了块里边的多个语句。

interface BlockStatement <: Statement { 
    type: "BlockStatement"; 
    body: [ Statement ]; 
}
登入後複製

EmptyStatement

一个空的语句节点,没有执行任何有用的代码,例如一个单独的分号 ;

interface EmptyStatement  <: Statement { 
    type: "EmptyStatement "; 
}
登入後複製

DebuggerStatement

debugger,就是表示这个,没有其他了。

interface DebuggerStatement <: Statement { 
    type: "DebuggerStatement"; 
}
登入後複製

WithStatement

with 语句节点,里边有两个特别的属性,object 表示 with 要使用的那个对象(可以是一个表达式),body 则是对应 with 后边要执行的语句,一般会是一个块语句。

interface WithStatement <: Statement { 
    type: "WithStatement"; 
    object: Expression; 
    body: Statement; 
}
登入後複製

下边是控制流的语句:

ReturnStatement

返回语句节点,argument 属性是一个表达式,代表返回的内容。

interface ReturnStatement <: Statement { 
    type: "ReturnStatement"; 
    argument: Expression | null; 
}
登入後複製

LabeledStatement

label 语句,平时可能会比较少接触到,举个例子:

loop: for(let i = 0; i < len; i++) { 
    // ... 
    for (let j = 0; j < min; j++) { 
        // ... 
        break loop; 
    } 
}
登入後複製

这里的 loop 就是一个 label 了,我们可以在循环嵌套中使用 break loop 来指定跳出哪个循环。所以这里的 label 语句指的就是loop: ... 这个。

一个 label 语句节点会有两个属性,一个 label 属性表示 label 的名称,另外一个 body 属性指向对应的语句,通常是一个循环语句或者 switch 语句。

interface LabeledStatement <: Statement { 
    type: "LabeledStatement"; 
    label: Identifier; 
    body: Statement; 
}
登入後複製

BreakStatement

break 语句节点,会有一个 label 属性表示需要的 label 名称,当不需要 label 的时候(通常都不需要),便是 null。

interface BreakStatement <: Statement { 
    type: "BreakStatement"; 
    label: Identifier | null; 
}
登入後複製

ContinueStatement

continue 语句节点,和 break 类似。

interface ContinueStatement <: Statement { 
    type: "ContinueStatement"; 
    label: Identifier | null; 
}
登入後複製

下边是条件语句:

IfStatement

if 语句节点,很常见,会带有三个属性,test 属性表示 if (...) 括号中的表达式。

consequent 属性是表示条件为 true 时的执行语句,通常会是一个块语句。

alternate 属性则是用来表示 else 后跟随的语句节点,通常也会是块语句,但也可以又是一个 if 语句节点,即类似这样的结构:

if (a) { //... } else if (b) { // ... }。

alternate 当然也可以为 null。

interface IfStatement <: Statement { 
    type: "IfStatement"; 
    test: Expression; 
    consequent: Statement; 
    alternate: Statement | null; 
}
登入後複製

SwitchStatement

switch 语句节点,有两个属性,discriminant 属性表示 switch 语句后紧随的表达式,通常会是一个变量,cases 属性是一个case 节点的数组,用来表示各个 case 语句。

interface SwitchStatement <: Statement { 
    type: "SwitchStatement"; 
    discriminant: Expression; 
    cases: [ SwitchCase ]; 
}
登入後複製

SwitchCase

switch 的 case 节点。test 属性代表这个 case 的判断表达式,consequent 则是这个 case 的执行语句。

当 test 属性是 null 时,则是表示 default 这个 case 节点。

interface SwitchCase <: Node { 
    type: "SwitchCase"; 
    test: Expression | null; 
    consequent: [ Statement ]; 
}
登入後複製

下边是异常相关的语句:

ThrowStatement

throw 语句节点,argument 属性用以表示 throw 后边紧跟的表达式。

interface ThrowStatement <: Statement { 
    type: "ThrowStatement"; 
    argument: Expression; 
}
登入後複製

TryStatement

try 语句节点,block 属性表示 try 的执行语句,通常是一个块语句。

hanlder 属性是指 catch 节点,finalizer 是指 finally 语句节点,当 hanlder 为 null 时,finalizer 必须是一个块语句节点。

interface TryStatement <: Statement { 
    type: "TryStatement"; 
    block: BlockStatement; 
    handler: CatchClause | null; 
    finalizer: BlockStatement | null; 
}
登入後複製

CatchClause

catch 节点,param 用以表示 catch 后的参数,body 则表示 catch 后的执行语句,通常是一个块语句。

interface CatchClause <: Node { 
    type: "CatchClause"; 
    param: Pattern; 
    body: BlockStatement; 
}
登入後複製

下边是循环语句:

WhileStatement

while 语句节点,test 表示括号中的表达式,body 是表示要循环执行的语句。

interface WhileStatement <: Statement { 
    type: "WhileStatement"; 
    test: Expression; 
    body: Statement; 
}
登入後複製

DoWhileStatement

do/while 语句节点,和 while 语句类似。

interface DoWhileStatement <: Statement { 
    type: "DoWhileStatement"; 
    body: Statement; 
    test: Expression; 
}
登入後複製

ForStatement

for 循环语句节点,属性 init/test/update 分别表示了 for 语句括号中的三个表达式,初始化值,循环判断条件,每次循环执行的变量更新语句(init 可以是变量声明或者表达式)。这三个属性都可以为 null,即 for(;;){}。

body 属性用以表示要循环执行的语句。

interface ForStatement <: Statement { 
    type: "ForStatement"; 
    init: VariableDeclaration | Expression | null; 
    test: Expression | null; 
    update: Expression | null; 
    body: Statement; 
}
登入後複製

ForInStatement

for/in 语句节点,left 和 right 属性分别表示在 in 关键词左右的语句(左侧可以是一个变量声明或者表达式)。body 依旧是表示要循环执行的语句。

interface ForInStatement <: Statement { 
    type: "ForInStatement"; 
    left: VariableDeclaration |  Pattern; 
    right: Expression; 
    body: Statement; 
}
登入後複製

Declarations

声明语句节点,同样也是语句,只是一个类型的细化。下边会介绍各种声明语句类型。

interface Declaration <: Statement { }
登入後複製

FunctionDeclaration

函数声明,和之前提到的 Function 不同的是,id 不能为 null。

interface FunctionDeclaration <: Function, Declaration { 
    type: "FunctionDeclaration"; 
    id: Identifier; 
}
登入後複製

VariableDeclaration

变量声明,kind 属性表示是什么类型的声明,因为 ES6 引入了 const/let。

declarations 表示声明的多个描述,因为我们可以这样:let a = 1, b = 2;。

interface VariableDeclaration <: Declaration { 
    type: "VariableDeclaration"; 
    declarations: [ VariableDeclarator ]; 
    kind: "var"; 
}
登入後複製

VariableDeclarator

变量声明的描述,id 表示变量名称节点,init 表示初始值的表达式,可以为 null。

interface VariableDeclarator <: Node { 
    type: "VariableDeclarator"; 
    id: Pattern; 
    init: Expression | null; 
}
登入後複製

Expressions

表达式节点。

interface Expression <: Node { }
登入後複製

ThisExpression

表示 this。

interface ThisExpression <: Expression { 
    type: "ThisExpression"; 
}
登入後複製

ArrayExpression

数组表达式节点,elements 属性是一个数组,表示数组的多个元素,每一个元素都是一个表达式节点。

interface ArrayExpression <: Expression { 
    type: "ArrayExpression"; 
    elements: [ Expression | null ]; 
}
登入後複製

ObjectExpression

对象表达式节点,property 属性是一个数组,表示对象的每一个键值对,每一个元素都是一个属性节点。

interface ObjectExpression <: Expression { 
    type: "ObjectExpression"; 
    properties: [ Property ]; 
}
登入後複製

Property

对象表达式中的属性节点。key 表示键,value 表示值,由于 ES5 语法中有 get/set 的存在,所以有一个 kind 属性,用来表示是普通的初始化,或者是 get/set。

interface Property <: Node { 
    type: "Property"; 
    key: Literal | Identifier; 
    value: Expression; 
    kind: "init" | "get" | "set"; 
}
登入後複製

FunctionExpression

函数表达式节点。

interface FunctionExpression <: Function, Expression { 
    type: "FunctionExpression"; 
}
登入後複製

下边是一元运算符相关的表达式部分:

UnaryExpression

一元运算表达式节点(++/-- 是 update 运算符,不在这个范畴内),operator 表示运算符,prefix 表示是否为前缀运算符。argument 是要执行运算的表达式。

interface UnaryExpression <: Expression { 
    type: "UnaryExpression"; 
    operator: UnaryOperator; 
    prefix: boolean; 
    argument: Expression; 
}
登入後複製

UnaryOperator

一元运算符,枚举类型,所有值如下:

enum UnaryOperator { 
    "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" 
}
登入後複製

UpdateExpression

update 运算表达式节点,即 ++/--,和一元运算符类似,只是 operator 指向的节点对象类型不同,这里是 update 运算符。

interface UpdateExpression <: Expression { 
    type: "UpdateExpression"; 
    operator: UpdateOperator; 
    argument: Expression; 
    prefix: boolean; 
}
登入後複製

UpdateOperator

update 运算符,值为 ++ 或 --,配合 update 表达式节点的 prefix 属性来表示前后。

enum UpdateOperator { 
  "++" | "--" 
}
登入後複製

下边是二元运算符相关的表达式部分:

BinaryExpression

二元运算表达式节点,left 和 right 表示运算符左右的两个表达式,operator 表示一个二元运算符。

interface BinaryExpression <: Expression { 
    type: "BinaryExpression"; 
    operator: BinaryOperator; 
    left: Expression; 
    right: Expression; 
}
登入後複製

BinaryOperator

二元运算符,所有值如下:

enum BinaryOperator { 
    "==" | "!=" | "===" | "!==" 
         | "<" | "<=" | ">" | ">=" 
         | "<<" | ">>" | ">>>" 
         | "+" | "-" | "*" | "/" | "%" 
         | "|" | "^" | "&" | "in" 
         | "instanceof" 
}
登入後複製

AssignmentExpression

赋值表达式节点,operator 属性表示一个赋值运算符,left 和 right 是赋值运算符左右的表达式。

interface AssignmentExpression <: Expression { 
    type: "AssignmentExpression"; 
    operator: AssignmentOperator; 
    left: Pattern | Expression; 
    right: Expression; 
}
登入後複製

AssignmentOperator

赋值运算符,所有值如下:(常用的并不多)

enum AssignmentOperator { 
    "=" | "+=" | "-=" | "*=" | "/=" | "%=" 
        | "<<=" | ">>=" | ">>>=" 
        | "|=" | "^=" | "&=" 
}
登入後複製

LogicalExpression

逻辑运算表达式节点,和赋值或者二元运算类型,只不过 operator 是逻辑运算符类型。

interface LogicalExpression <: Expression { 
    type: "LogicalExpression"; 
    operator: LogicalOperator; 
    left: Expression; 
    right: Expression; 
}
登入後複製

LogicalOperator

逻辑运算符,两种值,即与或。

enum LogicalOperator { 
    "||" | "&&" 
}
登入後複製

MemberExpression

成员表达式节点,即表示引用对象成员的语句,object 是引用对象的表达式节点,property 是表示属性名称,computed 如果为false,是表示 . 来引用成员,property 应该为一个 Identifier 节点,如果 computed 属性为 true,则是 [] 来进行引用,即property 是一个 Expression 节点,名称是表达式的结果值。

interface MemberExpression <: Expression, Pattern { 
    type: "MemberExpression"; 
    object: Expression; 
    property: Expression; 
    computed: boolean; 
}
登入後複製

下边是其他的一些表达式:

ConditionalExpression

条件表达式,通常我们称之为三元运算表达式,即 boolean ? true : false。属性参考条件语句。

interface ConditionalExpression <: Expression { 
    type: "ConditionalExpression"; 
    test: Expression; 
    alternate: Expression; 
    consequent: Expression; 
}
登入後複製

CallExpression

函数调用表达式,即表示了 func(1, 2) 这一类型的语句。callee 属性是一个表达式节点,表示函数,arguments 是一个数组,元素是表达式节点,表示函数参数列表。

interface CallExpression <: Expression { 
    type: "CallExpression"; 
    callee: Expression; 
    arguments: [ Expression ]; 
}
登入後複製

NewExpression

new 表达式

interface NewExpression <: CallExpression { 
    type: "NewExpression"; 
}
登入後複製

SequenceExpression

这个就是逗号运算符构建的表达式(不知道确切的名称),expressions 属性为一个数组,即表示构成整个表达式,被逗号分割的多个表达式。

interface SequenceExpression <: Expression { 
    type: "SequenceExpression"; 
    expressions: [ Expression ]; 
}
登入後複製

Patterns

模式,主要在 ES6 的解构赋值中有意义,在 ES5 中,可以理解为和 Identifier 差不多的东西。

interface Pattern <: Node { }
登入後複製

这一部分的内容比较多,但都可以举一反三,写这个的时候我就当把 JavaScript 语法再复习一遍。这个文档还有 ES2015,ES2016,ES2017 相关的内容,涉及的东西也蛮多,但是理解了上边的这一些,然后从语法层面去思考这个文档,其他的内容也就很好理解了,这里略去,有需要请参阅:The Estree Spec。

Plugins

回到我们的主角,Acorn,提供了一种扩展的方式来编写相关的插件:Acorn Plugins。

我们可以使用插件来扩展解析器,来解析更多的一些语法,如 .jsx 语法,有兴趣的看看这个插件:acorn-jsx。

官方表示 Acorn 的插件是用于方便扩展解析器,但是需要对 Acorn 内部的运行极致比较了解,扩展的方式会在原本的基础上重新定义一些方法。这里不展开讲了,如果我需要插件的话,会再写文章聊聊这个东西。

Examples

现在我们来看一下如何应用这个解析器,例如我们需要用来解析出一个符合 CommonJS 规范的模块依赖了哪些模块,我们可以用 Acorn 来解析 require 这个函数的调用,然后取出调用时的传入参数,便可以获取依赖的模块。

下边是示例代码:

// 遍历所有节点的函数 
function walkNode(node, callback) { 
  callback(node) 
 
  // 有 type 字段的我们认为是一个节点 
  Object.keys(node).forEach((key) => { 
    const item = node[key] 
    if (Array.isArray(item)) { 
      item.forEach((sub) => { 
        sub.type && walkNode(sub, callback) 
      }) 
    } 
 
    item && item.type && walkNode(item, callback) 
  }) 
} 
 
function parseDependencies(str) { 
  const ast = acorn.parse(str, { ranges: true }) 
  const resource = [] // 依赖列表 
 
  // 从根节点开始 
  walkNode(ast, (node) => { 
    const callee = node.callee 
    const args = node.arguments 
 
    // require 我们认为是一个函数调用,并且函数名为 require,参数只有一个,且必须是字面量 
    if ( 
      node.type === &#39;CallExpression&#39; && 
      callee.type === &#39;Identifier&#39; && 
      callee.name === &#39;require&#39; && 
      args.length === 1 && 
      args[0].type === &#39;Literal&#39; 
    ) { 
      const args = node.arguments 
 
      // 获取依赖的相关信息 
      resource.push({ 
        string: str.substring(node.range[0], node.range[1]), 
        path: args[0].value, 
        start: node.range[0], 
        end: node.range[1] 
      }) 
    } 
  }) 
 
  return resource 
}
登入後複製

这只是简单的一个情况的处理,但是已经给我们呈现了如何使用解析器,Webpack 则在这个的基础上做了更多的东西,包括 var r = require; r('a') 或者 require.async('a') 等的处理。

AST 这个东西对于前端来说,我们无时无刻不在享受着它带来的成果(模块构建,代码压缩,代码混淆),所以了解一下总归有好处。


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles