概述
ECMAScript 5.1就是我们常说的es5。它在2012年就已经被公开。时至今日,除了一些较低版本的浏览器,各大主流浏览器都已经实现支持了es5的绝大部分特性。
先上一段代码,体会一下:
<body>
<h2>单项数据绑定:通过修改JS中的数据,页面呈现最新修改的数据信息。这是一种映射关系,把JS数据的变化映射到DOM结构上</h2>
<div id="box">数据单项绑定呈现位置</div>
<input type="text" id="ipt">
</body>
<script src="./js/jquery-1.12.3.min.js"></script>
<script>
// 创建对象
// var obj = {
// des:"把Model的变化映射到DOM结构上"
// }
// 获取元素
// var box = document.getElementById("box");
// // 设置元素的内部文本
// box.innerHTML = obj.des;
// 普通的方式,修改对象的值,查看页面DOM数据变化
// obj.des = "新的数据";//页面不会发生改变,除非通过innerHTML重新写入
// 通过set方法设置单项绑定
// Object.defineProperty(obj,'des',{
// //赋值器
// set:function(value){
// // 当设置或修改新的值时,将最新的值输出到页面
// box.innerHTML = value;
// // 备用属性赋值
// this.oDes = value;
// },
// // 取值器
// get:function(){
// return this.oDes;
// }
// });
// 再次修改以下值试试
// obj.des = "新的值";//发现页面内容更新了
// 现在我们做这样一个修改,页面添加一个输入框,随着输入框内容的输入,上面呈现输入框中的内容,修改如下:
// 创建对象
var obj = {
des:"把Model的变化映射到DOM结构上"
}
// 获取元素
var box = document.getElementById("box");
var ipt = document.getElementById("ipt");
// 设置元素的内部文本
box.innerHTML = obj.des;
Object.defineProperty(obj,'des',{
//赋值器
set:function(value){
// 当设置或修改新的值时,将最新的值输出到页面
box.innerHTML = value;
// 备用属性赋值
this.oDes = value;
},
// 取值器
get:function(){
return this.oDes;
}
});
// 新的值来自于页面输入框 触发正在输入事件
// ipt.oninput = function(){
// if(this.value === ""){
// box.innerHTML = "把Model的变化映射到DOM结构上";
// }else{
// obj.des = this.value;
// }
// }
// 含有输入法时,不能检测中文,改造并使用jQuery(使用js也可)如下:
/**
* 拓展:实现中文输入法下,仅在选词后触发input事件
* 描述:在使用oninput监控输入框内容变化时,我们期望仅在value值变化时,才触发oninput事件,而在中文输入下,未选词时的按键也会触发oninput事件。
* 两个事件:
* compositionstart事件
* compositionend事件
* 实现方式:使用一个变量表示拼写状态,在oninput事件中判断是否在拼写状态,当拼写状态结束,继续执行下一步操作。
* 代码示例如下:
**/
// 定义是否开启输入法的开关 默认关闭
var flag = false;
//oninput在oncompositionend之前执行,需加定时器
ipt.oninput = function(){
this.addEventListener('compositionstart',function(){//中文开始书写
flag = true;//检测到中文输入法开启,设为true
})
this.addEventListener('compositionend',function(){//中文书写完毕,选取文字完毕
flag = false;//输入完毕,设置false
})
setTimeout(function() {
if(!flag) {//保证输入法没有开启也能正常获取数据
if(ipt.value === ""){
box.innerHTML = "把Model的变化映射到DOM结构上";
}else{
obj.des = ipt.value;
}
}
},0);
}
</script>
一、严格模式
1.1 基本概述
除了正常的运行模式(混杂模式),ES5中添加了第二种运行模式:“严格模式”(strict mode) 顾名思义,这种模式,使得JavaScript在更严格的语法下运行 "严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。 另一方面,同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。掌握这些内容,有助于更细致深入地理解Javascript,让你变成一个更好的程序员
1.2 设置严格模式的目的
消除JavaSript语法的一些不合理,不严谨之处,减少一些怪异的行为 消除代码运行的一些不安全之处,为代码的安全运行保驾护航 提高编译器效率,增加运行速度 为未来新版本的JavaScript做好铺垫
1.3 如何使用
在全局 或 函数内部,第一条语句定义为
“use strict”;
如果浏览器不支持,只会解析为一条普通的字符串语句,加以忽略,不会有任何副作用 如果这行语句不在第一行,则无效,整个脚本以"正常模式"运行。
1.4 语法和行为改变
1.4.1 必须使用var声明变量
在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,全局变量必须显式声明。
a = 100;
//非严格模式下,输出 a: 100
//严格模式下,a没有声明,抛出一个错误 Error: a is not defined
console.log("a:",a);
1.4.2 禁止使用八进制数
var num4 = 076;//八进制标识 0
//非严格模式下,使用八进制没有任何位置
//严格模式下,不支持八进制 报错SyntaxError: Octal literals are not allowed in strict mode.
1.4.3 禁止使用arguments.callee
在函数内部,有两个特殊的对象:arguments 和 this。其中, arguments 的主要用途是保存函数参数,但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。 但在严格模式下,是被禁止使用的。 如下,实现阶乘的递归调用
function factorial(num){
if(num == 1){
return 1;
}else{
// return num * factorial(num - 1);//原来阶乘方式
//非严格模式下,使用arguments.callee()指向拥有这个arguments对象的函数
//严格模式下禁止使用 报错TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
return num * arguments.callee(num - 1);
}
}
1.4.4 禁止使用 delete 删除变量
delete常用于删除对象中的属性;如果使用delete删除一个变量,在正常模式下可以执行通过,但不会删除成功;在严格模式下是禁止这样使用的
// 定义变量a
var a = 100;
// 定义window全局对象的变量b
window.b = 200;
// 以上两个都属于全局变量
// 删除操作
// 非严格模式下,可以删除window对象的全局变量b,但是不能删除使用var声明的全局变量a,不会报错
// 严格模式下,禁止使用delete删除变量,一旦使用就会报错:SyntaxError: Delete of an unqualified identifier in strict mode
delete a;
delete b;
1.4.5 禁止自定义函数中的this指向window
(function fn(){
//非严格模式下,普通函数中的this指向window
//严格模式下,普通函数中的this不再指向window 返回undefined
console.log(this);
})();
1.4.6 创建 eval 作用域,即:块级作用域
正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。 正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部使用
eval("var x = 10;");
// 非严格模式下,x为10
// 严格模式下,x没有声明,抛出一个错误 Error: s is not defined
alert(x);
任意由eval()创建的变量或函数仍呆在eval()里。然而,你可以通过从eval()中返回一个值的方式实现值的传递:
var result = eval("var a = 10,b = 20;a + b");
// 严格模式与非严格模式下都能正常工作(得到30)
console.log("result:",result);//result: 30
1.4.7 width作用域
with(target){}方法: 正常模式下:如果添加了tatget对象,它会把这个对象,当作with要执行的代码体的作用域的最顶端,也就是with会改变作用域链。 作用域链是经过很复杂的情况生成的结构,作用域链改了之后,系统内核会消耗大量的效率去更改作用域链,是会把程序变得非常慢的。 所以,在ES5严格模式下,with方法就不可以再使用了。
"use strict";
var num = 10;
var obj = {
name:"张三",
num:100
}
fn()
function fn(){
var num = 1000;
// console.log(num);//1000
// with(window){
// console.log(num);//10
// }
with(obj){
console.log(num);//100
var score = 99;
console.log(score);//99
}
console.log(score);//99
}
// console.log(score);//Error: score is not defined width(){}中声明的不存在的变量的作用域由它所在的那个作用域决定
// 严格模式下不支持 width(){} 报错 SyntaxError: Strict mode code may not include a with statement
1.4.8 对象不能有重名的属性
正常模式下,如果对象有多个重名属性,最后赋值的那个属性会覆盖前面的值。严格模式下,这属于语法错误(但是程序目前检测不出来)。
var obj = {a:10,a:100}
1.4.9 函数不能有重名的参数
正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
"use strict";
//严格模式下报错 Error: Duplicate parameter name not allowed in this context
function fn(a,a,b){
return;
}
1.4.10 保留字
为了向将来Javascript的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。 使用这些词作为变量名将会报错。
//非严格模式下不会报错
//严格模式下报错 Error: Unexpected strict mode reserved word
var let = 10;
此外,ECMAscript第五版本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的const保留字,也是不能作为变量名的。
注意:经过测试 IE6,7,8,9 均不支持严格模式
二、提供全局的JSON对象
序列化和反序列化概念: (1)序列化:将内存中的对象转化为字节序列,用于持久化到磁盘中或者通过网络传输。对象序列化的最主要的用处就是传递和保存对象,保证对象的完整性和可传递性。 序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了对象的状态以及相关的描述信息。序列化机制的核心作用就是 对象状态的保存与重建。 (2)反序列化:从字节序列创建对象的过程称为反序列化。序列化对象和平台无关,序列化得到的字节流可以在任何平台反序列化。从文件中或网络上获得序列化的字节流后, 根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。
2.1 JSON.stringify( ) 对象的序列化,js对象(数组)转换为json对象(数组)
JSON.stringify(obj/arr,callbackfn) 参数:obj 必需;要处理的对象 callbackfn 可选;回调函数,函数中有两个参数如下: 第一个参数:属性名 第二个参数:属性值
// 需求一:对象转JSON串的过程中,将 数字字符串 作为 数字保留
//定义对象
var obj = {
a:1,
b:'2',
c:{
d:3
}
}
//对象转JSON串 JSON.stringify()
var result = JSON.stringify(obj,function(key,value){
// 对value进行判断
if(typeof value === "string"){
// 是字符串数字,通过 正(+)运算符转为纯数值
return +value;//这里 + 是 正负的正符号 数学运算 转为数值
}
return value;
});
console.log(result,"数据类型:",typeof result);//{"a":1,"b":2,"c":{"d":3}} 数据类型: string
2.2 JSON.parse( ) 对象的反序列化,json对象(数组)转换为js对象(数组)
JSON.parse(json,callbackfn) 参数:str 必需;要处理的json字符串 callbackfn 可选;回调函数,函数中有两个参数如下: 第一个参数:属性名 第二个参数:属性值
// 需求2:JSON串转对象过程中,将 数字字符串 转为 数字
// 创建JSON串
var jsonStr = '{"a":1,"b":"2","c":{"d":3}}';
// JSON串转对象 JSON.parse()
var result2 = JSON.parse(jsonStr,function(key,value){
// 将 数字字符串 转为 数字
if(typeof value === "string"){
return +value;
}
return value;
});
console.log(result2,"数据类型:",typeof result2);//a: 1, b: 2, c: {…}} "数据类型:" "object"