【前端18_JS】ES 6:箭头函数、处理错误、数据结构 Set、WeakSet、数据类型 Symbol、魔术字符
文章目录
- 箭头函数
- 参数
- 参数默认值
- 用法 & 问题
- 与 this 的联系
- 缺点
- 处理错误
- 数据结构:set
- 规则
- 长度
- 增加元素
- 删元素
- 查找元素
- 遍历
- 清空
- 曲线救国实现 map 方法
- 数组去重
- 求两个 set 元素的交集
- WeakSet
- 数据类型 Symbol
- 取值
- Symbol.for()
- 取 ‘ 描述 ’
- 魔术字符
- 深入理解 Object 和 Map
- Object
- Map
箭头函数
参数
- 最简单的箭头函数:一个形参可以不用括号
var f = v => v;console.log(f(1));//1//这就等同于var f = function (v) {console.log(v)};f();
- 函数如果没有形参,需要加括号
var f1 = () => 5;console.log(f1());//5
- 多参数也需要加括号
var f2 = (a,b) => a + b;console.log(f2(3,4));//7
- 箭头函数里没有
arguments,可以...rest来接过来
let fn = (...arg)=>{console.log('arg',arg); // arg (4) [1, 2, 3, 4]// console.log(arguments);
}
function fn1(){console.log(arguments); // Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
fn(1,2,3,4)
fn1(1,2,3,4)
参数默认值
箭头函数里的默认值可以写在参数里
function fn() {// 以前设置默认值麻烦,而且有风险,如果a = 0,就走后面了// 比较严谨一点可以些成 typeof a === undefined ? 1 : aa = a || 1;b = b || 2;return a + b;
}
// es6 的箭头函数的默认值可以写成这样
let fnES6 = (a = 1, b = 2) => {return a + b;
};
console.log(fnES6(10,20)); // 30
console.log(fnES6()); // 3
用法 & 问题
- 箭头函数不能直接返回对象,他会当作代码块去处理,解决方法:在对象外 套上圆括号 即可
//不能直接返回对象 //解决:在对象外加 ()var f3 = hi => ({name:"小强",age:18});console.log(f3(1));//{name: "小强", age: 18}
- 函数如果没有返回值,打印的是
undefined
let {log:l} = console;var f4 = () => {};l(f4());//undefined
- 把很多实参捏到一起,变成真正的数组,用
...arr,也叫做rest
let {log:l} = console;var f5 = (...arr) => arr;l(f5(1,2,'33',4,"5"));//(5) [1, 2, "33", 4, "5"]
- 和
map映射结合,把数组中的每一项都加1
let {log:l} = console;var arr_map = [1,2,3,4].map(items => items + 1);l(arr_map);//(4) [2, 3, 4, 5]
- 和
sort结合,进行从小到大排序
var arr_sort = [100,5,74,998].sort((a,b) => a-b);l(arr_sort);//(4) [5, 74, 100, 998]
与 this 的联系
用了箭头函数,那么 this 指向的就是对象,而不是谁调用就指谁了
let fn ;
let fn2 = function(){console.log('fn2--this:>>',this);fn=()=>{console.log('fn--this:>>',this);}
}
// fn2 = fn2.bind(document.body);
fn2 = fn2.bind(document.body);fn2();
fn();
//看这个例子function f8() {setTimeout(function () {console.log(this)},1000)}function f8_jiantou() {setTimeout( () => {console.log(this)},4000)//当定时器的函数体扩回后,定时器又重新是windows的了//当定时器的函数体扩回前,定时器是一直指向obj_f8的}var obj_f8 = {name:"f8Name"};f8.call(obj_f8);//Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}//这里把 obj_f8 的指针给了f8_jiantou,那么定时器里的this 就指向obj_f8f8_jiantou.call(obj_f8);//{name: "f8Name"}
再来一个例子慢慢理解一下
function foo () {return () => {return () =>{console.log(this.id);}}}var foo1 = foo.call({id:"一"});console.log(foo1);/*() => {return () =>{console.log(this.id);}}*/var foo2 = fun1.call({id:"二"});console.log(foo2);/*() =>{console.log(this.id);}*/foo2();//一
总结:箭头函数它本身没有this,调用建通函数的this时, 指向的是其声明时所在的作用域的this
缺点
- 不能使用箭头函数实例化对象了
var F = () =>{};var f = new F;f();//Uncaught TypeError: F is not a constructor
- 不能用 arguments 获取传来的参数了
/*3.不能使用arguments*/var fun3 = () => {console.log(arguments);};fun3(123);//Uncaught ReferenceError: arguments is not defined
处理错误
- 一般由
try、catch、finally、throw几个构成 try:尝试执行代码,这里遇到的第一个错误会带到catch中catch:处理错误,可以把错误吞并掉,从而避免卡住浏览器finally:无论try中出错与否,都会执行throw:抛尸,比方说throw new error("你输错了");
<body><h3>请输入6~100</h3><input type="text" id="inp"><button id="btn">这是一个测试</button>
</body><script>var btn = document.querySelector("#btn");var inp = document.querySelector("#inp");//尝试执行代码btn.onclick = function () {try{if(inp.value < 6){throw new error("你输错了");}}catch (err) {//try里遇到第一个错误之后会携带错误信息跳到catch里//会把error吃掉,不会卡住浏览器,会继续渲染console.log(err);//处理错误inp.value = '';}finally {//不管有没有错误都要执行console.log("吃瓜群众")}}
</script>
数据结构:set
这个数据结构的特点是:元素不会重复
它没有下标,没有所谓的 length 长度
规则
- 重复元素的判断跟
===差不多,不同的是NaN,如果有两个NaN,他会认成一个,也就是书面一样
let set = new Set([NaN,NaN]);console.log(set);//Set(1) {NaN}
let set = new Set([0,-0]);console.log(set);//Set(1) {0}
let set = new Set([1,"1"]);console.log(set);//Set(2) {1, "1"}
长度
- 用
set.size
let set = new Set([1,1,1,2,2,3,3,3,4,5,6,"5",NaN,NaN]);console.log(set.size);//8console.log(set.length);//undefined
增加元素
- 用
set.add()
let set = new Set([]);set.add("8848钛金手机");console.log(set);//Set(1) {"8848钛金手机"}
删元素
- 用
set.delete()删除元素,返回布尔值,表示成功与否
let set = new Set(["8848钛金手机"]);console.log(set);//Set(1) {"8848钛金手机"}set.delete("8848钛金手机");console.log(set);//Set(0) {}
查找元素
- 用
set.has("");查找元素,返回布尔值表示,true 为存在
let set = new Set(["8848钛金手机"]);console.log(set.has("8848钛金手机"));;//true
遍历
遍历可以用如下的方法
- 用
Array.from(set) - 结构解析
[...set] forEach循环
var set1 = new Set([1,2,3,4,3,2,1])/*只要有遍历器接口的都可以用forOf遍历*/console.log(Array.from(set1));//(4) [1, 2, 3, 4]console.log([...set1]);//(4) [1, 2, 3, 4]
let set = new Set(["甲","乙","丙","丁"]);set.forEach((item) => console.log(item));//甲//乙//丙//丁
清空
- 用
set.clear();来清空
let set = new Set(["8848钛金手机"]);console.log(set);//Set(1) {"8848钛金手机"}set.clear();console.log(set);//Set(0) {}
曲线救国实现 map 方法
var set = new Set([1,1,2,2,3,3,4,4,5,5]);//先把set结构解析成数组,然后用数组的mapvar map = new Set([...set].map(item => item + 10));console.log(map);//Set(5) {11, 12, 13, 14, 15}
数组去重
用 set 的特性啊,没有重复的元素
想得到么小伙子
console.log([...new Set([1,2,3,1,2,3,1,2,3,1,2,3])]);//(3) [1, 2, 3]
求两个 set 元素的交集
关键,用过滤器 filter,他会保留返回值是 true 的
let set1 = new Set([1,2,3,4,5,9]);let set2 = new Set([1,2,5,6,7,8,9,]);let result_jiaoji = [...set1].filter(items => set2.has(items));console.log(result_jiaoji);//(4) [1, 2, 5, 9]
WeakSet
- 只能添加 Object 的 set
- WeakSet 不允许被循环,因为内部保存的对象的值是弱引用的,如果这些对象没有使用了,那么它将会被垃圾回收机制给收走,所以就没办法枚举了。
- WeakSet 里面放节点-防止内存泄露-JC
转载:知乎-WeakSet 的用法解惑
MDN:WeakSet
var weakset = new WeakSet();var set = new Set([1]);var obj = {name:'1'};//添加一个对象weakset.add(obj);console.log(weakset);//WeakSet {{…}}//如果想要添加一个数字,他会报错 weakset.add(1);//Uncaught TypeError: Invalid value used in weak set
- 如果想添加个数组
var weakset = new WeakSet();weakset.add([[1,2],[1,2]]);console.log(weakset);//WeakSet {Array(2)}
数据类型 Symbol
ES 6 中又新添加了个数据类型
- 他的值 独一无二
let s1 = Symbol("这里是描述s1");let s2 = Symbol("这里是描述s2");console.log((s1 == s2));//falseconsole.log((typeof s1));//symbol//console.log(s1 + "1");//Uncaught TypeError: Cannot convert a Symbol value to a string//不能隐式转换,能显示转换console.log((s1.toString() + '1'));//Symbol(这里是描述s1)1
- 建议放在对象中做属性名(因为它的特性–永远不会重复)
let s1 = Symbol();let s2 = Symbol();const obj = {[s1]:"string1",[s2]:"string2"};console.log(obj[s1]);//string1console.log(obj[s2]);//string2
- 用
Object.keys()是拿不出来 Symbol 的,根据这个特性,可以伪装成私有属性,for in循环更是白扯,啥都不输出
let s1 = Symbol();let s2 = Symbol();const obj = {[s1]:"string1",[s2]:"string2"};for (let x in obj){console.log(x);//没用,啥都不输出}console.log(Object.keys(obj));//(2) [Symbol(), Symbol()]
取值
它有自己的方法 Object.getOwnPropertySymbols(obj)
let s1 = Symbol();let s2 = Symbol();const obj = {[s1]:"string1",[s2]:"string2"};//这个可以拿出来以Symbol为key的console.log(obj[Object.getOwnPropertySymbols(obj)[0]]);//string1
Symbol.for()
Q:有人就想问,Symbol 既然是独一无二的,真的就不能重用么?
引进新的方法:Symbol.for(); 只要描述相同的话,那么他俩就是相同的
let a = Symbol("a");//重用,第一个Symbol.for("b")相当于注册let b = Symbol.for("b");//之后Symbol.for("b")是寻找,并且把b的指针给clet c = Symbol.for("b");console.log((a == b));//falseconsole.log((b == c));//true
取 ‘ 描述 ’
symbol.description可以拿出属性Symbol.keyFor(b)只能拿出Symbol.for("")设定的属性
let a = Symbol("a");let b = Symbol.for("b");let c = Symbol.for("b");console.log(a.description);//aconsole.log(b.description);//b//主要拿Symbol.for的description的console.log(Symbol.keyFor(b));//bconsole.log(Symbol.keyFor(a));//undefined
魔术字符
就是出现频率贼 JB 高,改起来贼 JB 费劲,一改就要改一大堆的的字符串就叫做魔术字符
官方说法:我们把 耦合性极强,复用性极差,出现频率极高 的字符串成为魔术字符
//例子//这里的字符串 '6' 就称之为魔术字符//这是判断语句少的情况,多了的话改起来就费劲了function test(mon) {if(mon == "6"){}else if(mon > "6"){}else if(mon < "6"){}}
那解决的方法蛮多的,用个变量代替它不就好了。要改的话,就改变量的值就好了
//这样改呗const obj = {key:"value"};function test(mon) {if(mon == obj.key){}else if(mon > obj.key){}else if(mon < obj.key){}}
深入理解 Object 和 Map
Object
- 对象结构来源于:hash 结构
- 对象的 key 是会自动
toString的 - 是 string - value 的组合
Map
- map 的 key 值没有 toString,很自由,想放什么放什么
- 是 value - value 的组合
const map = new Map();map.set({name:1},2);console.log(map.get({name:1}));//undefined//这里的undefined是因为 //map.get({name:1}) 中,又新建了一个{name:1}//这个跟set里的对象,虽然内容一样,但是指针不同//相当于var obj_kong = {};console.log((obj_kong == {}));//false
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
