ホームページ  >  記事  >  ウェブフロントエンド  >  「JavaScript高度なプログラミング」を深く理解する

「JavaScript高度なプログラミング」を深く理解する

零下一度
零下一度オリジナル
2017-07-18 16:04:391588ブラウズ

この本「Advanced Javascript Programming」は内容が多く、非常に分厚いので、時間がない人もこの一連の抜粋を読むことで、この本の核となる内容を学ぶことができれば幸いです。

背景が緑色のコンテンツは、より注目すべきと思われるオリジナルコンテンツです。

背景が黄色のコンテンツは、私が非常に重要だと思うオリジナルコンテンツです。

私の理解は青い文字でマークされます。

この章は内容が多く、比較的重要です。これは次のパートです。

5.5.4 関数の内部プロパティ

関数の内部には、arguments と this という 2 つの特別なオブジェクトがあります。その中で、引数は第 3 章で紹介されました。これは、関数に渡されるすべてのパラメータを含む配列のようなオブジェクトです。引数の主な目的は関数パラメータを保存することですが、このオブジェクトには callee と呼ばれる属性もあり、これは引数オブジェクトを所有する関数へのポインタです。以下の非常に古典的な階乗関数を見てください

function factorial(num){if (num <=1) {return 1;

} else {return num * factorial(num-1)

}

}

関数に名前があり、その名前が変更されない場合、上記のコードに示すように、再帰アルゴリズムは通常、階乗関数を定義するために使用されます。この定義で問題ありません。しかし、問題は、この関数の実行が関数名階乗と密接に関係していることです。この密結合を排除するには、arguments.callee を次のように使用できます。

function factorial(num){if (num <=1) {return 1;

} else {return num * arguments.callee(num-1)

}

}
コードを見る
この書き換えられたfactorial()関数の関数本体では、関数名factorialが引用符で囲まれなくなりました。このようにして、

関数を参照するときにどのような名前が使用されても、再帰呼び出しは正常に完了することが保証されます。例:

var trueFactorial = factorial;

factorial = function(){return 0;

};

alert(trueFactorial(5)); //120alert(factorial(5)); //0
コードを表示

在此,变量 trueFactorial 获得了 factorial 的值,实际上是在另一个位置上保存了一个函数的指针。然后,我们又将一个简单地返回 0 的函数赋值给 factorial 变量。如果像原来的 factorial()那样不使用 arguments.callee,调用 trueFactorial()就会返回 0。可是,在解除了函数体内的代码与函数名的耦合状态之后, trueFactorial()仍然能够正常地计算阶乘;至于 factorial(),它现在只是一个返回 0 的函数。

函数内部的另一个特殊对象是 this,其行为与 Java 和 C#中的 this 大致类似。换句话说, this引用的是函数据以执行的环境对象——或者也可以说是 this 值(当在网页的全局作用域中调用函数时,this 对象引用的就是 window)。来看下面的例子。

window.color = "red";var o = { color: "blue" };function sayColor(){

alert(this.color);

}

sayColor(); //"red"o.sayColor = sayColor;

o.sayColor(); //"blue"
View Code

  上面这个函数 sayColor()是在全局作用域中定义的,它引用了 this 对象。由于在调用函数之前,this 的值并不确定,因此 this 可能会在代码执行过程中引用不同的对象。当在全局作用域中调用sayColor()时, this 引用的是全局对象 window;换句话说,对 this.color 求值会转换成对window.color 求值,于是结果就返回了"red"。而当把这个函数赋给对象 o 并调用 o.sayColor()时,this 引用的是对象 o,因此对 this.color 求值会转换成对 o.color 求值,结果就返回了"blue"。

  请读者一定要牢记,函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的 sayColor()函数与 o.sayColor()指向的仍然是同一个函数。

  ECMAScript 5 也规范化了另一个函数对象的属性:caller。除了 Opera 的早期版本不支持,其他浏览器都支持这个 ECMAScript 3 并没有定义的属性。这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为 null。例如:

function outer(){

inner();

}function inner(){

alert(inner.caller);

}

outer();
View Code

以上代码会导致警告框中显示 outer()函数的源代码。因为 outer()调用了 inter(),所以inner.caller 就指向 outer()。为了实现更松散的耦合,也可以通过 arguments.callee.caller来访问相同的信息。

function outer(){

inner();

}function inner(){

alert(arguments.callee.caller);

}

outer();
View Code

IE、 Firefox、 Chrome 和 Safari 的所有版本以及 Opera 9.6 都支持 caller 属性。

当函数在严格模式下运行时,访问 arguments.callee 会导致错误。 ECMAScript 5 还定义了arguments.caller 属性,但在严格模式下访问它也会导致错误,而在非严格模式下这个属性始终是undefined。定义这个属性是为了分清 arguments.caller 和函数的 caller 属性。以上变化都是为了加强这门语言的安全性,这样第三方代码就不能在相同的环境里窥视其他代码了。严格模式还有一个限制:不能为函数的 caller 属性赋值,否则会导致错误。

 

  5.5.5 函数属性和方法

  前面曾经提到过, ECMAScript 中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性: length 和 prototype。其中, length 属性表示函数希望接收的命名参数的个数,如下面的例子所示。

function sayName(name){

alert(name);

}function sum(num1, num2){return num1 + num2;

}function sayHi(){

alert("hi");

}

alert(sayName.length); //1alert(sum.length); //2alert(sayHi.length); //0
View Code

  在 ECMAScript 核心所定义的全部属性中,最耐人寻味的就要数 prototype 属性了。对于ECMAScript 中的引用类型而言, prototype 是保存它们所有实例方法的真正所在。换句话说,诸如toString()和 valueOf()等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及实现继承时, prototype 属性的作用是极为重要的(第 6 章将详细介绍)。在 ECMAScript 5 中, prototype 属性是不可枚举的,因此使用 for-in 无法发现。

  每个函数都包含两个非继承而来的方法: apply()和 call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。首先, apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例也可以是arguments 对象。例如:

function sum(num1, num2){return num1 + num2;

}function callSum1(num1, num2){return sum.apply(this, arguments); // 传入 arguments 对象}function callSum2(num1, num2){return sum.apply(this, [num1, num2]); // 传入数组}

alert(callSum1(10,10)); //20alert(callSum2(10,10)); //20
View Code

  在上面这个例子中, callSum1()在执行 sum()函数时传入了 this 作为 this 值(因为是在全局作用域中调用的,所以传入的就是 window 对象)和 arguments 对象。而 callSum2 同样也调用了sum()函数,但它传入的则是 this 和一个参数数组。这两个函数都会正常执行并返回正确的结果。

  call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call()方法而言,第一个参数是 this 值没有变化,变化的是其余参数都直接传递给函数。换句话说,在使用call()方法时,传递给函数的参数必须逐个列举出来,如下面的例子所示。

function sum(num1, num2){return num1 + num2;

}function callSum(num1, num2){return sum.call(this, num1, num2);

}

alert(callSum(10,10)); //20
View Code

  在使用 call()方法的情况下, callSum()必须明确地传入每一个参数。结果与使用 apply()没有什么不同。至于是使用 apply()还是 call(),完全取决于你采取哪种给函数传递参数的方式最方便。如果你打算直接传入 arguments 对象,或者包含函数中先接收到的也是一个数组,那么使用 apply()肯定更方便;否则,选择 call()可能更合适。(在不给函数传递参数的情况下,使用哪个方法都无所谓。)

事实上,传递参数并非 apply()和 call()真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。下面来看一个例子。

window.color = "red";var o = { color: "blue" };function sayColor(){

alert(this.color);

}

sayColor(); //redsayColor.call(this); //redsayColor.call(window); //redsayColor.call(o); //blue
View Code

  这个例子是在前面说明 this 对象的示例基础上修改而成的。这一次, sayColor()也是作为全局函数定义的,而且当在全局作用域中调用它时,它确实会显示"red"——因为对 this.color 的求值会转换成对 window.color 的求值。而 sayColor.call(this)和 sayColor.call(window),则是两种显式地在全局作用域中调用函数的方式,结果当然都会显示"red"。但是,当运行 sayColor.call(o)时,函数的执行环境就不一样了,因为此时函数体内的 this 对象指向了 o,于是结果显示的是"blue"。

  使用 call()(或 apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。在前面例子的第一个版本中,我们是先将 sayColor()函数放到了对象 o 中,然后再通过 o 来调用它的;而在这里重写的例子中,就不需要先前那个多余的步骤了。

ECMAScript 5 还定义了一个方法: bind()。这个方法会创建一个函数的实例,其 this 值会被绑定到传给 bind()函数的值。例如:

window.color = "red";var o = { color: "blue" };function sayColor(){

alert(this.color);

}var objectSayColor = sayColor.bind(o);

objectSayColor(); //blue

ここで、sayColor() は、bind() を呼び出し、オブジェクト o を渡し、objectSayColor() 関数を作成します。 object

SayColor() 関数の this 値は o に等しいため、この関数がグローバル スコープで呼び出された場合でも、「青」と表示されます。この手法の利点については、第 22 章を参照してください。

bind() メソッドをサポートするブラウザは、IE9 以降、Firefox 4 以降、Safari 5.1 以降、Opera 12 以降、および Chrome です。

各関数によって継承される toLocaleString() メソッドと toString() メソッドは、常に関数のコードを返します。リターン コードの形式はブラウザによって異なります。ソース コード内の関数コードと同じコードを返すものもあれば、関数コードの内部表現を返すものもあります。つまり、パーサーによってコメントが削除され、特定のコードが変更されます。 。これらの違いのため、これら 2 つのメソッドから返された結果に基づいて重要な操作を行うことはできませんが、この情報はコードをデバッグするときに役立ちます。継承された別の valueOf() メソッドも、関数コードのみを返します。

5.6 基本的なパッケージ化タイプ

基本的なタイプ値の操作を容易にするために、ECMAScript は 3 つの特別な参照タイプ、Boolean、Number、String も提供します。これらの型は、この章で紹介する他の参照型と似ていますが、それぞれの基本型に対応する特別な動作もあります。実際、基本型の値が読み取られるたびに、対応する基本ラッパー型オブジェクトがバックグラウンドで作成され、このデータを操作するいくつかのメソッドを呼び出すことができるようになります。次の例を考えてみましょう。

var s1 = "some text";

var s2 = s1.substring(2);

この例の変数 s1 には文字列が含まれており、これはもちろん基本型の値です。次の行では、s1 の substring() メソッドを呼び出し、返された結果を s2 に保存します。プリミティブ型の値はオブジェクトではないことがわかっているため、論理的にはメソッドを持つべきではありません (ただし、私たちが望むように、メソッドを持つ必要があります)。実はこの直感的な操作を実現するために、一連の処理がバックグラウンドで自動的に行われています。コードの 2 行目が s1 にアクセスするとき、アクセス プロセスは読み取りモードになります。つまり、この文字列の値がメモリから読み取られます。読み取りモードで文字列にアクセスすると、以下の処理がバックグラウンドで自動的に完了します。

(1) String 型のインスタンスを作成します。

(2) インスタンス上で指定されたメソッドを呼び出します。

(3) このインスタンスを破棄します。

上記の 3 つのステップは、次の ECMAScript コードを実行するものと想像できます。

var s1 = new String("some text");

var s2 = s1.substring(2);

s1 = null;

この処理の後、基本文字列は価値観はオブジェクトのようになります。さらに、上記の 3 つの手順は、それぞれ Boolean 型と Number 型に対応する Boolean 値と数値にも適用されます。参照型と基本ラッパー型の主な違いは、オブジェクトの存続期間です。 new 演算子を使用して作成された参照型のインスタンスは、実行フローが現在のスコープを離れるまでメモリ内に残ります。自動的に作成される基本的なパッケージング タイプのオブジェクトは、コード行が実行される時点でのみ存在し、その後すぐに破棄されます。これは、実行時にプリミティブ型の値にプロパティやメソッドを追加できないことを意味します。

次の例を見てください:

var s1 = "some text";

s1.color = "red";

alert(s1.color); //undefined

在此,第二行代码试图为字符串 s1 添加一个 color 属性。但是,当第三行代码再次访问 s1 时,其 color 属性不见了。问题的原因就是第二行创建的 String 对象在执行第三行代码时已经被销毁了。第三行代码又创建自己的 String 对象,而该对象没有 color 属性。当然,可以显式地调用 Boolean、 Number 和 String 来创建基本包装类型的对象。不过,应该在绝对必要的情况下再这样做,因为这种做法很容易让人分不清自己是在处理基本类型还是引用类型的值。对基本包装类型的实例调用 typeof 会返回"object",而且所有基本包装类型的对象都会被转换为布尔值 true。

Object 构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。例如:

var obj = new Object("some text");

alert(obj instanceof String); //true

把字符串传给 Object 构造函数,就会创建 String 的实例;而传入数值参数会得到 Number 的实例,传入布尔值参数就会得到 Boolean 的实例。

要注意的是,使用 new 调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。例如:

var value = "25";var number = Number(value); //转型函数alert(typeof number); //"number"var obj = new Number(value); //构造函数alert(typeof obj); //"object"
View Code

在这个例子中,变量 number 中保存的是基本类型的值 25,而变量 obj 中保存的是 Number 的实例。要了解有关转型函数的更多信息,请参考第 3 章。

尽管我们不建议显式地创建基本包装类型的对象,但它们操作基本类型值的能力还是相当重要的。而每个基本包装类型都提供了操作相应值的便捷方法。

5.6.1 Boolean类型

Boolean 类型是与布尔值对应的引用类型。要创建 Boolean 对象,可以像下面这样调用 Boolean构造函数并传入 true 或 false 值。

var booleanObject = new Boolean(true);

Boolean 类型的实例重写了 valueOf()方法,返回基本类型值 true 或 false;重写了 toString()

方法,返回字符串"true"和"false"。可是, Boolean 对象在 ECMAScript 中的用处不大,因为它经常会造成人们的误解。其中最常见的问题就是在布尔表达式中使用 Boolean 对象,例如:

var falseObject = new Boolean(false);var result = falseObject && true;

alert(result); //truevar falseValue = false;

result = falseValue && true;

alert(result); //false
View Code

前面讨论过,布尔表达式中的所有对象都会被转换为 true,因此 falseObject 对象在布尔表达式中代表的是 true。结果, true && true 当然就等于 true 了。

基本类型与引用类型的布尔值还有两个区别。首先, typeof 操作符对基本类型返回"boolean",而对引用类型返回"object"。其次,由于 Boolean 对象是 Boolean 类型的实例,所以使用 instanceof操作符测试 Boolean 对象会返回 true,而测试基本类型的布尔值则返回 false。例如:

alert(typeof falseObject); //objectalert(typeof falseValue); //booleanalert(falseObject instanceof Boolean); //truealert(falseValue instanceof Boolean); //false
View Code

理解基本类型的布尔值与 Boolean 对象之间的区别非常重要——当然,我们的建议是永远不要使用 Boolean 对象。

5.6.2 Number类型

Number 是与数字值对应的引用类型。要创建 Number 对象,可以在调用 Number 构造函数时向其中传递相应的数值。下面是一个例子。

var numberObject = new Number(10);

与 Boolean 类型一样, Number 类型也重写了 valueOf()、 toLocaleString()和 toString()

方法。重写后的 valueOf()方法返回对象表示的基本类型的数值,另外两个方法则返回字符串形式的数值。我们在第 3 章还介绍过,可以为 toString()方法传递一个表示基数的参数,告诉它返回几进制数值的字符串形式,如下面的例子所示。

var num = 10;

alert(num.toString()); //"10"alert(num.toString(2)); //"1010"alert(num.toString(8)); //"12"alert(num.toString(10)); //"10"alert(num.toString(16)); //"a"NumberTypeExample01.htm
View Code

除了继承的方法之外, Number 类型还提供了一些用于将数值格式化为字符串的方法。

其中, toFixed()方法会按照指定的小数位返回数值的字符串表示,例如:

var num = 10;

alert(num.toFixed(2)); //"10.00"

NumberTypeExample01.htm

这里给 toFixed()方法传入了数值 2,意思是显示几位小数。于是,这个方法返回了"10.00",即以 0 填补了必要的小数位。如果数值本身包含的小数位比指定的还多,那么接近指定的最大小数位的值就会舍入,如下面的例子所示。

var num = 10.005;

alert(num.toFixed(2)); //"10.01"

能够自动舍入的特性,使得 toFixed()方法很适合处理货币值。但需要注意的是,不同浏览器给这个方法设定的舍入规则可能会有所不同。在给 toFixed()传入 0 的情况下, IE8 及之前版本不能正确舍入范围在{(-0.94,-0.5],[0.5,0.94)}之间的值。对于这个范围内的值, IE 会返回0,而不是1或1;其他浏览器都能返回正确的值。 IE9 修复了这个问题。

5.6.3 String类型

String 类型是字符串的对象包装类型,可以像下面这样使用 String 构造函数来创建。

var stringObject = new String("hello world");

String 对象的方法也可以在所有基本的字符串值中访问到。其中,继承的 valueOf()、toLocale

String()和 toString()方法,都返回对象所表示的基本字符串值。

String 类型的每个实例都有一个 length 属性,表示字符串中包含多个字符。来看下面的例子。

var stringValue = "hello world";

alert(stringValue.length); //"11"

这个例子输出了字符串"hello world"中的字符数量,即"11"。应该注意的是,即使字符串中包含双字节字符(不是占一个字节的 ASCII 字符),每个字符也仍然算一个字符。

String 类型提供了很多方法,用于辅助完成对 ECMAScript 中字符串的解析和操作。

1. 字符方法

两个用于访问字符串中特定字符的方法是: charAt()和 charCodeAt()

2. 字符串操作方法

下面介绍与操作字符串有关的几个方法。第一个就是 concat(),用于将一或多个字符串拼接起来,返回拼接得到的新字符串。先来看一个例子。

var stringValue = "hello ";var result = stringValue.concat("world");

alert(result); //"hello world"alert(stringValue); //"hello"
View Code

ECMAScript还提供了三个基于子字符串创建新字符串的方法:slice()、substr()和substring()。这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数(在指定的情况下)表示子字符串到哪里结束。具体来说, slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置。而 substr()的第二个参数指定的则是返回的字符个数。如果没有给这些方法传递第二个参数,则将字符串的长度作为结束位置。与concat()方法一样, slice()、 substr()和 substring()也不会修改字符串本身的值——它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。请看下面的例子。

var stringValue = "hello world";

alert(stringValue.slice(3)); //"lo world"alert(stringValue.substring(3)); //"lo world"alert(stringValue.substr(3)); //"lo world"alert(stringValue.slice(3, 7)); //"lo w"alert(stringValue.substring(3,7)); //"lo w"alert(stringValue.substr(3, 7)); //"lo worl"
View Code

3. 字符串位置方法

有两个可以从字符串中查找子字符串的方法: indexOf()和 lastIndexOf()。这两个方法都是从

一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回-1)。这两个方法的区别在于: indexOf()方法从字符串的开头向后搜索子字符串,而 lastIndexOf()方法是从字符串的末尾向前搜索子字符串。还是来看一个例子吧。

var stringValue = "hello world";

alert(stringValue.indexOf("o")); //4

alert(stringValue.lastIndexOf("o")); //7

4. trim()方法

ECMAScript 5 为所有字符串定义了 trim()方法。这个方法会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果。例如:

var stringValue = " hello world ";var trimmedStringValue = stringValue.trim();

alert(stringValue); //" hello world "alert(trimmedStringValue); //"hello world"
View Code

5. 字符串大小写转换方法

接下来我们要介绍的是一组与大小写转换有关的方法。 ECMAScript 中涉及字符串大小写转换的方法有 4 个: toLowerCase()、 toLocaleLowerCase()、 toUpperCase()和 toLocaleUpperCase()

7. localeCompare()方法

与操作字符串有关的最后一个方法是 localeCompare(),这个方法比较两个字符串,并返回下列值中的一个:

q 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1,具体的值要视实现而定);

q 如果字符串等于字符串参数,则返回 0;

q 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是 1,具体的值同样要视实现而定)。

下面是几个例子。

var stringValue = "yellow";

alert(stringValue.localeCompare("brick")); //1alert(stringValue.localeCompare("yellow")); //0alert(stringValue.localeCompare("zoo")); //-1
View Code

5.7 単一の組み込みオブジェクト

ECMA-262では、組み込みオブジェクトを「ホスト環境に依存しないECMAScript実装によって提供されるオブジェクト。これらのオブジェクトはECMAScriptプログラムが実行される前にすでに存在している。」と定義しています。意味 つまり、組み込みオブジェクトはすでにインスタンス化されているため、開発者は明示的にインスタンス化する必要はありません。 Object、Array、String などの組み込みオブジェクトのほとんどをすでに紹介しました。

ECMA-262 では、Global と Math という 2 つの単一の組み込みオブジェクトも定義されています。

5.7.1 Global オブジェクト

Global (グローバル) オブジェクトは、どの角度から見ても存在しないため、ECMAScript で最も特殊なオブジェクトと言えます。 ECMAScript の Global オブジェクトは、ある意味で究極の「キャッチオール オブジェクト」として定義されます。つまり、他のオブジェクトに属さないプロパティとメソッドは、最終的にはそのオブジェクトのプロパティとメソッドになります。実際、グローバル変数や関数は存在せず、グローバル スコープで定義されたすべてのプロパティと関数は Global オブジェクトのプロパティです。 isNaN()、isFinite()、parseInt()、parseFloat() など、本書の前半で紹介した関数は、実際にはすべて Global オブジェクトのメソッドです。これに加えて、Global オブジェクトには他のメソッドもいくつか含まれています。

1. URI エンコードメソッド

グローバルオブジェクトの encodeURI() メソッドと encodeURIComponent() メソッドは、ブラウザに送信するために URI (Uniform Resource

識別子、ユニバーサルリソース識別子) をエンコードできます。スペースなどの特定の文字は、有効な URI に含めることはできません。これら 2 つの URI エンコード方法では、ブラウザが受け入れて理解できるように、すべての無効な文字を特別な UTF-8 エンコードに置き換えます。

2. eval() メソッド

次に、最後のメソッド、おそらく ECMAScript 言語全体で最も強力なメソッド eval() を紹介します。 eval() メソッドは完全な ECMAScript パーサーに似ており、実行される ECMAScript (または JavaScript) 文字列という 1 つのパラメーターのみを受け取ります。次の例を見てください:

eval("alert('hi')");

このコード行は、次のコード行と同等です。

パーサーは、コード内で eval() メソッドが呼び出されていることを検出すると、受信パラメータを実際の ECMAScript ステートメントとして解析し、実行結果を元の位置に挿入します。 eval() 経由で実行されるコードは、呼び出しを含む実行環境の一部とみなされ、実行されるコードはその実行環境と同じスコープ チェーンを持ちます。これは、eval() 経由で実行されるコードは、それを含む環境で定義された変数を参照できることを意味します。たとえば、次のようになります。 hello world"

変数 msg は eval() が呼び出される環境の外で定義されていることがわかりますが、そこで呼び出されるalert() は依然として "hello world" を表示できます。これは、上記のコードの 2 行目が最終的に実際のコード行に置き換えられるためです。同様に、 eval() 呼び出しで関数を定義し、呼び出しの外部コードでその関数を参照することもできます。

sayHi();

明らかに、関数sayHi()はeval()内で定義されています。ただし、 eval() の呼び出しは最終的に関数

を定義する実際のコードに置き換えられるため、sayHi() は次の行で呼び出すことができます。変数についても同様です:

eval("var msg = 'hello world'; ");

alert(msg); //"hello world"

在 eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们被包含在一个字符串中;它们只在 eval()执行的时候创建。

严格模式下,在外部访问不到 eval()中创建的任何变量或函数,因此前面两个例子都会导致错误。同样,在严格模式下,为 eval 赋值也会导致错误:

"use strict";

eval = "hi"; //causes error

能够解释代码字符串的能力非常强大,但也非常危险。因此在使用 eval()时必须极为谨慎,特别是在用它执行用户输入数据的情况下。否则,可能会有恶意用户输入威胁你的站点或应用程序安全的代码(即所谓的代码注入)。

3. Global 对象的属性

Global 对象还包含一些属性,其中一部分属性已经在本书前面介绍过了。例如,特殊的值

undefined、 NaN 以及 Infinity 都是 Global 对象的属性。此外,所有原生引用类型的构造函数,像Object 和 Function,也都是 Global 对象的属性。下表列出了 Global 对象的所有属性。

undefined 特殊值undefined Date 构造函数Date

NaN 特殊值NaN RegExp 构造函数RegExp

Infinity 特殊值Infinity Error 构造函数Error

Object 构造函数Object EvalError 构造函数EvalError

Array 构造函数Array RangeError 构造函数RangeError

Function 构造函数Function ReferenceError 构造函数ReferenceError

Boolean 构造函数Boolean SyntaxError 构造函数SyntaxError

String 构造函数String TypeError 构造函数TypeError

Number 构造函数Number URIError 构造函数URIError

ECMAScript 5 明确禁止给 undefined、 NaN 和 Infinity 赋值,这样做即使在非严格模式下也会导致错误。

4. window 对象

ECMAScript 虽然没有指出如何直接访问 Global 对象,但 Web 浏览器都是将这个全局对象作为window 对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了 window对象的属性。来看下面的例子。

var color = "red";function sayColor(){

alert(window.color);

}

window.sayColor(); //"red"
View Code

ECMAScript で指定された Global オブジェクトの役割を果たすことに加えて、JavaScript の window オブジェクトは他の多くのタスクも引き受けます。ウィンドウ オブジェクトについては、第 8 章でブラウザ オブジェクト モデルを説明するときに詳しく説明します。

5.7.2 Math オブジェクト

ECMAScript は、数式と情報を保存するための共通の場所である Math オブジェクトも提供します。 Math オブジェクトによって提供される計算関数は、JavaScript で直接記述する計算関数よりもはるかに高速に実行されます。 Math オブジェクトには、これらの計算の完了を支援するプロパティとメソッドも提供されます。

1. Math オブジェクトのプロパティ

Math オブジェクトに含まれるプロパティのほとんどは、数学的計算で使用される可能性のある特別な値です。次の表に、これらのプロパティを示します。

これらの値の意味と使用法については本書の範囲を超えていますが、実際はいつでも使用できます。

2. min() メソッドと max() メソッド

Math オブジェクトには、単純な数学的計算と複雑な数学的計算の実行を支援する多くのメソッドも含まれています。

その中で、min() メソッドと max() メソッドは、一連の値の最小値と最大値を決定するために使用されます。次の例に示すように、どちらのメソッドも任意の数の数値引数を受け入れることができます。

var max = Math.max(3, 54, 32, 16);

alert(max); //54

var min = Math.min(3, 54, 32, 16) ; フロア()とMath.round()。

これら 3 つのメソッドは、それぞれ次の丸めルールに従います。

Math.ceil() は上向きの丸めを実行します。つまり、値を常に最も近い整数に切り上げます。切り捨てを実行します。つまり、値を常に最も近い整数に切り捨てます。

Math.round() は、標準的な四捨五入を実行します。つまり、値を常に最も近い整数に切り下げます。 整数 (これは、私たちが学習した丸め規則でもあります)数学の授業中)。

4. random() メソッド

Math.random() メソッドは、0 以上 1 未満の乱数を返します。一部のサイトでは、この方法は有名な引用やニュース イベントをランダムに表示するために使用できるため、非常に実用的です。次の式を適用すると、Math.random() を使用して、特定の範囲の整数から値をランダムに選択できます。

value = Math.floor(Math.random() * 可能な値の合計 + 最初の可能な値)

5. その他のメソッド

5.8 まとめ

オブジェクトは JavaScript では参照型値と呼ばれ、特定のオブジェクトの作成に使用できる組み込みの参照型がいくつかあります。簡単にまとめると次のとおりです:

参照型は従来のオブジェクトのクラスに似ています。指向のプログラミングですが、実装は異なります;

Object は基本的な型であり、他のすべての型は Object から基本的な動作を継承します。

Array 型は一連の値の順序付きリストであり、これらの値を操作および変換するための関数も提供します。 type は、現在の日付と時刻および関連する計算関数を含む日付と時刻に関する情報を提供します。

RegExp type は、ECMAScript が正規表現をサポートするためのインターフェイスであり、最も基本的な正規表現関数といくつかの高度な正規表現関数を提供します。

関数は実際には Function 型のインスタンスであるため、関数はオブジェクトでもあり、これが JavaScript の最も特徴的な機能です。関数はオブジェクトであるため、関数の動作を強化するために使用できるメソッドも備えています。

基本ラッパー型のため、JavaScriptの基本型の値をオブジェクトとしてアクセスできます。 3 つの基本的なラッパー タイプは、Boolean、Number、String です。以下はそれらの共通の特性です:

各ラッパー型は同じ名前の基本型にマップされます

基本型の値が読み取りモードでアクセスされると、対応する基本ラッパー型のオブジェクトが作成されます。これにより、データ操作が容易になります。

基本型の値を操作するステートメントが実行されると、新しく作成されたパッケージング オブジェクトはすぐに破棄されます。

すべてのコードが実行される前に、Global と Math という 2 つの組み込みオブジェクトがスコープ内にすでに存在します。 Global オブジェクトは、ほとんどの ECMAScript 実装では直接アクセスできませんが、Web ブラウザはこの役割を担うウィンドウ オブジェクトを実装します。グローバル変数と関数は、Global オブジェクトのプロパティです。 Math オブジェクトは、複雑な数学的計算タスクの完了を支援する多くのプロパティとメソッドを提供します。

以上が「JavaScript高度なプログラミング」を深く理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。