说到ES6 我们先来延申一下ES5
ES5 (ECMAScript 第五个版本)
-
严格模式
在当前作用域的顶部添加 "use strict" 在当前作用域内的代码都以严格模式运行
新增要求:
① 禁止给未声明的变量赋值,否则会报错
(js中可以给未声明的变量赋值,并不报错但是会造成内存泄漏和全局污染)
② 静默失败升级为错误
静默失败:执行不成功 也不报错。
③ 普通函数调用和匿名函数自调中的this不在指向window,而是underfined
④ 禁用了arguments.callee()递归函数:在函数内获得当前正在执行的函数自己
因为递归函数效率极低不推荐使用 可以的情况下 用循环代替递归
//斐波那契数列
// 1月 2月 3月 4月 5月
// 1对 1对 2对 3对 5对
// 第三个月开始,前两个月的和 2+3=5
// f(1)=1 f(2)=2 f(n)=f(n-1)+f(n-2)
//递归函数
f(n){
//获得正在执行的函数对象自己,而不要写死当前函数名(f())
var fun = arguments.callee
if( n<3 ){
return 1
}else{
// return f(n-1)+f(n-2)
//用arguments.callee()自动获得当前函数对象,执行下一轮递归,就相当于return arguments.callee(n-1)+arguments.callee(n-2)
return fun(n-1)+fun(n-2)
}
}
console.log(f(10))
-
保护对象
什么是保护对象? 就是阻止程序对一个对象执行不符合规定的修改
在旧的js中 对象可以被肆意修改 假如 年龄为-2 用户名被篡改 等情况所以就要 保护对象
两个层面的保护:
① 保护单个属性:
阻止对对象中某个属性执行不合常理的修改
② 保护对象结构:
阻止添加删除属性
es5对对象的属性 也进行了分类 命名属性 和 内部属性
① 命名属性:
那么如何修改属性(就是如何打开关闭一个属性内的开关)?
错误:LiLei.sname.writeable=false
正确: 用专门的函数进行修改
Object.defineProperty(对象,“属性名”,{
开关名:true/false
writable:false,
... : true/false,
//修改指定对象的 指定属性名的开关为true或false
})
//定义一个对象 尝试对他的属性值进行修改
var LiLei = {
sname:"Li Lei",
sage:19,
className:"高三二班"
}
//尝试修改LiLei的名字
LiLei.sname = "Li xiao Lei"
//尝试删除LiLei的年龄
delete LiLei.sage
console.log(LiLei)
//但是往往在实际生活中 一些属性是不能随意改变的 比如说名字不能随便修改 就要做到保护属性
//希望LiLei的名字 只读
//错误做法 :LiLei.sanme.writable =false
//正确做法 :
Object.defineProperty(LiLei ,"sanem",{
writable:false , //修改writable属性为不可修改 也就是只读
configurable:false //通常修改前两个开关时候,要先操作第三个开关 ---双保险,
//但是一旦configurable:false 就不可逆 再也改不回true了
})
//希望 LiLei的sage属性不能被删除
Object.defineProperty(LiLei ,"sage",{
//既控制属性是否可删除 //又控制是否可修改前两个属性
configurable:false
})
//希望 LiLei的className属性不能被for in 遍历
// 但是该属性只能不被for in遍历,但是还可以用.进行访问 (js的bug)
Object.defineProperty(LiLei ,"className",{
enumerable:false,
configurable:false
})
console.log(LiLei.className) //依然可以访问到
问题:Object.defineProperty(对象,“属性名”,{xxxx}) 该方法一次只能修改一个属性的开关,造成代码冗余
更好的方法:
Object.defineProperties(对象,{
属性名:{
开关:true/false,
... : ...,
},
属性名:{
开关:true/false,
... : ...,
},
........
})
var LiLei ={
sanme:"Li Lei",
sage:19,
className:"高三二班"
}
//一次修改多个 代码简洁
Object.defineproperties(LiLei,{
sanme:{
wtitable:false,
configurable:false
},
sage:{
configurable:false
},
className:{
enumerable:false
configurable:false
}
})
① 内部属性:
如果想自定义属性 或者是自定义规则的时候就要用到访问器属性get set
什么是访问器属性?
给程序的属性 请的保镖
访问器属性不实际存储属性值,仅提供对另一个保存数据的属性的保护
如何使用访问器属性?
①定义访问器属性 保护另一个保存数据的属性 (请保镖)
②通过访问器属性来操作受保护的数据属性
访问器属性的用法与普通的数据属性一样!
获得属性值:对象.访问器属性 (访问器属性会自动调用自己的get())
修改属性值:对象.访问器属性=新值 (访问器属性会自动调用自己的set())
var LiLei ={ sanme:"Li Lei", className:"高三二班", // sage : 19, //1. 首先 伪装一个 隐姓埋名的sage _sage : 19, } Object.defineProperties(LiLei ,{ _sage :{ //2. 其次 半隐藏 enumerable:false ,//控制属性不被for in 遍历到 configurable:false, } //3. 然后 请保镖 来保护该属性 sage:{ //该保镖来冒名顶替真实的 其中保镖包含两个 set() 和 get() get:function(){ console.log("自动调用LiLei的get()") return this._sage; //返回受保护的属性_sage的值 }, set:function(value){ console.log(`自动调用LiLei的set(${value})`) if(value>18 && value<=65){ this._sage = value; }else{ throw Error(`年龄必须在18~65之间 才符合!`) } }, enumerable:true, //让sage代替_sage 抛头露面 configurable:false //不能轻易删除保镖 //因为保镖不实际存储属性值 只是起到虚晃一枪的作用 所以没有value属性 也没有那些开关 } }) //当有用户试图读取LiLei的年龄时 console.log(LiLei.sage) //访问和之前一样只是在执行过程中有个替身保镖来保护 //当有用户试图修改 LiLei的年龄时 LiLei.sage = 26; console.log(LiLei.sage) LiLei.sage = -2; console.log(LiLei.sage)
![]()