搜尋
首頁web前端js教程詳解JS常見的BUG與錯誤處理

詳解JS常見的BUG與錯誤處理

May 31, 2018 am 10:33 AM
javascript處理錯誤

這次帶給大家詳解JS常見的BUG和錯誤處理,詳JS常見BUG和錯誤處理的注意事項有哪些,以下就是實戰案例,一起來看一下。

電腦程式中的缺陷通常稱為 bug。它讓程式設計師覺得很好,將它們想像成小事,只是碰巧進入我們的作品。實際上,當然,我們自己把它們放在了那裡。

如果一個程式是思想的結晶,你可以粗略地將錯誤分為因為思想混亂所造成的錯誤,以及思想轉換為程式碼時引入的錯誤。前者通常比後者更難診斷和修復。

語言

電腦能夠自動向我們指出許多錯誤,如果它足夠了解我們正在嘗試做什麼。但這裡 JavaScript 的寬鬆是個障礙。它的綁定和屬性概念很模糊,在實際運行程式之前很少會發現拼字錯誤。即使這樣,它也允許你做一些不會報錯的無意義的事情,例如計算true *'monkey'。

JavaScript 有一些報錯的事情。編寫不符合語言語法的程式會立即使電腦報錯。其他的東西,例如呼叫不是函數的東西,或在未定義的值上尋找屬性,會導致程式嘗試執行操作時報告錯誤。

不過,JavaScript 在處理無意義的計算時,會只回傳NaN(表示不是數字)或undefined這樣的結果。程式會認為其執行的程式碼毫無問題且順利運行下去,要等到隨後的運行過程中才會出現問題,而此時已經有許多函數使用了這個無意義的值。程式執行中也可能不會遇到任何錯誤,只會產生錯誤的程式輸出。找出這類錯誤的源頭是非常困難的。

我們將查找程式中的錯誤或 bug 的過程稱為偵錯(debug)。

嚴格模式

當啟用了嚴格模式(strict mode)後,JavaScript 就會在執行程式碼時變得更嚴格。我們只需在檔案或函數體頂部放置字串"use strict"就可以啟用嚴格模式了。下面是範例程式碼:

function canYouSpotTheProblem() {
 "use strict";
 for (counter = 0; counter <p style="text-align: left;">通常,當你忘記在綁定前面放置let時,就像在範例中的counter一樣,JavaScript 靜靜地建立一個全域綁定並使用它。在嚴格模式下,它會報告錯誤。這非常有幫助。但是,應該指出的是,當綁定已經作為全域綁定存在時,這是行不通的。在這種情況下,循環仍然會悄悄地覆蓋綁定的值。 </p><p style="text-align: left;">嚴格模式中的另一個變化是,在未被作為方法而呼叫的函數中,this綁定持有值undefined。當在嚴格模式之外進行這樣的呼叫時,this引用全域作用域對象,該物件的屬性是全域綁定。因此,如果你在嚴格模式下不小心錯誤地呼叫方法或建構器,JavaScript 會在嘗試從this讀取某些內容時產生錯誤,而不是愉快地寫入全域作用域。 </p><p style="text-align: left;">例如,考慮下面的程式碼,程式碼不帶new關鍵字呼叫建構器,以便其this不會引用新建構的物件:</p><pre class="brush:php;toolbar:false">function Person(name) { this.name = name; }
let ferdinand = Person("Ferdinand"); // oops
console.log(name);
// → Ferdinand

雖然我們錯誤地呼叫了Person,程式碼也可以執行成功,但會傳回一個未定義值,並建立名為name的全域綁定。而在嚴格模式中,結果就不同了。

"use strict";
function Person(name) { this.name = name; }
let ferdinand = Person("Ferdinand");
// → TypeError: Cannot set property 'name' of undefined

JavaScript 會立即告知我們程式碼中包含錯誤。這種特性十分有用。

幸運的是,使用class符號建立的建構器,如果在不使用new來調用,則始終會報錯,即使在非嚴格模式下也不會產生問題。

嚴格模式做了更多的事情。它不允許使用同一名稱為函數賦能多個參數,並且完全刪除某些有問題的語言特性(例如with語句,這是錯誤的,本書不會進一步討論)。

簡而言之,在程式頂部放置"use strict"很少會有問題,並且可能會幫助你發現問題。

類型

有些語言甚至在執行程式之前想要知道,所有綁定和表達式的類型。當類型以不一致的方式使用時,他們會馬上告訴你。 JavaScript 只在實際執行程式時考慮類型,即使經常嘗試將值隱式轉換為它預期的類型,所以它沒有多大幫助。

尽管如此,类型为讨论程序提供了一个有用的框架。 许多错误来自于值的类型的困惑,它们进入或来自一个函数。 如果你把这些信息写下来,你不太可能会感到困惑。

你可以在上一章的goalOrientedRobot函数上面,添加一个像这样的注释来描述它的类型。

// (WorldState, Array) → {direction: string, memory: Array}
function goalOrientedRobot(state, memory) {
 // ...
}

有许多不同的约定,用于标注 JavaScript 程序的类型。

关于类型的一点是,他们需要引入自己的复杂性,以便能够描述足够有用的代码。 你认为从数组中返回一个随机元素的randomPick函数的类型是什么? 你需要引入一个绑定类型T,它可以代表任何类型,这样你就可以给予randomPick一个像([T])->T的类型(从T到T的数组的函数)。

当程序的类型已知时,计算机可以为你检查它们,在程序运行之前指出错误。 有几种 JavaScript 语言为语言添加类型并检查它们。 最流行的称为 TypeScript。 如果你有兴趣为你的程序添加更多的严谨性,我建议你尝试一下。

在本书中,我们将继续使用原始的,危险的,非类型化的 JavaScript 代码。

测试

如果语言不会帮助我们发现错误,我们将不得不努力找到它们:通过运行程序并查看它是否正确执行。

一次又一次地手动操作,是一个非常糟糕的主意。 这不仅令人讨厌,而且也往往是无效的,因为每次改变时都需要花费太多时间来详尽地测试所有内容。

计算机擅长重复性任务,测试是理想的重复性任务。 自动化测试是编写测试另一个程序的程序的过程。 编写测试比手工测试有更多的工作,但是一旦你完成了它,你就会获得一种超能力:它只需要几秒钟就可以验证,你的程序在你编写为其测试的所有情况下都能正常运行。 当你破坏某些东西时,你会立即注意到,而不是在稍后的时间里随机地碰到它。

测试通常采用小标签程序的形式来验证代码的某些方面。 例如,一组(标准的,可能已经由其他人测试过)toUpperCase方法的测试可能如下:

function test(label, body) {
 if (!body()) console.log(`Failed: ${label}`);
}
test("convert Latin text to uppercase", () => {
 return "hello".toUpperCase() == "HELLO";
});
test("convert Greek text to uppercase", () => {
 return "Χαίρετε".toUpperCase() == "ΧΑΊΡΕΤΕ";
});
test("don't convert case-less characters", () => {
 return "مرحبا".toUpperCase() == "مرحبا";
});

像这样写测试往往会产生很多重复,笨拙的代码。 幸运的是,有些软件通过提供适合于表达测试的语言(以函数和方法的形式),并在测试失败时输出丰富的信息来帮助你构建和运行测试集合(测试套件,test suite)。 这些通常被称为测试运行器(test runner)。

一些代码比其他代码更容易测试。 通常,代码与外部交互的对象越多,建立用于测试它的上下文就越困难。 上一章中显示的编程风格,使用自包含的持久值而不是更改对象,通常很容易测试。

调试

当程序的运行结果不符合预期或在运行过程中产生错误时,你就会注意到程序出现问题了,下一步就是要推断问题出在什么地方。

有时错误很明显。错误消息会指出错误出现在程序的哪一行,只要稍加阅读错误描述及出错的那行代码,你一般就知道如何修正错误了。

但不总是这样。 有时触发问题的行,只是第一个地方,它以无效方式使用其他地方产生的奇怪的值。 如果你在前几章中已经解决了练习,你可能已经遇到过这种情况。

下面的示例代码尝试将一个整数转换成给定进制表示的字符串(十进制、二进制等),其原理是:不断循环取出最后一位数字,并将其除以基数(将最后一位数从数字中除去)。但该程序目前的输出表明程序中是存在bug的。

function numberToString(n, base = 10) {
 let result = "", sign = "";
 if (n  0);
 return sign + result;
}
console.log(numberToString(13, 10));
// → 1.5e-3231.3e-3221.3e-3211.3e-3201.3e-3191.3e-3181.3…

你可能已经发现程序运行结果不对了,不过先暂时装作不知道。我们知道程序运行出了问题,试图找出其原因。

这是一个地方,你必须抵制随机更改代码来查看它是否变得更好的冲动。 相反,要思考。 分析正在发生的事情,并提出为什么可能发生的理论。 然后,再做一些观察来检验这个理论 - 或者,如果你还没有理论,可以进一步观察来帮助你想出一个理论。

有目的地在程序中使用console.log来查看程序当前的运行状态,是一种不错的获取额外信息的方法。在本例中,我们希望n的值依次变为 13,1,然后是 0。让我们先在循环起始处输出n的值。

13
1.3
0.13
0.013
…
1.5e-323

没错。13 除以 10 并不会产生整数。我们不应该使用n/=base,而应该使用n=Math.floor(n/base),使数字“右移”,这才是我们实际想要的结果。

使用console.log来查看程序行为的替代方法,是使用浏览器的调试器(debugger)功能。 浏览器可以在代码的特定行上设置断点(breakpoint)。 当程序执行到带有断点的行时,它会暂停,并且你可以检查该点的绑定值。 我不会详细讨论,因为调试器在不同浏览器上有所不同,但请查看浏览器的开发人员工具或在 Web 上搜索来获取更多信息。

设置断点的另一种方法,是在程序中包含一个debugger语句(仅由该关键字组成)。 如果你的浏览器的开发人员工具是激活的,则只要程序达到这个语句,程序就会暂停。

错误传播

不幸的是,程序员不可能避免所有问题。 如果你的程序以任何方式与外部世界进行通信,则可能会导致输入格式错误,工作负荷过重或网络故障。

如果你只为自己编程,那么你就可以忽略这些问题直到它们发生。 但是如果你创建了一些将被其他人使用的东西,你通常希望程序比只是崩溃做得更好。 有时候,正确的做法是不择手段地继续运行。 在其他情况下,最好向用户报告出了什么问题然后放弃。 但无论在哪种情况下,该程序都必须积极采取措施来回应问题。

假设你有一个函数promptInteger,要求用户输入一个整数并返回它。 如果用户输入"orange",它应该返回什么?

一种办法是返回一个特殊值,通常会使用null,undefined或 -1。

function promptNumber(question) {
 let result = Number(prompt(question, ""));
 if (Number.isNaN(result)) return null;
 else return result;
}
console.log(promptNumber("How many trees do you see?"));

现在,调用promptNumber的任何代码都必须检查是否实际读取了数字,否则必须以某种方式恢复 - 也许再次询问或填充默认值。 或者它可能会再次向它的调用者返回一个特殊值,表示它未能完成所要求的操作。

在很多情况下,当错误很常见并且调用者应该明确地考虑它们时,返回特殊值是表示错误的好方法。 但它确实有其不利之处。 首先,如果函数已经可能返回每一种可能的值呢? 在这样的函数中,你必须做一些事情,比如将结果包装在一个对象中,以便能够区分成功与失败。

function lastElement(array) {
 if (array.length == 0) {
 return {failed: true};
 } else {
 return {element: array[array.length - 1]};
 }
}

返回特殊值的第二个问题是它可能产生非常笨拙的代码。 如果一段代码调用promptNumber 10 次,则必须检查是否返回null 10 次。 如果它对null的回应是简单地返回null本身,函数的调用者将不得不去检查它,以此类推。

异常

当函数无法正常工作时,我们只希望停止当前任务,并立即跳转到负责处理问题的位置。这就是异常处理的功能。

异常是一种当代码执行中遇到问题时,可以触发(或抛出)异常的机制,异常只是一个普通的值。触发异常类似于从函数中强制返回:异常不只跳出到当前函数中,还会跳出函数调用方,直到当前执行流初次调用函数的位置。这种方式被称为“堆栈展开(Unwinding the Stack)”。你可能还记得我们在第3章中介绍的函数调用栈,异常会减小堆栈的尺寸,并丢弃所有在缩减程序栈尺寸过程中遇到的函数调用上下文。

如果异常总是会将堆栈尺寸缩减到栈底,那么异常也就毫无用处了。它只不过是换了一种方式来彻底破坏你的程序罢了。异常真正强大的地方在于你可以在堆栈上设置一个“障碍物”,当异常缩减堆栈到达这个位置时会被捕获。一旦发现异常,你可以使用它来解决问题,然后继续运行该程序。

function promptDirection(question) {
 let result = prompt(question, "");
 if (result.toLowerCase() == "left") return "L";
 if (result.toLowerCase() == "right") return "R";
 throw new Error("Invalid direction: " + result);
}
function look() {
 if (promptDirection("Which way?") == "L") {
 return "a house";
 } else {
 return "two angry bears";
 }
}
try {
 console.log("You see", look());
} catch (error) {
 console.log("Something went wrong: " + error);
}

throw关键字用于引发异常。 异常的捕获通过将一段代码包装在一个try块中,后跟关键字catch来完成。 当try块中的代码引发异常时,将求值catch块,并将括号中的名称绑定到异常值。 在catch块结束之后,或者try块结束并且没有问题时,程序在整个try / catch语句的下面继续执行。

在本例中,我们使用Error构造器来创建异常值。这是一个标准的 JavaScript 构造器,用于创建一个对象,包含message属性。在多数 JavaScript 环境中,构造器实例也会收集异常创建时的调用栈信息,即堆栈跟踪信息(Stack Trace)。该信息存储在stack属性中,对于调用问题有很大的帮助,我们可以从堆栈跟踪信息中得知问题发生的精确位置,即问题具体出现在哪个函数中,以及执行失败为止调用的其他函数链。

需要注意的是现在look函数可以完全忽略promptDirection出错的可能性。这就是使用异常的优势:只有在错误触发且必须处理的位置才需要错误处理代码。其间的函数可以忽略异常处理。

嗯,我们要讲解的理论知识差不多就这些了。

异常后清理

异常的效果是另一种控制流。 每个可能导致异常的操作(几乎每个函数调用和属性访问)都可能导致控制流突然离开你的代码。

这意味着当代码有几个副作用时,即使它的“常规”控制流看起来像它们总是会发生,但异常可能会阻止其中一些发生。

这是一些非常糟糕的银行代码。

const accounts = {
 a: 100,
 b: 0,
 c: 20
};
function getAccount() {
 let accountName = prompt("Enter an account name");
 if (!accounts.hasOwnProperty(accountName)) {
 throw new Error(`No such account: ${accountName}`);
 }
 return accountName;
}
function transfer(from, amount) {
 if (accounts[from] <p style="text-align: left;">transfer函数将一笔钱从一个给定的账户转移到另一个账户,在此过程中询问另一个账户的名称。 如果给定一个无效的帐户名称,getAccount将引发异常。</p><p style="text-align: left;">但是transfer首先从帐户中删除资金,之后调用getAccount,之后将其添加到另一个帐户。 如果它在那个时候由异常中断,它就会让钱消失。</p><p style="text-align: left;">这段代码本来可以更智能一些,例如在开始转移资金之前调用getAccount。 但这样的问题往往以更微妙的方式出现。 即使是那些看起来不像是会<a href="http://www.php.cn/php/php-tp-throw.html" target="_blank">抛出异常</a>的函数,在特殊情况下,或者当他们包含程序员的错误时,也可能会这样。</p><p style="text-align: left;">解决这个问题的一个方法是使用更少的副作用。 同样,计算新值而不是改变现有数据的编程风格有所帮助。 如果一段代码在创建新值时停止运行,没有人会看到这个完成一半的值,并且没有问题。</p><p style="text-align: left;">但这并不总是实际的。 所以try语句具有另一个特性。 他们可能会跟着一个finally块,而不是catch块,也不是在它后面。 finally块会说“不管发生什么事,在尝试运行try块中的代码后,一定会运行这个代码。”</p><pre class="brush:php;toolbar:false">function transfer(from, amount) {
 if (accounts[from] <p style="text-align: left;">这个版本的函数跟踪其进度,如果它在离开时注意到,它中止在创建不一致的程序状态的位置,则修复它造成的损害。</p><p style="text-align: left;">请注意,即使finally代码在异常退出try块时运行,它也不会影响异常。finally块运行后,堆栈继续展开。</p><p style="text-align: left;">即使异常出现在意外的地方,编写可靠运行的程序也非常困难。 很多人根本就不关心,而且由于异常通常针对异常情况而保留,因此问题可能很少发生,甚至从未被发现。 这是一件好事还是一件糟糕的事情,取决于软件执行失败时会造成多大的损害。</p><p style="text-align: left;"><strong>选择性捕获</strong></p><p style="text-align: left;">当程序出现异常且异常未被捕获时,异常就会直接回退到栈顶,并由 JavaScript 环境来处理。其处理方式会根据环境的不同而不同。在浏览器中,错误描述通常会写入 JavaScript 控制台中(可以使用浏览器工具或开发者菜单来<a href="http://www.php.cn/wiki/178.html" target="_blank">访问控制</a>台)。我们将在第 20 章中讨论的,无浏览器的 JavaScript 环境 Node.js 对数据损坏更加谨慎。 当发生未处理的异常时,它会中止整个过程。</p><p style="text-align: left;">对于程序员的错误,让错误通行通常是最好的。 未处理的异常是表示糟糕的程序的合理方式,而在现代浏览器上,JavaScript 控制台为你提供了一些信息,有关在发生问题时堆栈上调用了哪些函数的。</p><p style="text-align: left;">对于在日常使用中发生的预期问题,因未处理的异常而崩溃是一种糟糕的策略。</p><p style="text-align: left;">语言的非法使用方式,比如引用一个不存在的绑定,在null中查询属性,或调用的对象不是函数最终都会引发异常。你可以像自己的异常一样捕获这些异常。</p><p style="text-align: left;">进入catch语句块时,我们只知道try体中引发了异常,但不知道引发了哪一类或哪一个异常。</p><p style="text-align: left;">JavaScript(很明显的疏漏)并未对选择性捕获异常提供良好的支持,要不捕获所有异常,要不什么都不捕获。这让你很容易假设,你得到的异常就是你在写catch时所考虑的异常。</p><p style="text-align: left;">但它也可能不是。 可能会违反其他假设,或者你可能引入了导致异常的 bug。 这是一个例子,它尝试持续调用promptDirection,直到它得到一个有效的答案:</p><pre class="brush:php;toolbar:false">for (;;) {
 try {
 let dir = promtDirection("Where?"); // ← typo!
 console.log("You chose ", dir);
 break;
 } catch (e) {
 console.log("Not a valid direction. Try again.");
 }
}

我们可以使用for (;;)循环体来创建一个无限循环,其自身永远不会停止运行。我们在用户给出有效的方向之后会跳出循环。但我们拼写错了promptDirection,因此会引发一个“未定义值”错误。由于catch块完全忽略了异常值,假定其知道问题所在,错将绑定错误信息当成错误输入。这样不仅会引发无限循环,而且会掩盖掉真正的错误消息——绑定名拼写错误。

一般而言,只有将抛出的异常重定位到其他地方进行处理时,我们才会捕获所有异常。比如说通过网络传输通知其他系统当前应用程序的崩溃信息。即便如此,我们也要注意编写的代码是否会将错误信息掩盖起来。

因此,我们转而会去捕获那些特殊类型的异常。我们可以在catch代码块中判断捕获到的异常是否就是我们期望处理的异常,如果不是则将其重新抛出。那么我们该如何辨别抛出异常的类型呢?

我们可以将它的message属性与我们所期望的错误信息进行比较。 但是,这是一种不稳定的编写代码的方式 - 我们将使用供人类使用的信息来做出程序化决策。 只要有人更改(或翻译)该消息,代码就会停止工作。

我们不如定义一个新的错误类型,并使用instanceof来识别异常。

class InputError extends Error {}
function promptDirection(question) {
 let result = prompt(question);
 if (result.toLowerCase() == "left") return "L";
 if (result.toLowerCase() == "right") return "R";
 throw new InputError("Invalid direction: " + result);
}

新的错误类扩展了Error。 它没有定义它自己的构造器,这意味着它继承了Error构造器,它需要一个字符串消息作为参数。 事实上,它根本没有定义任何东西 - 这个类是空的。 InputError对象的行为与Error对象相似,只是它们的类不同,我们可以通过类来识别它们。

现在循环可以更仔细地捕捉它们。

for (;;) {
 try {
 let dir = promptDirection("Where?");
 console.log("You chose ", dir);
 break;
 } catch (e) {
 if (e instanceof InputError) {
  console.log("Not a valid direction. Try again.");
 } else {
  throw e;
 }
 }
}

这里的catch代码只会捕获InputError类型的异常,而其他类型的异常则不会在这里进行处理。如果又输入了不正确的值,那么系统会向用户准确报告错误——“绑定未定义”。

断言

断言(assertions)是程序内部的检查,用于验证某个东西是它应该是的方式。 它们并不是用于处理正常操作中可能出现的情况,而是发现程序员的错误。

例如,如果firstElement被描述为一个函数,永远不会在空数组上调用,我们可以这样写:

function firstElement(array) {
 if (array.length == 0) {
 throw new Error("firstElement called with []");
 }
 return array[0];
}

现在,它不会默默地返回未定义值(当你读取一个不存在的数组属性的时候),而是在你滥用它时立即干掉你的程序。 这使得这种错误不太可能被忽视,并且当它们发生时更容易找到它们的原因。

我不建议尝试为每种可能的不良输入编写断言。 这将是很多工作,并会产生非常杂乱的代码。 你会希望为很容易犯(或者你发现自己做过)的错误保留他们。

本章小结

错误和无效的输入十分常见。编程的一个重要部分是发现,诊断和修复错误。 如果你拥有自动化测试套件或向程序添加断言,则问题会变得更容易被注意。

我们常常需要使用优雅的方式来处理程序可控范围外的问题。如果问题可以就地解决,那么返回一个特殊的值来跟踪错误就是一个不错的解决方案。或者,异常也可能是可行的。

抛出异常会引发堆栈展开,直到遇到下一个封闭的try/catch块,或堆栈底部为止。catch块捕获异常后,会将异常值赋予catch块,catch块中应该验证异常是否是实际希望处理的异常,然后进行处理。为了有助于解决由于异常引起的不可预测的执行流,可以使用finally块来确保执行try块之后的代码。

习题

重试

假设有一个函数primitiveMultiply,在 20% 的情况下将两个数相乘,在另外 80% 的情况下会触发MultiplicatorUnitFailure类型的异常。编写一个函数,调用这个容易出错的函数,不断尝试直到调用成功并返回结果为止。

确保只处理你期望的异常。

class MultiplicatorUnitFailure extends Error {}
function primitiveMultiply(a, b) {
 if (Math.random() <p style="text-align: left;"><strong>上锁的箱子</strong></p><p style="text-align: left;">考虑以下这个编写好的对象:</p><pre class="brush:php;toolbar:false">const box = {
 locked: true,
 unlock() { this.locked = false; },
 lock() { this.locked = true; },
 _content: [],
 get content() {
 if (this.locked) throw new Error("Locked!");
 return this._content;
 }
};

这是一个带锁的箱子。其中有一个数组,但只有在箱子被解锁时,才可以访问数组。不允许直接访问_content属性。

编写一个名为withBoxUnlocked的函数,接受一个函数类型的参数,其作用是解锁箱子,执行该函数,无论是正常返回还是抛出异常,在withBoxUnlocked函数返回前都必须锁上箱子。

const box = {
 locked: true,
 unlock() { this.locked = false; },
 lock() { this.locked = true; },
 _content: [],
 get content() {
 if (this.locked) throw new Error("Locked!");
 return this._content;
 }
};
function withBoxUnlocked(body) {
 // Your code here.
}
withBoxUnlocked(function() {
 box.content.push("gold piece");
});
try {
 withBoxUnlocked(function() {
 throw new Error("Pirates on the horizon! Abort!");
 });
} catch (e) {
 console.log("Error raised:", e);
}
console.log(box.locked);
// → true

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样使用Vue实现树形视图数据

JS对DOM树实现遍历有哪些方法

以上是詳解JS常見的BUG與錯誤處理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在行動中:現實世界中的示例和項目JavaScript在行動中:現實世界中的示例和項目Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

記事本++7.3.1

記事本++7.3.1

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

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境