我是小又又,住在武汉,做了两年新媒体,准备用 6 个月时间转行前端。
今日学习目标
昨天基于搜索来基础学习 RegExp
断言。今天主要是基于搜索来学习 Global
对象中的编码方法和eval
方法,又是适合学习的一天,加油,小又又!!!!
今日学习概要
- URI 编码方法
- eval()
URI 编码方法
decodeURI()
基础语法
decodeURI(encodedURI)
参数说明
- encodedURI
一个完整的编码过的 URI
返回值说明
返回一个给定编码统一资源标识符(URI)的未编码版本的新字符串。
异常
当encodedURI
包含无效字符序列时,引发URIError
(“格式错误的 URI 序列”)异常。
详细说明
decodeURI()
函数能解码由encodeURI
创建或其它流程得到的统一资源标识符(URI)。
将已编码 URI
中所有能识别的转义序列转换成原字符,但不能解码那些不会被 encodeURI
编码的内容(例如 "#")。
案例
解码一个西里尔字母(Cyrillic)URL
decodeURI("https://developer.mozilla.org/ru/docs/JavaScript_%D1%88%D0%B5%D0%BB%D0%BB%D1%8B");
// "https://developer.mozilla.org/ru/docs/JavaScript_шеллы"
捕捉异常
try {
var a = decodeURI('%E0%A4%A');
} catch(e) {
console.error(e);
}
// URIError: malformed URI sequence
decodeURIComponent()
基础语法
decodeURIComponent(encodedURI)
参数说明
- encodedURI
编码后的部分 URI
返回值说明
一个解码后的统一资源标识符(URI)字符串,处理前的 URI 经过了给定格式的编码。
异常
当该方法使用不当时,将会抛出一个 URIError(“格式错误的 URI 序列”)异常。
详细说明
decodeURIComponent()
方法用于解码由 encodeURIComponent
方法或者其它类似方法编码的部分统一资源标识符(URI)。
案例
解码一个西里尔字母的 URL
decodeURIComponent("JavaScript_%D1%88%D0%B5%D0%BB%D0%BB%D1%8B");
// "JavaScript_шеллы"
捕捉异常
try {
var a = decodeURIComponent('%E0%A4%A');
} catch(e) {
console.error(e);
}
// URIError: malformed URI sequence
encodeURI()
基础语法
encodeURI(URI)
参数说明
- URI
一个完整的 URI.
返回值说明
一个新字符串, 表示提供的字符串编码为统一资源标识符 (URI)。
基础说明
encodeURI()
函数通过将特定字符的每个实例替换为一个、两个、三或四转义序列来对统一资源标识符 (URI) 进行编码 (该字符的 UTF-8 编码仅为四转义序列)由两个 "代理" 字符组成)。
转译详细说明
假定一个URI
是完整的URI
,那么无需对那些保留的并且在 URI 中有特殊意思的字符进行编码。
http://username:password@www.example.com:80/path/to/file.php?foo=316&bar=this+has+spaces#anchor
encodeURI
会替换所有的字符,但不包括以下字符,即使它们具有适当的 UTF-8
转义序列:
类型 | 包含 |
---|---|
保留字符 | ; , / ? : @ & = + $ |
非转义的字符 | 字母 数字 - _ . ! ~ * ' ( ) |
数字符号 | # |
请注意,encodeURI
自身无法产生能适用于 HTTP GET
或 POST
请求的URI
,例如对于 XMLHTTPRequests
, 因为 "&", "+", 和 "=" 不会被编码,然而在 GET
和 POST
请求中它们是特殊字符。
然而encodeURIComponent
这个方法会对这些字符编码。
另外,如果试图编码一个非高-低位
完整的代理字符,将会抛出一个 URIError
错误,例如:
// 编码高-低位完整字符 ok
console.log(encodeURI('\uD800\uDFFF'));
// 编码单独的高位字符抛出 "Uncaught URIError: URI malformed"
console.log(encodeURI('\uD800'));
// 编码单独的低位字符抛出 "Uncaught URIError: URI malformed"
console.log(encodeURI('\uDFFF'));
并且需要注意,如果URL
需要遵循较新的RFC3986
标准,那么方括号是被保留的(给IPv6
),因此对于那些没有被编码的URL
部分(例如主机),可以使用下面的代码:
function fixedEncodeURI (str) {
return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']');
}
encodeURIComponent()
基础语法
encodeURIComponent(str);
参数说明
- str
String. URI 的组成部分。
返回值说明
原字符串作为URI
组成部分被编码后形成的字符串。
详细说明
encodeURIComponent()
是对统一资源标识符(URI)的组成部分进行编码的方法。它使用一到四个转义序列来表示字符串中的每个字符的UTF-8编码(只有由两个Unicode代理区字符组成的字符才用四个转义字符编码)。
转译详细说明
encodeURIComponent
转义除了以下字符外的所有字符:
不转义的字符:
A-Z a-z 0-9 - _ . ! ~ * ' ( )
转译不同点
encodeURIComponent()
和 encodeURI
有以下几个不同点:
var set1 = ";,/?:@&=+$"; // 保留字符
var set2 = "-_.!~*'()"; // 不转义字符
var set3 = "#"; // 数字标志
var set4 = "ABC abc 123"; // 字母数字字符和空格
console.log(encodeURI(set1)); // ;,/?:@&=+$
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // #
console.log(encodeURI(set4)); // ABC%20abc%20123 (the space gets encoded as %20)
console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // %23
console.log(encodeURIComponent(set4)); // ABC%20abc%20123 (the space gets encoded as %20)
注意,如果试图编码一个非高-低位
完整的代理字符,将会抛出一个 URIError
错误,例如:
// 高低位完整
alert(encodeURIComponent('\uD800\uDFFF'));
// 只有高位,将抛出"URIError: malformed URI sequence"
alert(encodeURIComponent('\uD800'));
// 只有低位,将抛出"URIError: malformed URI sequence"
alert(encodeURIComponent('\uDFFF'));
为了避免服务器收到不可预知的请求,对任何用户输入的作为URI
部分的内容你都需要用encodeURIComponent
进行转义。
比如,一个用户可能会输入"Thyme &time=again"作为comment
变量的一部分。
如果不使用encodeURIComponent
对此内容进行转义,服务器得到的将是comment=Thyme%20&time=again
。
请注意,"&"符号和"="符号产生了一个新的键值对,所以服务器得到两个键值对(一个键值对是comment=Thyme
,另一个则是time=again
),而不是一个键值对。
对于 application/x-www-form-urlencoded (POST)
这种数据方式,空格需要被替换成 '+',所以通常使用 encodeURIComponent
的时候还会把 "%20" 替换为 "+"。
为了更严格的遵循 RFC 3986
(它保留 !
, '
, (
, )
, 和 *)
,即使这些字符并没有正式划定 URI
的用途,下面这种方式是比较安全的:
function fixedEncodeURIComponent (str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
案例
下面这个例子提供了 UTF-8
下 Content-Disposition
和 Link
的服务器响应头信息的参数(例如 UTF-8
文件名)
var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''"
+ encodeRFC5987ValueChars(fileName);
console.log(header);
// 输出 "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"
function encodeRFC5987ValueChars (str) {
return encodeURIComponent(str).
// 注意,仅管 RFC3986 保留 "!",但 RFC5987 并没有
// 所以我们并不需要过滤它
replace(/['()]/g, escape). // i.e., %27 %28 %29
replace(/\*/g, '%2A').
// 下面的并不是 RFC5987 中 URI 编码必须的
// 所以对于 |`^ 这3个字符我们可以稍稍提高一点可读性
replace(/%(?:7C|60|5E)/g, unescape);
}
eval()
基础语法
eval(string)
参数说明
- string
一个表示 JavaScript
表达式、语句或一系列语句的字符串。表达式可以包含变量与已存在对象的属性。
如果字符串表示的是表达式,eval()
会对表达式进行求值。
如果参数表示一个或多个 JavaScript
语句,那么eval()
就会执行这些语句。
算术表达式
如果你以字符串的形式构造了算术表达式,那么可以在后面用 eval()
对它求值。
例如,假设你有一个变量 x
,可以通过将表达式的字符串值(例如 3 * x + 2
)赋值给一个变量,然后在你的代码后面的其他地方调用 eval()
,来推迟涉及 x
的表达式的求值。
参数不是字符串
如果 eval()
的参数不是字符串,eval()
会将参数原封不动地返回。在下面的例子中,String 构造器被指定,而 eval()
返回了 String 对象而不是执行字符串。
eval(new String("2 + 2")); // 返回了包含"2 + 2"的字符串对象
eval("2 + 2"); // returns 4
你可以使用一些通用的方法来绕过这个限制,例如使用 toString()
。
var expression = new String("2 + 2");
eval(expression.toString());
返回值说明
返回字符串中代码的返回值。如果返回值为空,则返回 undefined
。
详细说明
eval()
是全局对象的一个函数属性,会将传入的字符串当做 JavaScript
代码进行执行。
不需要用 eval()
来执行一个算术表达式:因为 JavaScript
可以自动为算术表达式求值。
间接的使用 eval()
如果你间接的使用 eval()
,比如通过一个引用来调用它,而不是直接的调用 eval
。
从 ECMAScript 5
起,它工作在全局作用域
下,而不是局部作用域
中。
这就意味着,例如,下面的代码的作用声明创建一个全局函数,并且 eval
中的这些代码在执行期间不能在被调用的作用域
中访问局部变量。
function test() {
var x = 2, y = 4;
console.log(eval('x + y')); // 直接调用,使用本地作用域,结果是 6
var geval = eval; // 等价于在全局作用域调用
console.log(geval('x + y')); // 间接调用,使用全局作用域,throws ReferenceError 因为`x`未定义
(0, eval)('x + y'); // 另一个间接调用的例子
}
避免使用eval()
eval()
是一个危险的函数, 它使用与调用者相同的权限执行代码。如果你用 eval()
运行的字符串代码被恶意方(不怀好意的人)修改,您最终可能会在网页/扩展程序的权限下,在用户计算机上运行恶意代码。
更重要的是,第三方代码可以看到某一个 eval()
被调用时的作用域,这也有可能导致一些不同方式的攻击。
相似的 Function
就不容易被攻击。
eval()
通常比其他替代方法更慢,因为它必须调用 JS 解释器,而许多其他结构则可被现代 JS 引擎进行优化。
案例
在下面的代码中,两种包含了 eval()
的声明都返回了 42。第一种是对字符串 "x + y + 1" 求值;第二种是对字符串 "42" 求值。
var x = 2;
var y = 39;
var z = "42";
eval("x + y + 1"); // returns 42
eval(z); // returns 42
今日学习总结
今日心情
今天主要是基于搜索来学习 Global
对象中的编码方法和eval
方法, 希望明天学到更多的内容~~~~
本文使用 mdnice 排版