【前端18_JS】ES 6:箭头函数、处理错误、数据结构 Set、WeakSet、数据类型 Symbol、魔术字符


箭头函数

参数

  • 最简单的箭头函数:一个形参可以不用括号
	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 : a
    a = 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_f8
    f8_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

处理错误

  • 一般由 trycatchfinallythrow 几个构成
  • 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);
    //8
    
    console.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结构解析成数组,然后用数组的map
    var 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));
    //false

    console.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]);
    //string1
    
    console.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的指针给c
    let c = Symbol.for("b");

    console.log((a == b));
    //false

    console.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);
    //a

    console.log(b.description);
    //b

    //主要拿Symbol.for的description的
    console.log(Symbol.keyFor(b));
    //b

    console.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
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值