」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 現實世界中的自動類型轉換

現實世界中的自動類型轉換

發佈於2025-04-17
瀏覽:455

Automatic Type Conversion In The Real World

核心要点

  • JavaScript 的自动类型转换在不同情况下既是优势也是劣势。作为核心功能,它会在运算符或语句期望特定数据类型时将数据转换为预期类型。
  • 根据转换结果,JavaScript 值被称为“真值”或“假值”。共有六个假值:falseundefinednull0""(空字符串)和 NaN(非数字)。所有其他值都被视为真值。
  • 必须仔细考虑类型转换如何影响评估以避免陷阱。例如,在为可选参数定义默认值时,必须确保已知数据的真值性以防止失败。
  • 虽然使用 typeof 进行显式测试始终安全,但使用自动类型转换有利于文件大小的考虑,因为较小的文件加载速度更快且带宽使用更少。但是,理解编程语言如何处理类型转换对于避免意外结果至关重要。

JavaScript 中有一些表达式很常见,但一些编程纯粹主义者会告诉你它们从来都不是好主意。这些表达式的共同点是它们依赖于自动类型转换——JavaScript 的核心功能,根据情况和你的观点,它既是优势也是劣势。

因此,在本文中,我想特别关注这两个表达式,并考虑它们在哪些情况下是好主意,哪些情况下不是好主意。

第一个表达式是一个简单的 if() 条件:

if (foo) {
}

第二个表达式是一个带有可选值的变量赋值:

var x = foo || bar;

如果这两个例子中的 foobar 都是布尔值,那么表达式很简单:如果 foo 为真,则第一个条件通过;如果 foo 为真,则第二个表达式将 foo 赋值给 x,否则将 bar 赋值给 x

但是,如果它们不是简单的布尔值——如果 foo 是一个对象、一个字符串或 undefined 怎么办?如果 foobar 是不同的数据类型怎么办?要理解这些表达式将如何计算,我们需要了解 JavaScript 如何在数据类型之间自动转换。

自动类型转换

JavaScript 是一种“松散类型”语言,这意味着每当运算符或语句期望特定数据类型时,JavaScript 都会自动将数据转换为该类型。第一个例子中的 if() 语句期望一个布尔值,因此括号中定义的任何内容都将转换为布尔值。while()do...while() 语句也是如此。

根据此类转换的结果(即真或假),JavaScript 值通常被称为“真值”或“假值”。最简单的理解方法是这样的:除非已知值为假值,否则该值为真值;实际上,只有 六个 假值:

  • false(当然!)
  • undefined
  • null
  • 0(数字零)
  • ""(空字符串)
  • NaN(非数字)

值得注意的例外是“0”(字符串零)和所有类型的对象——它们是真值——这包括 所有 原生构造函数,这意味着 new Boolean(false) 计算结果为真!(有点令人困惑,但在实践中你永远不需要那样创建原生值。)

注意:比较两个假值并不总是会产生你可能期望的结果,例如(null != false),即使两者都是假值。有一些相当复杂的算法决定了相等性评估的工作方式,讨论它们超出了本文的范围。但如果你对细节感兴趣,可以查看 ECMAScript 5.1 中的抽象相等比较算法。

条件快捷方式

我在开头向你展示的 if() 示例将其表达式转换为布尔值,由于对象总是计算为真而 null 计算为假,因此我们可以使用这样的条件来测试 DOM 元素的存在:

var element = document.getElementById("whatever");
if (element) {
  // 元素存在
} else {
  // 元素不存在
}

在处理 DOM 元素时,这始终可靠地工作,因为 DOM 规范要求不存在的元素返回 null

但是,其他情况并非如此明确,例如这个例子:

function doStuff(foo) {
  if (foo) {
    ...
  }
}

这样的条件经常用于表示 “如果 foo 参数已定义”,但是有几种情况会导致失败——即 foo 是假值的情况。因此,例如,如果它是布尔值 false 或空字符串,则不会执行条件代码,即使 foo 定义。

我们想要的是这个:

function doStuff(foo) {
  if (typeof foo != "undefined") {
    ...
  }
}

未定义的参数(和其他变量)的数据类型为“undefined”。因此,我们可以使用 typeof 比较器来测试参数的数据类型,然后如果 foo 完全定义,则条件将始终通过。当然,if() 表达式仍在计算布尔值,但它计算的布尔值是该 typeof 表达式的 结果

赋值快捷方式

我在开头向你展示的第二个示例使用逻辑运算符来确定应将两个值中的哪个值赋给变量:

var x = foo || bar;

逻辑运算符不 返回 布尔值,但它们确实仍然 期望 布尔值,因此转换和计算会在内部发生。如果 foo 计算结果为真,则返回 foo,否则返回 bar 的值。这非常有用。

这个表达式通常在事件处理函数中看到,它用于根据支持的模型定义事件参数:

element.onclick = function(e) {
  e = e || window.event;
};

因此,e 计算为布尔值,如果支持事件参数模型,则该布尔值为真值(事件对象),否则为假值(undefined);如果它是真值,则返回 e,否则返回 window.event

同样类型的表达式也常用于分配事件属性,通过评估每个可能性来查找支持的属性:

var target = e.target || e.srcElement || window;

因此,这些引用中的每一个都依次(从左到右)进行评估,并且第一个计算结果为真的将被返回。第一种情况处理标准模型,第二种情况用于 Internet Explorer,而第三种情况用于 Internet Explorer,当事件可能在窗口对象(没有 srcElement 属性)上触发时。

但是,这种表达式同样容易失败,在不知道数据真值性的情况下。例如,另一个常见的用例是为可选参数定义默认值,但这不好:

function doStuff(foo) {
  foo = foo || "default value";
}

现在,如果你确定 foo 总是 是字符串或 undefined,并且假设空字符串应被视为 undefined,那么该表达式是安全的。但如果不是,则需要将其重新定义为更精确的内容,例如:

function doStuff(foo) {
  if (typeof foo != "string") {
    foo = "default value";
  }
}

通过针对“字符串”测试类型,我们可以处理多种情况——foo 未定义的情况,以及将其错误定义为非字符串值的情况。在这种情况下,我们还允许空字符串作为有效输入,但如果我们想排除空字符串,则必须添加第二个条件:

function doStuff(foo) {
  if (typeof foo != "string" || foo == "") {
    foo = "default value";
  }
}

还有其他一些令人惊讶的微妙情况可能会导致问题。例如,我们可能有一个日期函数,它创建 unix 时间戳,除非可选地定义输入时间戳:

function doDateStuff(timestamp) {
  timestamp = timestamp || new Date().getTime();
}

如果输入为 0,则会失败——因为零是假值,但它也是有效的时间戳。

一般原则

从所有这些中吸取的一般教训很简单——考虑类型转换将如何影响评估,并注意不要陷入我们遇到的陷阱。经过适当的注意和关注,你仍然可以利用自动类型转换,在适当的情况下缩短条件和逻辑表达式。

但这确实提出了一个问题——如果我们知道使用 typeof 进行显式测试始终安全,而依赖自动类型转换有时并不安全——那么为什么不 始终 明确呢?当然,如果偏好较短语法的原因仅仅是因为它键入速度更快,那么这是一个懒惰和草率的原因。

但事实是,JavaScript 通常通过公共网络运行,在这种情况下文件大小很重要。较小的文件加载速度更快,并且带宽使用更少,小的语法快捷方式确实可以累积。

利用较短的表达式本身并不是一种优化,它只是一种编程风格,它充分利用了语言特性。

(此处省略了原文中的常见问题解答部分,因为该部分内容与文章主题关联性较弱,并且篇幅较长,不适合在伪原创中保留。)

最新教學 更多>
  • 如何克服PHP的功能重新定義限制?
    如何克服PHP的功能重新定義限制?
    克服PHP的函數重新定義限制在PHP中,多次定義一個相同名稱的函數是一個no-no。嘗試這樣做,如提供的代碼段所示,將導致可怕的“不能重新列出”錯誤。 但是,PHP工具腰帶中有一個隱藏的寶石:runkit擴展。它使您能夠靈活地重新定義函數。 runkit_function_renction_...
    程式設計 發佈於2025-05-02
  • Python元類工作原理及類創建與定制
    Python元類工作原理及類創建與定制
    python中的metaclasses是什麼? Metaclasses負責在Python中創建類對象。就像類創建實例一樣,元類也創建類。他們提供了對類創建過程的控制層,允許自定義類行為和屬性。 在Python中理解類作為對象的概念,類是描述用於創建新實例或對象的藍圖的對象。這意味著類本身是使用...
    程式設計 發佈於2025-05-02
  • 找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    如何在mySQL中使用mySql 檢索最大計數,您可能會遇到一個問題,您可能會在嘗試使用以下命令:理解錯誤正確找到由名稱列分組的值的最大計數,請使用以下修改後的查詢: 計數(*)為c 來自EMP1 按名稱組 c desc訂購 限制1 查詢說明 select語句提取名稱列和每個名稱...
    程式設計 發佈於2025-05-02
  • 如何將MySQL數據庫添加到Visual Studio 2012中的數據源對話框中?
    如何將MySQL數據庫添加到Visual Studio 2012中的數據源對話框中?
    在Visual Studio 2012 儘管已安裝了MySQL Connector v.6.5.4,但無法將MySQL數據庫添加到實體框架的“ DataSource對話框”中。為了解決這一問題,至關重要的是要了解MySQL連接器v.6.5.5及以後的6.6.x版本將提供MySQL的官方Visual...
    程式設計 發佈於2025-05-02
  • 如何在Java字符串中有效替換多個子字符串?
    如何在Java字符串中有效替換多個子字符串?
    在java 中有效地替換多個substring,需要在需要替換一個字符串中的多個substring的情況下,很容易求助於重複應用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    程式設計 發佈於2025-05-02
  • 條件語句中的賦值操作
    條件語句中的賦值操作
    [2 在PHP 中很常见 看到这样写的代码: if($ summary = get_post_summary()) { 返回$摘要; } 我指的是条件中的作业。非常狡猾,它也可以在JavaScript中完成,尽管它不太常见: if(summary = document.getElem...
    程式設計 發佈於2025-05-02
  • 在Oracle SQL中如何提取下劃線前的子字符串?
    在Oracle SQL中如何提取下劃線前的子字符串?
    [ 在oracle sql 解決方案: Explanation:SUBSTR function extracts a substring starting from the specified position (0) and continuing for a specified length.IN...
    程式設計 發佈於2025-05-02
  • 如何解決由於Android的內容安全策略而拒絕加載腳本... \”錯誤?
    如何解決由於Android的內容安全策略而拒絕加載腳本... \”錯誤?
    Unveiling the Mystery: Content Security Policy Directive ErrorsEncountering the enigmatic error "Refused to load the script..." when deployi...
    程式設計 發佈於2025-05-02
  • 如何正確使用與PDO參數的查詢一樣?
    如何正確使用與PDO參數的查詢一樣?
    在pdo 中使用類似QUERIES在PDO中的Queries時,您可能會遇到類似疑問中描述的問題:此查詢也可能不會返回結果,即使$ var1和$ var2包含有效的搜索詞。錯誤在於不正確包含%符號。 通過將變量包含在$ params數組中的%符號中,您確保將%字符正確替換到查詢中。沒有此修改,PD...
    程式設計 發佈於2025-05-02
  • 如何從Python中的字符串中刪除表情符號:固定常見錯誤的初學者指南?
    如何從Python中的字符串中刪除表情符號:固定常見錯誤的初學者指南?
    從python import codecs import codecs import codecs 導入 text = codecs.decode('這狗\ u0001f602'.encode('utf-8'),'utf-8') 印刷(文字)#帶有...
    程式設計 發佈於2025-05-02
  • 如何高效地在一個事務中插入數據到多個MySQL表?
    如何高效地在一個事務中插入數據到多個MySQL表?
    mySQL插入到多個表中,該數據可能會產生意外的結果。雖然似乎有多個查詢可以解決問題,但將從用戶表的自動信息ID與配置文件表的手動用戶ID相關聯提出了挑戰。 使用Transactions和last_insert_id() 插入用戶(用戶名,密碼)值('test','tes...
    程式設計 發佈於2025-05-02
  • 如何將PANDAS DataFrame列轉換為DateTime格式並按日期過濾?
    如何將PANDAS DataFrame列轉換為DateTime格式並按日期過濾?
    Transform Pandas DataFrame Column to DateTime FormatScenario:Data within a Pandas DataFrame often exists in various formats, including strings.使用時間數據時...
    程式設計 發佈於2025-05-02
  • Go語言如何動態發現導出包類型?
    Go語言如何動態發現導出包類型?
    與反射軟件包中的有限類型的發現能力相反,本文探索了替代方法,探索了在Runruntime。 go import( “ FMT” “去/進口商” ) func main(){ pkg,err:= incorter.default()。導入(“ time”) 如果er...
    程式設計 發佈於2025-05-02
  • Go web應用何時關閉數據庫連接?
    Go web應用何時關閉數據庫連接?
    在GO Web Applications中管理數據庫連接很少,考慮以下簡化的web應用程序代碼:出現的問題:何時應在DB連接上調用Close()方法? ,該特定方案將自動關閉程序時,該程序將在EXITS EXITS EXITS出現時自動關閉。但是,其他考慮因素可能保證手動處理。 選項1:隱式關閉終...
    程式設計 發佈於2025-05-02
  • 為什麼不````''{margin:0; }`始終刪除CSS中的最高邊距?
    為什麼不````''{margin:0; }`始終刪除CSS中的最高邊距?
    在CSS 問題:不正確的代碼: 全球範圍將所有餘量重置為零,如提供的代碼所建議的,可能會導致意外的副作用。解決特定的保證金問題是更建議的。 例如,在提供的示例中,將以下代碼添加到CSS中,將解決餘量問題: body H1 { 保證金頂:-40px; } 此方法更精確,避免了由全局保證金重置...
    程式設計 發佈於2025-05-02

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3