>  기사  >  웹 프론트엔드  >  'Javascript Advanced 프로그래밍'에 대한 심층적인 이해

'Javascript Advanced 프로그래밍'에 대한 심층적인 이해

零下一度
零下一度원래의
2017-07-18 16:04:391596검색

이 책 "고급 자바스크립트 프로그래밍"은 내용이 많고 두껍습니다. 시간이 없는 사람들도 이 발췌문 시리즈를 읽고 책의 핵심 내용을 전반적으로 배울 수 있기를 바랍니다.

 녹색 배경의 콘텐츠가 오리지널 콘텐츠라 더 주목받는 것 같아요.

  노란색 배경의 콘텐츠는 제가 매우 중요하게 생각하는 원본 콘텐츠입니다.

 내가 이해한 내용은 파란색 글꼴로 표시하겠습니다.

이 장은 내용이 많고 상대적으로 중요하며 두 부분으로 나누어 기록됩니다.

  5.5.4 함수의 내부 속성

  함수 내부에는 두 가지 특수 개체인 인수와 this가 있습니다. 그 중 인수(Arguments)는 3장에서 소개되었습니다. 함수에 전달되는 모든 매개변수를 포함하는 배열형 객체입니다. 인수의 주요 목적은 함수 매개변수를 저장하는 것이지만 이 개체에는 인수 개체를 소유한 함수에 대한 포인터인 호출 수신자 속성도 있습니다. 아래의 아주 고전적인 계승 함수를 살펴보세요

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

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

}

}

 재귀 알고리즘은 일반적으로 함수에 이름이 있고 이름이 변경되지 않는 경우 위 코드와 같이 계승 함수를 정의하는 데 사용됩니다. 미래, 이 정의에는 문제가 없습니다. 하지만 문제는 이 함수의 실행이 함수 이름인 계승(factorial)과 밀접하게 결합되어 있다는 것입니다. 이러한 긴밀한 결합을 제거하기 위해 Arguments.callee를 다음과 같이 사용할 수 있습니다.

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

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

}

}
코드 보기
이 재작성된 계승() 함수의 함수 본문에서 함수 이름 계승은 더 이상 인용되지 않습니다. 이런 식으로

함수를 참조할 때 어떤 이름을 사용하더라도 재귀 호출이 정상적으로 완료되도록 보장할 수 있습니다. 예:

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()는 바인딩()을 호출하고 객체 o를 전달하여 objectSayColor() 함수를 생성합니다. object

SayColor() 함수의 this 값이 o와 같으므로 전역 범위에서 이 함수를 호출하더라도 "blue"가 표시됩니다. 이 기술의 장점에 대해서는 22장을 참조하십시오.

bind() 메소드를 지원하는 브라우저는 IE9+, Firefox 4+, Safari 5.1+, Opera 12+ 및 Chrome입니다.

각 함수에서 상속된 toLocaleString() 및 toString() 메서드는 항상 함수의 코드를 반환합니다. 반환 코드의 형식은 브라우저마다 다릅니다. 일부는 소스 코드의 함수 코드와 동일한 코드를 반환하는 반면 다른 일부는 함수 코드의 내부 표현을 반환합니다. 즉, 파서가 주석을 제거하고 수정된 코드를 수정합니다. . 이러한 차이점으로 인해 이 두 메서드에서 반환된 결과를 기반으로 중요한 작업을 수행할 수는 없지만 이 정보는 코드를 디버깅할 때 유용할 수 있습니다. 또 다른 상속된 valueOf() 메서드도 함수 코드만 반환합니다.

5.6 기본 패키징 유형

 기본 유형 값의 작업을 용이하게 하기 위해 ECMAScript는 Boolean, Number 및 String의 3가지 특수 참조 유형도 제공합니다. 이러한 유형은 이 장에 소개된 다른 참조 유형과 유사하지만 해당 기본 유형에 해당하는 특별한 동작도 있습니다. 실제로 기본 유형 값을 읽을 때마다 해당 기본 래퍼 유형 개체가 백그라운드에서 생성되어 이 데이터에 대해 작업할 몇 가지 메서드를 호출할 수 있습니다. 다음 예를 고려하십시오.

var s1 = "some text";

var s2 = s1.substring(2);

 이 예제의 변수 s1에는 물론 기본 유형 값인 문자열이 포함되어 있습니다. 다음 줄에서는 s1의 substring() 메서드를 호출하고 반환된 결과를 s2에 저장합니다. 우리는 기본 유형 값이 객체가 아니라는 것을 알고 있으므로 논리적으로 메서드를 가져서는 안 됩니다(물론 우리가 원하는 대로 메서드가 있지만). 실제로 이러한 직관적인 작업을 달성하기 위해 일련의 프로세스가 백그라운드에서 자동으로 완료되었습니다. 코드의 두 번째 줄이 s1에 액세스하면 액세스 프로세스가 읽기 모드에 있습니다. 즉, 이 문자열의 값을 메모리에서 읽어야 합니다. 읽기 모드에서 문자열에 접근하면 백그라운드에서 다음 처리가 자동으로 완료됩니다.

(1) 문자열 유형의 인스턴스를 생성합니다.

(2) 인스턴스에서 지정된 메서드를 호출합니다.

(3) 이 인스턴스를 삭제합니다.

위의 세 단계를 다음 ECMAScript 코드를 실행하는 것으로 상상할 수 있습니다.

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

var s2 = s1.substring(2);

s1 = null;

이 처리 후 기본 문자 String 가치는 물건처럼 된다. 또한 위의 세 단계는 각각 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를 정의합니다.

5.7.1 Global Object

Global(전역) 객체는 ECMAScript에서 가장 특별한 객체라고 할 수 있습니다. 어느 각도에서 보더라도 이 객체는 존재하지 않기 때문입니다. ECMAScript의 Global 객체는 어떤 의미에서는 궁극적인 "포괄 객체"로 정의됩니다. 즉, 다른 개체에 속하지 않는 속성과 메서드는 궁극적으로 해당 개체의 속성과 메서드입니다. 실제로 전역 변수나 함수는 없습니다. 전역 범위에 정의된 모든 속성과 함수는 Global 개체의 속성입니다. 이 책의 앞부분에서 소개한 isNaN(), isFinite(),parseInt(),parseFloat() 등의 함수는 실제로 모두 Global 개체의 메서드입니다. 이 외에도 Global 개체에는 몇 가지 다른 메서드도 포함되어 있습니다.

1. URI 인코딩 방법

전역 객체의 encodeURI() 및 encodeURIComponent() 메서드는 브라우저에 보내기 위한 URI(Uniform Resource

식별자)를 인코딩할 수 있습니다. 공백과 같은 특정 문자는 유효한 URI에 포함될 수 없습니다. 이 두 가지 URI 인코딩 방법은 브라우저가 이를 받아들이고 이해할 수 있도록 모든 유효하지 않은 문자를 특수 UTF-8 인코딩으로 대체합니다.

2.eval() 메소드

이제 마지막 메소드인 eval()을 소개합니다. 아마도 전체 ECMAScript 언어에서 가장 강력한 메소드일 것입니다. eval() 메소드는 완전한 ECMAScript 파서와 유사하며 실행할 ECMAScript(또는 JavaScript) 문자열이라는 하나의 매개변수만 허용합니다. 다음 예를 살펴보십시오.

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

이 코드 줄은 다음 코드 줄과 동일합니다.

alert("hi");

파서는 코드에서 eval() 메서드가 호출된 것을 발견하면 들어오는 매개 변수를 실제 ECMAScript 문으로 구문 분석한 다음 실행 결과를 원래 위치에 삽입합니다. eval()을 통해 실행되는 코드는 호출을 포함하는 실행 환경의 일부로 간주되므로 실행되는 코드는 해당 실행 환경과 동일한 범위 체인을 갖습니다. 이는 eval()을 통해 실행된 코드가 포함 환경에 정의된 변수를 참조할 수 있음을 의미합니다. 예:

var msg = "hello world";

eval("alert(msg)") //" hello world"

msg 변수는 eval()이 호출되는 환경 외부에서 정의되었지만 거기에서 호출된 Alert()는 여전히 "hello world"를 표시할 수 있음을 알 수 있습니다. 이는 위의 두 번째 코드 줄이 결국 실제 코드 줄로 대체되기 때문입니다. 마찬가지로 eval() 호출에서 함수를 정의한 다음 호출의 외부 코드에서 해당 함수를 참조할 수도 있습니다.

eval("function sayHi() { Alert('hi'); }" );

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에서 지정한 전역 개체의 역할을 수행하는 것 외에도 JavaScript의 창 개체는 다른 많은 작업도 수행합니다. 윈도우 객체는 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().

이 세 가지 메소드는 각각 다음 반올림 규칙을 따릅니다.

Math.ceil()은 상향 반올림을 수행합니다. 즉, 항상 값을 가장 가까운 정수로 반올림합니다. 반올림을 수행합니다. 즉, 항상 값을 가장 가까운 정수로 내림합니다.

Math.round()는 표준 반올림을 수행합니다. 즉, 항상 값을 가장 가까운 정수로 내림합니다(이것은 우리가 배운 반올림 규칙이기도 합니다. 수학 시간에).

4.random() 메소드

Math.random() 메소드는 0보다 크거나 같고 1보다 작은 난수를 반환합니다. 일부 사이트의 경우 이 방법은 유명한 인용문과 뉴스 이벤트를 무작위로 표시하는 데 사용할 수 있으므로 매우 실용적입니다. 다음 공식을 적용하면 Math.random()을 사용하여 특정 정수 범위에서 값을 무작위로 선택할 수 있습니다.

값 = Math.floor(Math.random() * 가능한 값의 총 개수 + 첫 번째 가능한 값)

5. 기타 방법

5.8 요약

객체는 JavaScript에서 참조 유형 값이라고 하며 특정 객체를 생성하는 데 사용할 수 있는 몇 가지 내장 참조 유형이 있습니다. 간략하게 요약하면 다음과 같습니다.

참조 유형은 기존 객체의 클래스와 유사합니다. 지향적인 프로그래밍이지만 구현은 다릅니다.

Object는 기본 유형이고 다른 모든 유형은 Object에서 기본 동작을 상속합니다.

Array 유형은 값 집합의 순서가 지정된 목록이며 이러한 값을 조작하고 변환하는 기능도 제공합니다. 유형은 현재 날짜 및 시간과 관련 계산 기능을 포함하여 날짜 및 시간에 대한 정보를 제공합니다.

RegExp 유형은 정규식을 지원하는 ECMAScript용 인터페이스로, 가장 기본적이고 일부 고급 정규식 기능을 제공합니다.

함수는 실제로 Function 유형의 인스턴스이므로 함수도 객체이며 이는 JavaScript의 가장 독특한 특징입니다. 함수는 객체이기 때문에 동작을 향상시키는 데 사용할 수 있는 메서드도 있습니다.

기본 래퍼 유형이므로 JavaScript의 기본 유형 값은 객체로 접근할 수 있습니다. 세 가지 기본 래퍼 유형은 Boolean, Number 및 String입니다. 다음은 공통 특성입니다.

각 래퍼 유형은 동일한 이름을 가진 기본 유형에 매핑됩니다.

기본 유형 값이 읽기 모드에서 액세스되면 해당 기본 래퍼 유형의 개체가 생성됩니다.

기본 유형 값에 대해 작동하는 명령문이 실행되면 새로 생성된 패키징 개체가 즉시 삭제됩니다.

모든 코드가 실행되기 전에 두 개의 내장 개체가 이미 범위에 존재합니다: 전역 및 수학. Global 개체는 대부분의 ECMAScript 구현에서 직접 액세스할 수 없지만 웹 브라우저는 이 역할을 맡은 창 개체를 구현합니다. 전역 변수와 함수는 전역 개체의 속성입니다. Math 개체는 복잡한 수학 계산 작업을 완료하는 데 도움이 되는 다양한 속성과 메서드를 제공합니다.

위 내용은 'Javascript Advanced 프로그래밍'에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.