ホームページ  >  記事  >  ウェブフロントエンド  >  「JavaScript Breakthrough」の単一の組み込みオブジェクト

「JavaScript Breakthrough」の単一の組み込みオブジェクト

高洛峰
高洛峰オリジナル
2016-11-07 16:35:041047ブラウズ

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

グローバルオブジェクト

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

URI エンコード メソッド

Global オブジェクトの encodeURI() メソッドと encodeURIComponent() メソッドは、ブラウザに送信するために URI (Uniform Resource Identifier、Universal Resource Identifier) をエンコードできます。スペースなどの特定の文字は、有効な URI に含めることはできません。これら 2 つの URI エンコード方法では、ブラウザが受け入れて理解できるように、すべての無効な文字を特別な UTF-8 エンコードに置き換えます。

このうち、encodeURI() は主に URI 全体に使用され、encodeURIComponent() は主に URI 内の特定のセグメントをエンコードするために使用されます。これらの主な違いは、encodeURI() はコロン、スラッシュ、疑問符、ハッシュ マークなど、それ自体が URI である特殊文字をエンコードしないのに対し、encodeURIComponent() は検出した非標準文字をエンコードすることです。次の例を考えてみましょう。

var uri = "http://shijiajie.com/illegal value.htm#start"; 
 
console.log(encodeURI(uri)); 
// "http://shijiajie.com/illegal%20value.htm#start" 
 
console.log(encodeURIComponent(uri)); 
// "http%3A%2F%2Fshijiajie.com%2Fillegal%20value.htm%23start"

encodeURI() を使用してエンコードした結果、スペースを除くすべての文字はそのままで、スペースのみが %20 に置き換えられます。 encodeURIComponent() メソッドは、英数字以外の文字をすべて対応するエンコーディングに置き換えます。これが、URI 全体に対して encodeURI() を使用できるのに、既存の URI に追加された文字列に対してのみ encodeURIComponent() を使用できる理由です。

一般に、encodeURI() よりも encodeURIComponent() メソッドを頻繁に使用します。これは、実際には、基になる URI よりもクエリ文字列パラメータをエンコードする方が一般的であるためです。

encodeURI() メソッドと encodeURIComponent() メソッドに対応する 2 つのメソッドは、それぞれ decodeURI() と decodeURIComponent() です。このうち、decodeURI()はencodeURI()で置き換えられた文字のみをデコードできます。たとえば、%20 はスペースに置き換えられますが、%23 は何も行われません。これは、%23 はシャープ記号 # を表し、encodeURI() を使用して置き換えられないためです。同様に、decodeURIComponent() は、encodeURIComponent() を使用してエンコードされたすべての文字をデコードできます。つまり、任意の特殊文字のエンコードをデコードできます。次の例を考えてみましょう:

var uri = "http%3A%2F%2Fshijiajie.com%2Fillegal%20value.htm%23start"; 
 
console.log(decodeURI(uri)); 
// http%3A%2F%2Fshijiajie.com%2Fillegal value.htm%23start 
 
console.log(decodeURIComponent(uri)); 
// http://shijiajie.com/illegal value.htm#start

ここで、変数 uri には、encodeURIComponent() によってエンコードされた文字列が含まれています。 decodeURI() の最初の呼び出しの出力では、%20 のみがスペースに置き換えられます。 decodeURIComponent() の 2 回目の呼び出しの出力結果では、すべての特殊文字のエンコーディングが元の文字に置き換えられ、エスケープされていない文字列が取得されます (ただし、この文字列は有効な URI ではありません)。

eval() メソッド

eval() メソッドは完全な JavaScript パーサーのようなもので、パラメータを 1 つだけ受け入れ、実行される JavaScript 文字列を受け取ります。以下の例を見てください:

eval("console.log('hi')");

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

console.log("hi");

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

var msg = "console.log(msg)"; // "hello world"

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

eval("function SayHi() { console.log('hi'); }" ); SayHi(); // "こんにちは"

明らかに、関数 SayHi() は eval() 内で定義されています。ただし、 eval() の呼び出しは最終的に関数を定義する実際のコードに置き換えられるため、sayHi() は次の行で呼び出すことができます。変数についても同様です:

eval("var msg = 'hello world';"); 
console.log(msg); // "hello world"

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

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

"use strict"; eval =
"hi"; // causes error

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

Global 对象的属性

Global 对象还包含一些属性,其中一部分属性已经在本书前面介绍过了。例如,特殊的值 undefined、NaN 以及 Infinity 都是Global 对象的属性。此外,所有原生引用类型的构造函数,像 Object 和 Function,也都是 Global 对象的属性。下表列出了Global 对象的所有属性。

「JavaScript Breakthrough」の単一の組み込みオブジェクト

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

window 对象

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

var color = "red"; 
 
function sayColor(){ 
    console.log(window.color); 
} 
 
window.sayColor();  // "red"

JavaScript 中的 window 对象除了扮演规定的 Global 对象的角色外,还承担了很多别的任务。

Math 对象

JavaScript 还为保存数学公式和信息提供了一个公共位置,即 Math 对象。与我们在 JavaScript 直接编写的计算功能相比,Math对象提供的计算功能执行起来要快得多。Math 对象中还提供了辅助完成这些计算的属性和方法。

Math 对象的属性

Math 对象包含的属性大都是数学计算中可能会用到的一些特殊值。下表列出了这些属性。

属性说明

「JavaScript Breakthrough」の単一の組み込みオブジェクト

min() 和 max() 方法

Math 对象还包含许多方法,用于辅助完成简单和复杂的数学计算。其中,min() 和 max() 方法用于确定一组数值中的最小值和最大值。这两个方法都可以接收任意多个数值参数,如下面的例子所示。

var max = Math.max(3, 54, 32, 16); 
 
console.log(max); // 54 
 
var min = Math.min(3, 54, 32, 16); 
 
console.log(min); // 3

要找到数组中的最大或最小值,可以像下面这样使用 apply() 方法。

var values = [1, 2, 3, 4, 5, 6, 7, 8]; 
 
var max = Math.max.apply(Math, values); 
 
console.log(max); // 8

这个技巧的关键是把 Math 对象作为 apply() 的第一个参数,从而正确地设置 this 值。然后,可以将任何数组作为第二个参数。

舍入方法

下面来介绍将小数值舍入为整数的几个方法:Math.ceil()、Math.floor() 和 Math.round()。这三个方法分别遵循下列舍入规则:

Math.ceil() 执行向上舍入,即它总是将数值向上舍入为最接近的整数;

Math.floor() 执行向下舍入,即它总是将数值向下舍入为最接近的整数;

Math.round() 执行标准舍入,即它总是将数值四舍五入为最接近的整数。

下面是使用这些方法的示例:

console.log(Math.ceil(25.9));     // 26 
console.log(Math.ceil(25.5));     // 26 
console.log(Math.ceil(25.1));     // 26 
 
console.log(Math.round(25.9));    // 26 
console.log(Math.round(25.5));    // 26 
console.log(Math.round(25.1));    // 25 
 
console.log(Math.floor(25.9));    // 25 
console.log(Math.floor(25.5));    // 25 
console.log(Math.floor(25.1));    // 25

random() 方法

Math.random() 方法返回介于0和1之间一个随机数,不包括0和1。对于某些站点来说,这个方法非常实用,因为可以利用它来随机显示一些名人名言和新闻事件。套用下面的公式,就可以利用 Math.random() 从某个整数范围内随机选择一个值。

值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

公式中用到了 Math.floor() 方法,这是因为 Math.random() 总返回一个小数值。而用这个小数值乘以一个整数,然后再加上一个整数,最终结果仍然还是一个小数。举例来说,如果你想选择一个1到10之间的数值,可以像下面这样编写代码:

var num = Math.floor(Math.random() * 10 + 1);

总共有10个可能的值(1到10),而第一个可能的值是1。而如果想要选择一个介于2到10之间的值,就应该将上面的代码改成这样:

var num = Math.floor(Math.random() * 9 + 2);

从2数到10要数9个数,因此可能值的总数就是9,而第一个可能的值就是2。多数情况下,其实都可以通过一个函数来计算可能值的总数和第一个可能的值,例如:

function selectFrom(lowerValue, upperValue) { 
    var choices = upperValue - lowerValue + 1; 
    return Math.floor(Math.random() * choices + lowerValue); 
} 
 
var num = selectFrom(2, 10); 
console.log(num);   // 介于2和10之间(包括2和10)的一个数值

函数 selectFrom() 接受两个参数:应该返回的最小值和最大值。而用最大值减最小值再加1得到了可能值的总数,然后它又把这些数值套用到了前面的公式中。这样,通过调用 selectFrom(2,10) 就可以得到一个介于2和10之间(包括2和10)的数值了。利用这个函数,可以方便地从数组中随机取出一项,例如:

var colors = ["red", "green", "blue", "yellow", "black", "purple", "brown"]; 
 
var color = colors[selectFrom(0, colors.length-1)]; 
 
console.log(color); // 可能是数组中包含的任何一个字符串

其他方法

Math 对象中还包含其他一些与完成各种简单或复杂计算有关的方法,但详细讨论其中每一个方法的细节及适用情形超出了本书的范围。下面我们就给出一个表格,其中列出了这些没有介绍到的 Math 对象的方法。

「JavaScript Breakthrough」の単一の組み込みオブジェクト

虽然 ECMA-262 规定了这些方法,但不同实现可能会对这些方法采用不同的算法。毕竟,计算某个值的正弦、余弦和正切的方式多种多样。也正因为如此,这些方法在不同的实现中可能会有不同的精度。

关卡

// 如何高效产生m个n范围内的不重复随机数(m<=n) 
var getRandomNumber = function(n, m){ 
  // 待实现方法体 
} 
console.log(getRandomNumber(20, 3)); // 8,4,19


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