ES6自学之旅(2)—— 对象解构赋值、箭头函数使用和思考

    ES6的内容太过丰富,在学习的过程中,我选择取其精华,跳过非精华,个人觉得变量的解构赋值和箭头函数都是非常有实际使用价值的内容,就单独拿出来放一个章节分析和介绍。

    关于变量的解构赋值,其实有很多种解构方式,包括数组,对象,字符串等都可以进行解构赋值,但个人认为对象的结构赋值是最常用,也是最有用的。

    下面来看一个应用场景:现在有一个person对象,然后你通过引用(import/require)等方式得到了这个对象,现在你需要获取这个人的名字和性别,这个时候你只需要这样写即可。

//...引入person对象 person={name:'小明',sex:'男','age':17,'':'',...................}
let {name,sex} = person
name // 小明
sex // 男

    至于person对象里还包含什么属性,那与你无关,你尽管取得你所需要的数据即可。当然在解构的时候,你需要写对键名,你需要知道你所需要的数据,在未知对象中的键名是什么,比如你想取‘性别’,你通过 let {性别} =  person,那性别这个变量赋值为undefined。因为只有'sex',没有‘性别’。

    来看一下对象解构赋值里常见的误区。

let {a:c,b:d} = {a:'aaa',b:'bbb'}
//最终'aaa'赋值给变量c,模式a并未定义
console.log(a,b,c,d) // aaa bbb a,b均为undefined

    上述代码a,b均为undefined报错,c,d有赋值,所以对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

    关于变量解构赋值的嵌套这里不过多说明,有兴趣可以去看阮大神的原著,总结起来有点故意刁难自己的意思。

    来看一个实际应用吧,比如Math对象中的一些方法,你可以通过对象解构将他拎出来单独使用。

let {sin,cos,log} = Math
console.log(sin(3.14/2),cos,log)

    

    关于箭头函数的使用方式,最明显的就是用=>符号定义函数,请不要手贱在=和>中间打个空格。如:

let add = (a)=>a*a
//等价于
let add = function(a){
  return a*a
}

    这种方式大大简化了函数的写法,增强了代码的可读性(说实话,没觉得可读性提高多少)

    注意:箭头函数用双大括号{}划分作用域,因此你在return一个对象的时候,千万记得加(),不然他就会解析对象的双括号为作用域的双括号,然后再解析里面的内容。

let name = ()=>({name:'dkr'})
    

    关于箭头函数的好处,最重要的就是ES6中箭头函数内部的this指针指向就是定义时所在的对象,而不是使用时所在的对象。看下面这个例子,s1和s2会输出什么?

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}
let timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3000);
setTimeout(() => console.log('s2: ', timer.s2), 3000);

    这里我故意修改了官网的例子,最终的结果打印,s1为3,s2为0。官网上给出的setTimeout的延迟为3100,个人认为阮大神可能考虑了setInterval执行计算需要时间,为了保证结果正确特意做的修改,关于这个到底是3000,还是3000多放到最后说明。

    首先,this.s1++使用了箭头函数,此时的this指向生成箭头函数的环境,this.s1 = 0,并可以累加。

    而普通函数的this,由于setInterval是window对象下面的方法,因此普通函数的this改成了window,因此对timer实例的s2并没有影响。

    ok,讲完了ES6语法问题,下面来探究下我真正感兴趣的东西,javaScript的运行机制

    将,上述代码进行分析,逐行解析。

    第一步:javaScript中创建了一个Timer函数,他被扔在了一边,还未执行函数内部代码。然后他又发现了一个由let关键字定义的timer,他也被暂时扔在一边。

    第二步:timer是由构造函数Timer生成的一个实例,在生成的过程中,timer继承了Timer的作用域,也就this,同时,Timer执行了其内部的代码,也就是setInterval定时器开始启动了。

    第三步:setTimeout定时器也启动了。

    那么,javaScript作为一个单线程应用,是怎么管理这些代码执行的呢?看下面这张图


    作为一个单线程应用,javaScript有一个核心处理器,用于处理所有同步请求,其他异步请求(如ajax,回调函数),或者定时器,都会被放到同步请求一边,等同步操作都执行完了,再来处理这些其他请求,而这些其他请求也是自己排队,尽管setInterval * 3 === setTimeout,但是处理器可不会同时处理这两个操作,计算机内部每个时钟周期只能干一件事,因此大部分情况下,setTimeout会排在setInterval*3后边,因为setInterval在timer被实例化后就已经开始计时了,而setTimeout要晚一点被解析。但是,如果setInterval内部的执行时间过长,那么他会被强制要求排在setTimeout后面,计算机会自动处理,无需你担心,因此,设置一定的延迟有利于结果的正确输出。

    

    

猜你喜欢

转载自blog.csdn.net/dkr380205984/article/details/80665011