コンピュータープログラムの操作には、3.14番やテキスト「Hello World」などの操作値が必要です。プログラミング言語では、表現および操作できる値のタイプはデータ型と呼ばれます。プログラミング言語の最も基本的な機能は、複数のデータ型をホストすることです。プログラムが将来の使用のために値を維持する必要がある場合、変数を(値を「保存」)に割り当てられます。変数は値の象徴的な名前であり、値への参照は名前で取得できます。変数の作業メカニズムは、プログラミング言語の基本的な特徴です。この章では、前のセクションを参照して、この章の内容を理解するのに役立ち、後で詳しく説明します。
JavaScriptデータは、プリミティブタイプとオブジェクトタイプの2つのカテゴリに分割されます
JavaScriptの元のクラスには、数字、文字列、ブール値が含まれます。この章には、JavaScriptの数字、文字列、およびブール値について特に議論する別の章があります。 JavaScriptには、2つの特別な生値、null(空)と未定義(未定義)(未定義)もあり、数字、文字列、またはブール値ではありません。それらは、それぞれの特別なタイプの唯一のメンバーを表しています。
JavaScriptは、数字、文字列、ブール値、null、および未定義以外のオブジェクトです。オブジェクトはプロパティのコレクションです。各属性は「名前/値ペア」で構成されています(値は、数字、文字列、またはオブジェクトなどの原始的な値になります)。より特別なオブジェクトの1つ(グローバルオブジェクトが5番目のミスで紹介され、6番目のセクションについて詳しく説明します)
通常のJavaScriptオブジェクトは、「名前付き値」の不要なコレクションです。 JavaScriptは、番号付き値の順序付けられたセットを表す特別なオブジェクト - アレイも定義します。 JavaScriptは、配列の専用構文を定義します。メイクアレイには、通常のオブジェクトとは異なるユニークな動作プロパティがあります。
JavaScriptは、特別なオブジェクト機能も定義します。関数は、関連付けたい実行可能コードを備えたオブジェクトです。関数を呼び出してコードを実行し、操作の結果を返します。配列と同様に、関数の動作特性は他のオブジェクトとは異なります。 JavaScriptは、関数を使用するための特別な構文を定義します。 JavaScript関数用。最も重要なことは、それらはすべて真の値であり、JavaScriptを使用してそれらを通常のオブジェクトとして扱うことができます。
関数が(新しい演算子を使用)初期化された場合、それをコンストラクターと呼びます。各コンストラクターは、コンストラクターの初期化オブジェクトで構成されるクラスオブジェクトAコレクションを定義します。クラスは、オブジェクトタイプのサブタイプと見なすことができます。 Arrayクラスと関数クラスに加えて、JavaScriptは使用される他の3つのクラスも定義します。日付は、日付を表すオブジェクトを定義します。 regexpは、正規表現のオブジェクトを定義します。エラークラスは、JavaScriptプログラムのランタイムエラーと構文エラーオブジェクトを表す行を定義します。独自のコンストラクターを定義することにより、必要なクラスを定義できます。
JavaScriptインタープリターには、メモリ管理メカニズムが独自のメモリ管理メカニズムを備えています。これは、自動的にメモリのコレクションをごみ収集できます。これは、プログラムがオンデマンドでオブジェクトを作成できることを意味し、プログラマーはこれらのオブジェクトの破壊とメモリリサイクルを心配する必要がないことを意味します。オブジェクトを指す基準がない場合、通訳者はオブジェクトが役に立たないことを知っており、占有するメモリリソースを自動的にリサイクルします。
JavaScriptはオブジェクト指向の言語です。厳密に言えば、これはグローバル定義関数を使用して異なるタイプの値を操作しないことを意味します。データ型自体は、値を使用する方法を定義できます。たとえば、配列aの要素をソートするには、sort()関数に渡す必要はありませんが、method()を転送する必要はありません。
a.sort(); //ソート(a)オブジェクト指向バージョン
技術的には、JavaScriptオブジェクトのみがメソッドを持つことができます。ただし、数字、文字列、ブール値にも独自の方法があります。 JavaScriptでは、nullと未定義のみがメソッドを持たない値です。
JavaScriptのタイプは、プリミティブタイプとオブジェクトタイプに分けることができ、メソッドを持たない方法とタイプを持つことができるタイプに分けることができます。また、可変で不変のタイプに分けることもできます。可変タイプの値は変更でき、オブジェクトと配列は可変タイプに属します。JavaScriptプログラムは、オブジェクトの属性値の値と配列要素の値を変更できます。
数字、ブール人、ヌル、未定義は不変のタイプです。たとえば、配列自体の内容を変更することは意味がありません。文字列は文字の配列と見なすことができ、変更できると考えることができます。ただし、JavaScriptでは、文字列は不変です。文字列の任意の位置でテキストにアクセスできますが、JavaScriptは常に文字列のテキストコンテンツを変更する方法を提供しません。
JavaScriptはデータ型変換を自由に実行できます。たとえば、プログラムが文字列の使用を期待する場所で数値を使用する場合、JavaScriptは数値を文字列に自動的に変換します。ブール値が使用されている非ブール値を使用すると予想される場合、JavaScriptもそれに応じて変換されます。 JavaScriptでは、「判断の平等」ルールは「判断の平等」(平等)に使用されます
javaScript変数は無タイプです。変数は、人とタイプに割り当てることができます。 VARキーワードを使用して変数を宣言できます。 JavaScriptは構文範囲を採用しています。関数で宣言されていない変数は、グローバル変数と呼ばれます。それらはJavaScriptのプログラムのどこにでも見えます。
1。番号
他のプログラミング言語とは異なり、JavaScriptは整数値とフローティングポイント値を区別しません。 JavaScriptのすべての値は、フローティングポイント値で表されます。 JavaScriptプログラムに数値が直接表示される場合、私たちは数値リテラルであり、JavaScriptは複数の形式で数値直接量をサポートします。 (注:任意の数値の直前にネガティブサイン( - )を追加すると、負の値が得られる可能性があります)が、否定的な兆候は一方向の逆演算子です。 、直接数値の文法のコンポーネントではありません。 ))
I整数型直接数
10進整数は、JavaScriptの配列シーケンスで表されます
小数整数直接量に加えて、JavaScriptは16のメカニズム(16)の値をカーディナリティとして認識します。いわゆる16進数システムは、「0x」または「0x」が付いた直接的な数量で、それに続いて一連の16進数が続きます。 16進数は、0〜9とa(a)-f(f)の間の文字で構成されています。 AFの文字は、以下の10〜15号で表されます。ここに、直接的な量の16進整数の例があります
コードコピーは次のとおりです。
0xff // 15*16+15 = 255
0xcafe911
ECMAScriptはOctalの直接的な量をサポートしていませんが、JavaScriptのいくつかの実装により、Octalの整数の表現が可能になります(ベース8)。 Octal直接数量は数0で始まり、その後に0〜7の間の一連の数値が続きます。
コードコピーは次のとおりです。
0377 // 3*64 +7*8 +7 = 255(小数)
一部のJavaScriptの実装はOctal Internumberをサポートしているため、一部はそうではありませんが、0でプレフィックスを付けない整数間型を使用しないことをお勧めします。 ECMAScript6の厳密なモードでは、直接のオクタル量が明示的に禁止されています。
ii。浮動小数点直接数量
フローティングポイント直接量には小数点を含めることができ、従来の実数執筆方法を使用します。実数は、整数部、小数点、小数部で構成されています。
さらに、流通ポイントの直接量を表すために、指数カウント方法も使用できます。つまり、実際の数の後に文字EまたはEが続き、その後は正と負の兆候が続き、その後、整数指数が追加されます。このカウント方法で表される数値は、前の実数に10を掛けた指数力です。
より簡潔な構文で表現できます
コードコピーは次のとおりです。
[数字] [。桁] [(e | e)[(+| - )]数字]
3.14
2345.455
.3333333333333333333333333333333333
6.02E23 //6.02*10から23番目の電力
1.255454E-23 //1.255454*10 23番目
iii.javascriptの算術操作
JavaScriptプログラムは、言語州が提供する算術演算子を使用して数値操作を実行します。これらの演算子には + - * /および残りの(分割された担保)オペレータ%が含まれています
基本的な演算子に加えて、JavaScriptはより複雑な算術操作もサポートしています。この複雑な操作は、数学オブジェクトのプロパティとして定義された関数と定数によって実装されます。
コードコピーは次のとおりです。
Math.Pow(2、53)// => 9007199254740992 document.write(math.pow(2,53))
Math.Round(.6)//=>1.0ラウンド
Math.Ceil(.6)//=>1.0上向き検索
Math.floor(.6)//=>0.0下向き
Math.Abs(-5)// => 5絶対値を見つけます
math.max(x、y、z)//最大値を返します
Math.min(x、y、z)//最小値を返します
Math.random()// 0より大きい擬似ランダム数を生成し、1未満
Math.pi // pi
Math.e // E:自然対数のベース
Math.sqrt(3)// 3平方根
Math.Pow(3、1 /3)// 3のキューブルート
Math.sin(0)// Trigonometric関数、およびMath.cos、Math.Atanなど。
Math.log(10)//=>2.302585092994046ベース10の自然対数
Math.log(512) /math.ln2 //ベース2の512のログ
Math.log(100) /math.ln10 //ベース10の100のログ
Math.exp(3)// 3のパワー
JavaScriptの算術操作は、オーバーフロー、アンダーフロー、またはゼロで割り切れるとエラーを報告しません。ただし、数値動作結果はJavaScript(オーバーフロー)で表すことができる数を超えており、結果はJavaScriptでinfintyとして表される特別な無限値(infinty)値です。同様に、負の数の値がJavaScriptが表現できる負の数値の範囲を超えると、結果は負の無限であり、これはJavaScriptでは無限であると表現されます。無限の値の行動特性は、私たちが期待するものと一致しています:追加、減算、乗算、およびそれらに基づく分割の結果は無限です(標識の保存)
アンダーフローは、計算結果がワイヤレスでゼロに近く、JavaScriptが表すことができる最小値よりも小さい場合に発生する状況です。負の数がアンダーフローすると、JavaScriptは特別な値「負のゼロ」を返します。これは(負のゼロ)は通常のゼロとほぼ同じです。 JavaScriptプログラマーは、ネガティブゼロを使用することはめったにありません。
JavaScriptは、非数値値を表現するために、グローバル変数を事前に定義しました。 EcMascipt3では、これら2つの値を読み書きできます。 ecmascript5は、それらを読み取り専用として定義することにより、この問題を修正しました。 ecmascipt3の番号オブジェクトによって定義された属性値も読み取り専用です。いくつかの例を次に示します。
コードコピーは次のとおりです。
Infinity //読み取り可能な/書き込み変数をInfinityに初期化します
number.positive_infinity //同じ値、読み取り専用
1/0 //これは同じ値です
number.max_value + 1 //計算結果はまだ無限です
number.negative_infinity //は、負の無限を示します
- インフィニティ
-1/0
-number.max_value -1
nan //読み取り可能な/書き込み変数をNANに初期化します
number.nan //同じ値ですが、読み取りのみです
0/0 //計算結果はまだnanです
number.min_value/2 //アンダーフローが発生しました。計算された結果は0です
-number.min_value/2 //ネガティブゼロ
-1/Infinity //負のゼロ
-0 //負のゼロ
JavaScriptには、非数学的な値については少し特別なものがありますが、それは人間や自分自身を含む価値に等しくありません。言い換えれば、xがx == nanによってxがnanであるかどうかを判断することは不可能です。代わりに、xを使用する必要があります! = x xがnanである場合にのみ判断するには、式の結果が真であることを判断します。関数ISNAN()関数はこれに似ています。パラメーターがNANまたは非数値値(文字列やオブジェクトなど)の場合、それはtrueを返します。 JavaScriptにはIsFinite()に同様の関数があります。これは、パラメーターがNAN、infinty、またはinfinityではない場合にtrueを返します。
負のゼロ値も少し特別です。これは、正と負のゼロ(JavaScriptの厳密な平等テストを使用して判断されても)に等しくなります。つまり、これらの2つの値は、除外を除いてほぼ同じです。
コードコピーは次のとおりです。
var zero = 0;
var negz = -0;
zero === negz // =>真の正と負のゼロ値は等しい
1/zero === 1/negz //偽陽性の無限と負の無限が異なる
iiii.binaryフローティングポイント番号と丸めエラー
無数の実数がありますが、JavaScriptは浮動小数点数の形式を介して有限数を表すことができます(正確には、18 437 736 874 454 454 454 810 627があります)、つまり、実際の数がJavaScriptで使用される場合、多くの場合、実際の値の近似表現です。
JavaScriptは、IEEE-754フローティングポイント番号表記(ほとんどすべての最新のプログラミング言語で使用)を採用しています。これは、1/2 1/8や1/1024などの分数を正確に表すことができるバイナリ表現です。残念ながら、特に財務計算でよく使用する分数はすべて、10進数、1/10、1/100などに基づいています。バイナリ表記は0.1のような単純な数を表すことはできません。
JavaScriptの数字には十分な精度があります。 0.1に近い場合があります。しかし、実際には、数字を正確に表現できないことは、いくつかの問題をもたらします。
コードコピーは次のとおりです。
var x = .3 -.2;
var y = .2 -.1;
アラート(x == y)// => false 2つの値は等しくありません
x == .1 // => false .3-.2は.1に等しくありません
y == .1 // => true .2-.1等しい1
丸めエラーのため、0.3と0.2の近似差は、実際には0.2と0.1の近似差に等しくありません(実際のシミュレーション環境では、0.3-0.2 = 0.099 999 999 999 999 999 99999 9999999999 99999999999999 999999999999999999この問題はJavaScriptに存在するだけでなく、これを理解することが非常に重要です。この問題は、バイナリフローティングポイント番号を使用するプログラミング言語で発生します。また、上記のコードのxとyの値は互いに非常に近く、最終的な正しい値があることに注意することも重要です。この計算結果は、ほとんどの計算タスクで有能です。この問題は、2つの値が等しいかどうかを比較する場合にのみ発生します。
JavaScriptの将来のバージョンは、この問題を回避するために小数数の数値タイプをサポートする場合があります。たとえば、通貨ユニットには小数要素の代わりに整数「セグメント」を使用します。
iiiii.dateおよび時間
JavaScript言語のコアには、日付と時刻のオブジェクトを最初に作成した日付()コンストラクターが含まれます。これらの日付オブジェクトの方法は、日付計算のための簡単なAPIを提供します。日付オブジェクトは、数字のような基本的なデータ型にすることはできません。
コードコピーは次のとおりです。
var zhen = new Date(2011、0、1); // 2011年1月1日
var later = new Date(2011、0、1、17、10、30); //同じ日
var now = new date(); //現在の日付と時刻
var Elapsed = now -zhen; //日付減算。時間間隔のミリ秒数を計算します
later.getSlyear(); // => 2011
later.getMonth(); // => 0から0からカウントされます
later.getDate(); // => 1 1からカウントされる日数
later.getDay(); // => 5曜日を取得します。 0は日曜日を表し、5は日曜日を表します
later.gethours()// =>現地時間
Later.getutChours()// UTCを使用して、タイムゾーンに基づいて時間の時間を表します。
2。テキスト
文字列は、16ビット値の不変で順序付けられたシーケンスであり、各文字は通常、Unicode文字セットからのものです。 JavaScriptは、文字列タイプを介してテキストを表します。文字列の長さは、含まれる16ビット値の数です。 JavaScript文字列(およびその配列)のインデックスは0から始まります。空の文字列の長さは0で、JavaScriptの単一の文字を表す「文字型」はありません。 16ビット値を表すには、文字列変数に割り当てるだけです。この文字列の長さは1です。
文字セット、内側コード、JavaScript文字列
JavaScriptは、UTF-16エンコードされたUnicode文字セットを使用し、JavaScript文字列は、順序付けられていない16ビット値のセットで構成されるシーケンスです。最も一般的に使用されるユニコード文字は、16ビットの内側コードで表され、文字列内の単一の文字を表します。 16ビットとして表現できないユニコード文字の後に、UTF-16エンコードルールが続きます - 2つの16ビット値を使用してシーケンス(「プロキシペア」とも呼ばれます)を形成します。これは、長さ2のJavaScript文字列(2つの16ビット値)がユニコード文字を表すことを意味します。
コードコピーは次のとおりです。
var p = "π"; //πは、16ビットの内側コード0x03C0で表されます
var e = "e"; // Eは、17ビットの内側コード0x1D452で表されます
p.length // => 1 pには16ビット値が含まれています
E.length // => 2 e utf-16によってエンコードされた2つの値には、 "/ud835/udc52" "
JavaScriptによって定義されたすべての文字列操作方法は、文字ではなく16ビット値に作用し、プロキシアイテムを個別に処理しません。同様に、JavaScriptは文字列処理を標準化しません。文字列が合法的なUTF-16形式であるという保証はありません
私は直接数量を文字列にします
JavaScriptプログラムの直接的な量の文字列は、単一の引用または二重引用符で囲まれた一連の文字です。単一の引用符で区切られた文字列には、二重引用符を含めることができ、二重引用符で区切られた文字列には単一の引用符も含まれます。文字列の直接的な定量化の例をいくつか紹介します。
コードコピーは次のとおりです。
"" //空の文字列、0文字
「テスト」
「3.14」
'name = "myform"'
「オリーリーの本を好まないの?」
ECMAScript3では、文字列の直接的な量を1行に記述する必要がありますが、ECMAScript5では、文字列の直接的な量はいくつかの行に分割でき、各行はバックスラッシュ(/)で終了する必要があります。バックスラッシュもラインエンディング文字も、文字列の直接的な量の内容ではありません。一緒にいたい場合は、 /nを使用してキャラクターを逃れることができます。
文字列を区切るために単一の引用符を使用する場合、英語の略語とすべての形式に特に注意する必要があることに注意する必要があります。英語のアポストロフィと単一の引用は同じ文字であるため、脱出するためにバックスラッシュ(/)を使用する必要があります。
IIエスケープキャラクター
JavaScript文字列では、バックスラッシュ(/)には特別な目的があります。バックスラッシュにキャラクターを追加すると、文字通りの意味を表しなくなります。たとえば、 /nは新しいラインを表すエスケープキャラクターです。
コードコピーは次のとおりです。
/o // nul文字
/b //バックスペース文字
/t //水平タブ文字
/n // newline文字を行
/v //垂直タブ文字
/f //ページの更新
/R //キャリッジリターン文字
/"//二重引用符
// backslash
/XXXラテン-1 2ビット16進数によって指定された文字
/xxxxxx 4ビット16進数xxxxxで指定されたユニコード文字
III文字列の使用
JavaScriptの組み込み機能の1つは、文字列連結です。文字列にオペレーター +を使用して、文字列の連結を表します。例えば
コードコピーは次のとおりです。
var msg = "hello" + "world"; //文字列Hello Worldを生成します
文字列の長さ(含まれる16ビット値の数を決定するには、文字列の長さなどの長さ属性を使用できます。
s.length
長さの属性に加えて、文字列は呼び出される多くの方法も提供します。
コードコピーは次のとおりです。
var s = "hello、world";
S.Charat(0); // "H"最初の文字
s.charat(s.length -1)// "d"最後の文字
S.Substring(1、4)// "Ell" 2-4文字
S.Slice(1、4)//上記と同じ
S.Slice(-3)//最後の3文字が表示されます
s.indexof(l ")// 2文字l最初の発生位置
s.lastindexof( "l")// 10最後に文字lが表示されます
s.indexof( "l"、3)//位置3の後、L文字が表示される最初の位置
s.split( "、")// => ["hello"、 "world"]はサブストリングに分けられます
s.Replace( "H"、 "H")// => "hllo、world"フルテキスト文字置き換え
S.touppercase()// =>「こんにちは、世界」
JavaScriptでは、文字列が固定されていないと変更されていません。交換()やTouppercase()などの方法は、新しい文字列を返しますが、元の文字自体は変更されていません。
ECMAScriptでは、文字は読み取り専用アレイとして扱うことができます。 charat()メソッドを使用することに加えて、四角いブラケットを使用して、文字列内の個々の文字にアクセスすることもできます。 (16ビット値)
コードコピーは次のとおりです。
S = "こんにちは、世界"
s [0] // => "h"
S [s.length-1] // => "d"
FoxFireは、この方法の昔の文字列インデックスをサポートしており、ほとんどの最新のブラウザ(IEを除く)はMozaillaの足跡をたどり、ECMAScriptが形成される前にこの機能を完了しました。
IIIIパターンマッチング
JavaScriptは、regexp()コンストラクターを定義します。これは、テキストパターンマッチングを表すオブジェクトを作成するために使用されます。これらのパターンは、JavaScript Perlの「正規表現」、正規表現構文と呼ばれます。文字列とRegexpの両方のオブジェクトは、正規表現を使用してパターンを一致させ、見つけて置き換える関数を定義します。
regexpオブジェクトは、言語の基本的なデータ型ではありません。日付と同様に、実用的なAPIを備えた特別なオブジェクトです。正規表現には、複雑な構文とリッチAPIがあります。第10章で詳しく紹介します。Regexpは強力で一般的に使用されるテキスト処理ツールであり、概要を概念しています。
Regexpは言語の基本的なデータ型ではありませんが、それらは依然として直接的な量を持ち、JavaScriptで直接使用できます。 2つのスラッシュの間のテキストは、正規表現の直接的な量を形成します。 2番目のスラッシュは、1つ以上の文字に続くこともあります。マッチングパターンの意味を変更するために使用されます。例えば:
コードコピーは次のとおりです。
/^html/// htmlで始まる文字列を一致させます
/[1-9] [0-9]*///ゼロ以外の数値を一致させ、その後に任意の数字が続きます
// bjavascript/b/i/// javascriptという単語に一致し、上限と小文字を無視します
regexpオブジェクトは多くの有用な方法を定義し、文字列にはregexpパラメーターを受け入れることができる方法もあります。例えば:
コードコピーは次のとおりです。
var text = "テスト:1,2,3"; //テキストの例
var pattern = // d+/g // 1つ以上の数字を含むすべてのインスタンスを一致させる
pattern.test(text)// => true:試合は成功します
text.search(pattern)// => 9:最初の一致が成功した位置
text.match(pattern)// => ["1"、 "2"、 "3"]すべての一致は配列を形成します
text.repeat(pattern、 "#"); // =>「テスト:#、#、#」
text.split(// d+/); // => ["" "、" 1 "、" 2 "、" 3 "]:文字列をインターセプトするために非数字の文字を使用します
3。ブール値
ブール値は、オンまたはオフのtrueまたはfalseを指します。このタイプには2つの値しかなく、trueまたはfalseという単語は予約されています。
JavaScriptの比較ステートメントの結果は、通常、ブール値です。例えば
a == 4
このコードは、変数のaの値が4に等しいかどうかを検出するために使用されます。等しい場合、値は等しくない場合、falseです。
ブール値は通常、JavaScriptの/elseステートメントなどのJavaScript制御ステートメントで使用されます。ブール値がtrueの場合、ロジックの最初の部分を実行し、別のコードが偽である場合、例えば
コードコピーは次のとおりです。
if(a == 4)
b = b + 1;
それ以外
a = a + 1;
JavaScript値はブール値に変換でき、次の値はfalseに変換されます
コードコピーは次のとおりです。
未定義
ヌル
0
-0
ナン
"" //空の文字列
すべてのオブジェクト(配列)を含む他のすべての値は、true、falseに変換され、falseに変換できる上記の6つの値は「false値」と呼ばれることもあります。 JavaScriptは、ブール値を使用する場合、偽の値は偽として扱われ、真の値が真であると扱われることを期待しています。
例を見てみましょう。変数Oを追加することはオブジェクトまたはnullです。IFステートメントを使用して、Oが非ヌル値であるかどうかを検出できます。
if(o!== null)...
不均等な演算子 "ここでは、まず比較ステートメントを無視できます。 nullは誤った値であり、オブジェクトは真の値です。
if(o)...
最初のケースでは、oがoがnullでない場合にのみ実行される後のコードと、2番目のケースの制限はそれほど厳格ではありません。これは、oがfalseまたはfalse値(nullまたはfuningなど)でない場合にのみ実行される場合。
BooleanにはtoString()メソッドが含まれているため、この方法を使用して文字列を「true」または「false」に変換できますが、他の有用なメソッドは含まれていません。この重要でないAPIに加えて、3つの重要なブール演算子があります。
&&オペレーター、||オペレーターとユニリーオペレーター「!」ブール以外の(非)操作を実行します。真の値がfalseを返した場合、たとえば、false値はtrueを返します
コードコピーは次のとおりです。
if((x == 0 && y == 0)||(z == 0)){
// xとyは両方ともゼロまたはzが非ゼロです
}
4.ヌルと未定義
Nullは、JavaScript言語のキーワードです。特別な値「null値」を表します。 nullの場合、typeof()操作を実行し、オブジェクトを返します。つまり、nullは「非オブジェクト」を意味する特別なオブジェクト値と見なすことができます。しかし、実際、Nullは通常、その無料タイプの唯一のメンバーであると考えられています。数字、文字列、およびオブジェクトを表すことができます。ほとんどのプログラミング言語には、JavaScriptのようなnullが含まれており、nullまたはnilに精通することができます。
JavaScriptには、値の空孔を示す2番目の値もあります。より深い「ヌル値」を表すために使用されます。変数の値です。変数が初期化されていないことを示します。オブジェクト属性または配列要素の値を照会する場合、属性または要素が存在しないことを意味します。未定義は、事前に定義されたグローバル変数(nullとは異なり、キーワードではありません)であり、その値は未定義です。 typeofを使用して未定義のタイプをテストする場合、「未定義」が返され、値が唯一のメンバーであることを示します。
Nullと未定義は異なりますが、どちらも「価値の空accance」を表し、2つはしばしば交換可能です。平等を判断するオペレーター「==」は、2つが等しいと考えています(厳密な平等演算子を使用してそれらを区別します)。値がブール型になると予想される場合、それらの値はすべて偽です。 falseに似ています。 NULLと未定義の両方に、プロパティとメソッドが含まれていません。実際、「。」を使用するこれらの2つの値のメンバーまたはメソッドにアクセスする「[]」は、タイプエラーを生成します。
未定義は、間違った値のシステムレベルで予期せず生きている空席を表しているのに対し、nullはプログラムレベル、通常、または予想される値の空席を表していると思うかもしれません。変数またはプロパティにコピーするか、パラメーターとして関数に渡す場合、nullが最良の選択です。
5。グローバルオブジェクト
前のセクションでは、JavaScriptの要素タイプと元の値について説明します。オブジェクトタイプ - オブジェクト、配列、関数 /しかし、明確にしてはならない非常に重要なクラスのオブジェクトがあります:グローバルオブジェクト
Global Objectには、JavaScriptで重要な用途があります。グローバルオブジェクトのプロパティは、グローバルに定義されているシンボルです。 JavaScriptプログラムは直接使用できます。 JavaScriptインタープリターが起動すると、新しいグローバルオブジェクトが作成され、定義された初期プロパティのセットが与えられます。
未定義のinfintyやnanなどのグローバルプロパティ
isnan()、parseint()、eval()などのグローバル機能
date()、regexp()、string()、object()、array()などのコンストラクター
MathやJsonなどのグローバルオブジェクト
グローバルオブジェクトの初期属性は予約済みの単語ではありませんが、予約された単語として扱う必要があります。
コードの上位レベルで - javaScriptコードは、任意の関数内ではなく、JavaScriptキーワードを介してグローバルオブジェクトを参照できます。
var global = this; //グローバルオブジェクトを参照するグローバル変数を定義します。
クライアントJavaScriptでは、ウィンドウオブジェクトはグローバルオブジェクトとして機能します。このグローバルウィンドウオブジェクトには、おなじみのウィンドウ参照自体があります。これを置き換えて、グローバルオブジェクトを参照できます。 Windowsはグローバルコア属性を定義します。ただし、他のいくつかのグローバル属性は、WebブラウザーとインタラクティブなJavaScriptに対して定義されています。
初めて作成されると、グローバルオブジェクトはJavaScriptのすべての事前定義されたグローバル値を定義し、この特別なオブジェクトにはプログラムに定義されたグローバル値も含まれています。コードがグローバル変数を宣言する場合。このグローバル変数は、グローバルオブジェクトの属性です。
6。パッケージングオブジェクト
JavaScriptオブジェクトは複合値です。これは、属性または名前付き値のコレクションです。属性値は「」を介して参照されます。属性値が関数である場合、それはメソッドであり、OM()を使用してオブジェクトoでメソッドを転送します。
文字列にはプロパティと方法もあることがわかります。
コードコピーは次のとおりです。
var s = "hello world";
var word = S.Substring(S.Indexof( "")+1、S.Length); //文字列の属性を使用します。
document.write(word)// "ello world"
文字列はオブジェクトではないので、なぜプロパティがあるのですか?文字列Sの属性が参照される限り、JavaScriptは、文字列メソッドを継承する新しい文字列を呼び出すことにより、文字列の値をオブジェクトに変換します。属性参照を処理するために使用されます。新しい属性が参照されると。参照が完了すると、新しく作成されたオブジェクトが破壊されます。 (この一時的なオブジェクトは、実際に必ずしも作成または破壊するわけではありませんが、このプロセスはこのようになります。)
文字列と同様に、数字やブール値にも独自のメソッドがあり、数字()およびboolean()コンストラクターを介して一時的なオブジェクトを作成します。これらのメソッドはすべて、この一時的なオブジェクトから呼び出されます。 (null and未定義ではオブジェクトが包まれていないため、プロパティにアクセスするにはタイプエラーがあります)
次のコードを見て、それらの実行プロセスについて考えてください
コードコピーは次のとおりです。
var s = "test";
s.len = 4; //そのためにプロパティを設定します
var t = s.len //このプロパティを見つけます
このコードを実行すると、tの値は未定義です。コードの2行目は一時的な文字列オブジェクトを作成し、4の値を与えます。オブジェクトは破壊されます。 3行目は、元の(変更されていない)文字列を使用して新しい文字列オブジェクトを作成し、LENの属性を読み込もうとします。
このプロパティは自然に存在せず、結果が未定義であることを示しています。このコードは、文字列、配列、ブール値のプロパティ値(またはメソッド)を読み取るときに、オブジェクトのように動作するが、そのプロパティに値を割り当てようとする場合、そのように動作することを示しています。この操作は無視されます。変更は一時的なオブジェクトにのみ発生します。この一時的なオブジェクトは保持されませんでした。
ラッパーオブジェクトの作成は、string()、number()、およびboolean()コンストラクターを介して表示できることに注意してください。
コードコピーは次のとおりです。
var s = "test"、
n = 1、
b = true;
var s = new String(s);
var n = new Number(n);
var b = new boolean(b);
JavaScriptは、必要に応じてラッパーを元の値に変換するため、前のコードのオブジェクトSNBは頻繁に - 常にではありませんが、SNBと同じ値を表します。
しかし、「===」フル演算子はそれらを不平等として扱い、元の値とそれがラップするオブジェクトの違いは、Typeofオペレーターを介して見ることができます。
7.不変の元の値と可変オブジェクト参照。
JavaScriptの元の値(未定義のNULLブール数と文字列)は、オブジェクト(配列と関数を含む)とは根本的に異なります。元の値は変更できません。原始値を(または変異させる)方法はありません。数字とブール人には明らかに当てはまります - 数字の値を変更すること自体は意味がありませんが、文字列は文字の配列であるように見えるため、ひもにはそれほど明白ではありません。文字列内の文字は、指定されたインデックスによって変更できると予想されます。実際、JavaScriptはこれを行うことを禁止しています。文字列内のすべてのメソッドは、実際には新しい文字列である変更された文字列を返すように見えます。
コードコピーは次のとおりです。
var s = "hello world";
S.touppercase(); //「helloworld」を返し、sの値を変更しません
S // =>「Hello World」オリジナル文字列は変更されていません
原始值的比较是值的比较,只有在他们的值相当时它们在才相等。这对数字、布尔值、null和undefined来说听起来有点难,并没有其他办法来比较他们。同样,对于字符串来说则不那么明显;如果比较两个单独的字符串,当且仅当他们的长度相等且每个索引的字符都相等时,javascript的才认为相等。
コードコピーは次のとおりです。
var o = {x:1} //定义一个对象
ox = 2 //通过修改对象的属性来改变对象
oy = 3 //再次更改这个对象,给它增加一个新属性
var a =[1,2,3] //数组也是可以修改的
a[0]=0; //更改数组中的一个元素
a[3]=4; 给数组增加一个新元素
对象的比较并非值的比较:即使两个对象包含同样的属性及相同的值,他们也是不相等的,各个索引元素完全相等的两个数组也不相等
コードコピーは次のとおりです。
var o ={x:1}, p={x:1}//两个具有相同属性的两个对象
o === p ;//=>false 两个单独的对象永不相等( o == p ; =>false)
var a =[],b=[]; //两个单独的空数组
a === b ; //=>false两个单独的数组永不相等
我们通常将对象称为引用类型(reference type),以此来和javascript的基本类型区分开来。依照术语的叫法,对象都是引用(reference),对象的比较均是引用的比较;当且当它们应用同一个基对象时,它们才相等。
コードコピーは次のとおりです。
var a = []; //定义一个引用空数组的变量a
var b = a; //变量b引用同一个数组
b[0] = 1;
a[0] //=>1 变量a也会修改
a === b //=>true a和b引用同一个数组,因此他们相等。
就像你刚才看到的如上代码,将对象(或数组)赋值给一个变量,仅仅是赋值的引用值:对象本身并没有复制一次。
如果你想得到一个对象或数组的副本,则必须显式复制对象的每个属性或数组的每个元素。下面的这个例子则是通过循环来完成对数组的复制。
コードコピーは次のとおりです。
var a = ['a', 'b', 'c']; //待复制的数组
var b = []; //复制到目标的空数组
for (var i = 0; i < a.length; i++) { //遍历a[]中的每个元素
b[i] = a[i]; //将元素复制到b中。
}
同样的,如果我们想比较两个单独或者数组,则必须比较他们的属性或元素。下面这段代码定义了一个比较练个数组的函数。
コードコピーは次のとおりです。
function equalArrays(a, b) {
if (a.length != b.length) return false; //两个长度不相同的数组不相等
for (var i = 0; i < a.length; i++) //循环遍历所有元素
if (a[i] !== b[i]) return false; //如果有任意元素不等,则数组不相等
return true; // 否则他们相等
}
8.类型转化
javascript中的取值型非常灵活,我们已经从布尔值看到了这一点:当javascript期望使用一个布尔值时候,你可以提供任意类型值。javascript将根据需要自行转换类型。一些值(真值)为true,其它值(假值)转化为false.这在其它类型中同样适用。如果javascript期望使用一个字符串,它把给定的值转换为字符串。如果javascript期望使用一个数组,它把给定的值转换为数字(如果转化结果无意义的话将返回NaN),一些例子如下:
コードコピーは次のとおりです。
10 + "object" //=> "10object";
"7" * "4" // =>28 两个字符串均转化为数字
var n = 1 - "x" // =>NaN字符串x无法转换为数字
n + " objects" // =>"NaN objects":NaN转换为字符串"NaN"
下表说明了在javascript中如何进行类型转化。粗体突出了那些让你倍感意外的类型转化。空单元格表示不必要也没有执行的转换。
| 価値 | 文字列に変換します | 番号 | 布尔值 | 物体 |
| 未定義 ヌル | "未定義" "null" | NaN 0 | 間違い 間違い | throws TypeError throws TypeError |
| 真実 間違い | "ture" "間違い" | 1 0 | new Boolean(true) new Boolean(false) | |
| ""(空字符串) "1.2"(非空,数字) "one"(非空,非数字) | 0 1.2 NaN | 間違い 真実 真実 | new String("") new String("1.2") new String("one") | |
| 0 -0 NaN Infinty -Infinty 1(无穷大,非零) | "0" "0" "NaN" "Infinity" "-Infinity" "1" | 間違い 間違い 間違い 真実 真実 真実 | new Number(0); new Number(-0); new Number(NaN) new Number(Infinty) new Number(-Infinty) new Number(1) | |
| {}(任意对象) [](任意数组) [9](1个数字元素) ['a'](其它数组) function(){}(任意函数) | 参考本小节第三节内容 "" "9" 使用join()方法 参考本小节第三节内容 | 参考本小节第三节内容 0 9 NaN NaN | 真実 真実 真実 真実 真実 |
上表提到的原始值到原始值的转换行对简单,我们已经在第本文第三小节讨论过转换为布尔值的情况了。所有原始值转换为字符串的情形也已经明确定义。转换为数字的情形比较微妙。那些以数字表示的字符串可以直接转化为数字,也允许在开始和结尾处带有空格。但在开始和结尾处的任意非空字符都不会被当成数字量的一部分,进而造成字符串为数字的结果为NaN。有一些数字转换看起来让人奇怪:true转换为1,false、空字符串""转换为0.
原始值到对象的转换也非常简单,原始值通过调用String(),Number()或Boolean()构造函数,转化为它们各自的包装对象。见本文第6节。
null和undefined属于例外,当将它们用在期望是一个对象的地方都会造成一个类型错误(TypeError)异常。而不会执行正常的转换。
对象到原始值的转换多少有些复杂,本小节第三小节有专门描述。
i.转换和相等性
由于javascript可以做灵活的类型转换,因此其“==”相等运算符也随相等的含义灵活多变。例如:如下这些比较结果均是true;
null == undefined //这两值被认为相等
"0" == 0 //在比较之前,字符串转换成数字。
0 = false //在这之前布尔值转换成数字。
"0" ==false //在比较之前字符串和布尔值都转换成数字
在第四章9节第一小节相信讲解了“==”等于运算符在判断两个值是否相等时做了那些类型转换,并同样介绍了“===”恒等运算符在判断相等时并未做任何的类型转换。
需要特别注意的是:一个值转换为另一个值并不意味着两个值相等。比如在期望使用布尔值的地方使用了undefined,将会转换为false,但这不表明undefined==false。javascript运算符和语句期望使用多样化的数据类型,并可以互相转换。if语句将undefined转化为false,但“==”运算符从不试图将其转化为布尔值。
ii.显式类型转化
尽管javascript可以做做很多类型转换,但有时仍需要做显式转换,或者为了使代码变得清晰易读而做显式转换。
做显式转换最重简单的方法就是使用Boolean()、Number()、String()或Object函数。我们在本文第6节已经介绍过了. 当不通过new运算符调运这些函数时,他们会作为类型转换函数并按照上边表格所描述的规则做类型转换。
コードコピーは次のとおりです。
Number("3") //=>3
String(false) //=>"false"或使用false.toString()
Boolean([]) //=>true
Object(3) // =>new Number(3)
需要注意的是,除了null或undefined之外的任何值都具有toString()方法,在这个方法的执行结果通常和String()方法返回的结果一致。同样需要注意的话,如果试图把null或undefined转化为对象。则会抛出一个类型错误typeerro。Object()函数在这种情况下不会抛出异常:它仅简单返回一个新创建的空对象。
javascript中的某些运算符会做隐式的类型转换,有时用于类型转换。如果“+”运算符的一个操作数是字符串,它将会把令一个操作数转换为字符串。一元“+”运算符将其操作数转换为数字。同样,一元“!”运算符将其操作数转换为布尔值取反,在代码中常会看到这种类型转换的惯用法。
コードコピーは次のとおりです。
x + "" // 等于字符串String(x)
+x //等价于Number(x),也可以写成x-0
!!x //等价于Boolean(x)
在计算机中数字的解析和格式化代码是非常普通的工作。javascript中提供了专门的函数和方法用来更加精确的数字到字符串(number-to-string)和字符串到数字(string-to-number)的抓换。
Nmuber类定义的toString()方法可以接收表示基数(二进制,八进制,十六进制等)的可选参数,如果不指定该参数,转化规则将是十进制。同样也可以将数字转换为其它进制数。(范围在2-36之间)
コードコピーは次のとおりです。
var n = 17;
b_string = n.toString(2); //转化为10001
o_string = "0" + n.toString(8); //转化为八进制021
hex_string = "0x" + n.toString(16); //转化为16进制0x11
javascript为控制输出中小数点位置和有效数字位数,或者决定是否需要指定指数计数法。Number类为这种数字到字符串定义了三个方法。
toFixed()根据小数点后指定位数,将数字转换为字符串,它从不使用指数计数法。toExponential()使用指数计数法,将数字转换为指数形式的字符串,其中小数点前只有一位,小数点后的位置则由参数指定(也就是说有效数字位数要比指定的位数多一位)。toPrecision()根据指定的有效数字位数,将数字转换为字符串。如果有效数字的位数小于数字整数部分的位数,则转换成指数形式。我们注意到,三个方法都会适当的进行四舍五入或填充0,
コードコピーは次のとおりです。
var n = 123456.789;
n.toFixed(0); //"123457"
n.toFixed(2); //"123456.79"
n.toFixed(5); //"123456.78900"
n.toExponential(1); //"1.2e+5"
n.toExponential(3); //"1.235e+5"
n.toPrecision(4); // "1.235e+5"
n.toPrecision(7); //"123456.8"
n.toPrecision(10); //"123456.7890"
如果通过Number()转换函数传入一个字符串,它会试图将其转化为一个整数或浮点数直接量,这个方法只能基于十进制进行转换,并且不能出现非法的尾随字符。parseInt()和parseFloat()函数(它们是全局函数,不属于人和类的方法),更加灵活。parseInt()只解析整数。而parseFloat()则可以解析整数和浮点数。如果字符串前边是0x或0X,parseInt()将其解析为16进制数。两个方法都会跳过任意量的前导空格,尽可能解析更多数值字符。并忽略后边的内容。如果第一个是非法的数字直接量,则返回NaN
コードコピーは次のとおりです。
parseInt("3many nice") //=>3;
parseFloat("3.14meters") //=>3.14
parseInt("-12.34") //=>-12
parseInt("0xff") //=>255
parseInt("-0XFF") //=>-255
parseFloat(".1") // =>0.1
parseInt("0.1") //=> 0
parseInt(".1") //=>NaN 不能以.开始
parseInt("$112") //=>NaN 不能以$开头
parseInt()可以接收第二个可选参数。这个参数指定数字转换的基数。合法的取值范围是2-36
コードコピーは次のとおりです。
parseInt("11", 2) //=>3(1*2+1)
parseInt("ff", 16) //=> 255(15*16 +15)
parseInt("zz", 36) //=>1295(35*36+35)
parseInt("077", 8) // 63(7*8 +7)
parseInt("077", 10) //77(7*10+7)
iii.对象转化为原始值。
对象到布尔值的转换非常简单:所有的对象(包括数组和函数)都转换为true。对于包装对象亦是如此,new Boolean(false)是一个对象而不是原始值,它将转换为true。 对象到字符串(object-to-String)和对象到数字(object-to-number)的转换是通过调用带转换对象的一个方法来完成的。一个麻烦的事实是,javascript对象有两个不同的方法来执行转换,并且接下来要讨论并且接下来要讨论的场景更加复杂。值得注意的是,这里提到的字符串和数字的转换规则只适用于本地对象(native fangf object).宿主对象(例如:由web浏览器定义的对象),根据各自的算法可以转换成字符串和数字。
所有的对象继承了两个转换方法。第一个是toString(), 它的作用是返回一个反映这个对象的字符串。默认的toString()方法并不会返回一个有趣的值。
({x:1,y:2}).toString() //=>"[object object]"
很多类定义了更多特定版本的toString()方法.
例如:数组类(Array class)的toString()方法将每个数组元素转换为一个字符串,并在元素之间添加逗号后并合成结果字符串。
函数类(Function class)的toString()方法返回这个函数的实现定义的表示方式。实际上,这里的实现方式是通常是将用户定义函数转换为javascript源代码字符串。
日期类(Date class)定义toString()方法返回一个可读的(可被javascript-parsable解析的)日期和事件字符串
RegExp class定义的toString()方法将RegExp对象转换为正则表达式直接量字符串。
コードコピーは次のとおりです。
[1, 2, 3].toString(); //=> "1,2,3"
(function(x) {f(x);}).toString(); // =>"function(x){/nf(x); /n}"
//d+/g.toString(); //=> ///d+/g
new Date(2015, 0, 1).toString() //=>Thu Jan 01 2015 00:00:00 GMT+0800 (中国标准时间)
另外一个函数是valueOf(),这个方法的任务并未详细定义:如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示一个原始值,数组、函数和正则表达式简单地继承了这个默认方法,调用这些类型的实例的的valueOf()方法简单地返回对象本身。日期类定义的valueOf()方法返回它的一个内部表示:1970年1月1日以来的毫秒数。
コードコピーは次のとおりです。
var d = new Date(2015, 0, 1); //=>Thu Jan 01 2015 00:00:00 GMT+0800 (中国标准时间)
d.valueOf() //=>1420041600000
通过是用我们刚才讲解过的toString()和valueOf()方法,就可以做到对象到字符串和对象到数字的转换了。但在某些场景中,javascript执行了完全不同的对象到原始值的转换。这些特殊的场景在本节的最后会讲到。
javascript对象到字符串的转换经过了如下这些步奏
如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,javascript将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。
如果对象没toString()方法,或者这个方法并不返回一个原始值,那么javascript会调用valueOf()方法。如果存在这个方法,则javascript调用它。如果返回值是原始值,javascript将责怪值转换为字符串。
9.变量声明。
在javascript程序中,使用一个变量之前应该先声明,变量是通过var来声明的,如下所示:
var i;
var sum;
也可以通过一个var关键字声明多个变量
var i,sun;
而且还可以将变量的初始值和变量声明和写在一起;
var message = "hello";
var i=0 ,j=0,k=0;
如果在var声明语句中给变量指定初始值,那么虽然声明了这个变量,但在给它存入一个值前,它的初始值是undefined. 我们注意到,在for和fo/in循环中同样可以使用var语句,这样可以更加简洁地声明在循环体语法中内使用的循环变量。例如:
コードコピーは次のとおりです。
for (var i = 0; i < 10; i++) log(i);
for (var i = 0, j = 10; i < 10, j = 100; i++, j--) console.log(i * j)
for (var p in o) console.log(p);
如果在var声明语句中给变量指定初始值,那么虽然声明了这个变量,但在给它存入一个值前,它的初始值是undefined. 我们注意到,在for和fo/in循环中同样可以使用var语句,这样可以更加简洁地声明在循环体语法中内使用的循环变量。例如:
コードコピーは次のとおりです。
var i=10;
i="ten";
10.变量作用域
一个变量的左右域(scope)是程序源代码中定义这个变量的区域,全局变量拥有全局作用域,在javascript代码中的任何地方都是定义。然而在函数内部声明变量只在函数体内有定义。他们是局部变量,作用是局部性的。函数参数也是局部变量,它们只在函数体内有定义。
在函数体内,局部变量的优先级高于同名的全局变量。如果在函数内声明一个局部变量或者函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所遮盖。
コードコピーは次のとおりです。
var scope = "global"; //声明一个全局变量
function checkscope() {
var scope = "local"; //声明一个同名的局部变量
return scope;
}
checkscope(); //=>"local"
尽管在全局作用域编写代码时可以不写var语句,但声明局部变量时则必须使用var语句。
コードコピーは次のとおりです。
scope = "global"; //声明一个全局变量,甚至不使用var来声明
function checkscope2() {
scope = "local"; //修改了全局变量
myscope = "local"; //这里显示式得声明了一个新的全局变量
return [scope, myscope]; //
}
checkscope2(); //=> ["local","local"]:产生了副作用
scope // =>"local"全局变量修改了
myscope //=> "local"全局命名空间搞乱了。
函数定义是可以嵌套的。由于每个函数都有它直接的作用域,因此会出现几个局部作用域嵌套的情况。
コードコピーは次のとおりです。
var scope = "global scope"; //全局变量
function checkscope() {
var scope = "local scope"; //局部变量
function nested() {
var scope = "sested scope"; //嵌套作用域内的局部变量
return scope;
}
return nested();
}
checkscope() //=>"嵌套作用域" sested scope
i.函数作用域和声明提前
在一些类似c语言的编程语言中,花括号内的每一段代码都具有各自的左右域,而且变量在声明他们的代码之外是不可见的我们称之为块级作用域(block scope),而javascript中没有块级作用域,javascript取而代之的使用了函数作用域(function scope);变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有意义的。
如下代码,在不同的位置定义了ijk,他们都在同一个作用域内,这三个变量在函数体内均有定义的。
コードコピーは次のとおりです。
function test(o) {
var i = 0; //i在整个函数体内均是定义的
if (typeif o == "object") {
var j = 0; //j在函数体内是有定义的,不仅仅是在这个代码段内
for (var k = 0; k < 10; k++) { //k在函数体内是有定义的,不仅仅是在循环内
console.log(k); //输出数字0-9
}
console.log(k); //k已经定义,输出10
}
console.log(j); //j已经定义了,但可能没有初始化。
}
javascript的函数作用域是指在函数内声明的所有变量在函数体内始终是可见的。有意思的是,这意味这变量在声明之前甚至已经可用。javascript的这个特性被非正式的称为声明提前(hoisting),即javascript函数里声明的所有变量(但不涉及赋值)都被提前至函数整体的顶部。如下代码:
コードコピーは次のとおりです。
var scope = "global";
function f() {
console.log(scope); //输出"undefined",而不是"global"
var scope = "local"; //变量在这里赋初始值,但变量本身在函数体内任何地方都是有定义的
console.log(scope); //输出"local"
你可能误以为函数的第一行会输出"global",因为代码还没有执行到var语句声明局部变量的地方。其实不然,由于函数作用域的特性模具部变量在整个函数体内始终有定义的,也就是说,在函数体内局部变量覆盖了同名全局变量。尽管如此,只有在程序执行到var语句的时候,局部变量才能正真的被赋值。
因此,上述的过程等价于:将函数内的变量声明"提前"至函数顶部,同时变量初始化留在原来的位置:
コードコピーは次のとおりです。
function f() {
var scope; //在函数的顶部声明了局部变量
console.log(scope); //变量存在,但其值是"undefined"
scope = "local"; //在这里将其初始化,并赋值
console.log(scope); //这里它具有了我们所期望的值
}
在具有块级作用域的编程语言中,在狭小的作用域里让变量声明和使用变量的代码尽可能靠近彼此,通常来说,这是一个非常不错的编程习惯。由于在javascript中没有块级作用域,因此一些程序员特意将变量声明放在函数体顶部,而不是将声明放在靠近使用变量之处。这种做法使得他们的源代码非常清晰地反映了真实的变量作用域。
ii作为属性的变量
当声明一个javascript全局变量时面试及上是定义了全局对象的一个属性。见本文第三节。
当使用var声明一个变量时,创建的这个属性是不可配置的。见第六章第7节。也就是说这个变量无法通过delete运算符删除。可能你已经注意到了,如果你没有使用严格模式并给一个未声明的变量赋值的话。javascript会自动创建一个全局变量。以这种方式创建变量是全局对象正常的可配置属性。可以删除它们。
コードコピーは次のとおりです。
var truevar = 1; //声明一耳光不可删除的全局变量
fakevar = 2; //创建全局对象的一个可删除的属性
this.fakevar2 = 3; //同上
delete truevar // =>false 变量并没有删除
delete fakevar //=>true 变量被删除
delete this.fakevar2 //=>true 变量被删除
javascript全局变量是全局对象的属性,这是在ECMAScript规范中强制规定的。对于局部变量则没有此规定,但我们可以想象得到,局部变量当做跟函数调用相关的某个对象的属性。ECMAScript3规范称对象为“调用对象”(call object),ECMAScript5规定范称为“声明上下文对象”(declarative environment record)。javascript可以允许使用this关键字引用全局对象,却没有方法可以引用局部变量中存放的对象。这种存放局部变量的对象的特有性质,是一种对我们不可见的内部实现。然而,这些局部变量对象存在的观念是非常重要的。
iii作用域链
javascript是基于词法作用域的语言:通过阅读包含变量定义在内的舒航源码就能知道变量的作用域。
全局变量在程序中始终是都是有定义的。局部变量在声明它的函数体内以及其所嵌套的函数内始终是有定义的。