01-ES6

知识点

var和let/const区别和联系

  • var:
    • 可以重复声明;
    • 作用域:全局作用域和函数作用域;
    • 会进行预解析;
  • let、const:
    • 同一作用域下不能重复定义;
    • 作用域:全局作用域和块级作用域{};
    • 不会进行预解析.
    if(true) {
      var a = 'aaa';
      let b = 'bbbb';
    }
    console.log(a); // aaa
    console.log(b); // ReferenceError: b is not defined
    

作用域

  • 页面中有三个 li

      const lis = document.querySelectorAll('li');
      for(var i=0; i<lis.length; i++){
        lis[i].onclick = function() {
          console.log('点击:', i);
        }
      }
      // 点击: 3
    
      const lis = document.querySelectorAll('li');
      for(let i=0; i<lis.length; i++){
        lis[i].onclick = function() {
          console.log('点击:', i);
        }
      }
      // 点击: 0
      // 点击: 1
      // 点击: 2
    

解构赋值

  • 快速交换a和b的值:[a,b] = [b,a];

展开运算符

  let a = [1, 2];
  let b = [3, 4, 5]
  let c = [3, 4, ...a, 5];  // [3, 4, 1, 2, 5];
  let [x, y, ...z] = c; //3 4 [1, 2, 5]
  // 对象也类似
  // 对象的拷贝,修改obj2中的内容,不影响obj1中的内容
  let obj2 = {...obj1};

Set

  • 对象的数据结构;
  • 属性:size;
  • 方法:clear()、delete()、has()、add();
  • 可用于数组去重。
    let arr = [2,3,4,5,5];
    // 构造函数:用来构建某一类型的对象--对象的实例化
    let s = new Set(arr) // 接受一个数组或者类数组作为参数
    console.log(s, s.size); // Set(4) { 2, 3, 4, 5 } 4
    
    // console.log(s.clear());  // undefined
    // console.log(s.delete(2)); // true
    // console.log(s.has(5));  // true
    console.log(s.add(9));  // 返回新的 Set,可以进行链式调用
    
    console.log(s);
    

Map

  • 对象的数据结构;
  • 属性:size;
  • 方法:clear()、delete()、get()、has()、set ();
    let arr = [
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', 4]
    ];
    
    let m = new Map(arr);
    console.log(m, m.size); // Map(4) { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4 } 4
    
    // console.log(m.clear());  // undefined
    // console.log(m.delete('a')); // true
    // console.log(m.has('a'));  // true
    // console.log(m.get('a'));  // 1
    console.log(m.set('f', 8));  // 返回一个新的 Map,可以进行链式调用
    
    console.log(m, m.size); // Map(5) { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'f' => 8 } 5
    

箭头函数

  • 注:箭头函数中的 this 会穿透,如果包含在多个嵌套的箭头函数中,会一直穿透;
  • 箭头函数没有不定参数(arguments)
function fn1() {
  console.log(arguments);
}
fn1(1,2,3,4,5);  // [1,2,3,4,5]

const fn2 = (a,b,...rest) => {
  console.log(a,b,rest); 
};
fn2(3,4,5,6,7); // 3 4 [5, 6, 7]
  • this 指向问题:箭头函数本身没有 this,调用箭头函数的 this 时,指向的是其声明时所在的作用域的 this:
    document.onclick = function() {
      console.log(this);  // #document
    }
    
    document.onclick = () => {
      console.log(this);  // Window
    }
    
    document.onclick = function() {
      function fn1() {
        console.log(this)
      }
      fn1();  // Window
    
      const fn2 = () => {
        console.log(this);
      }
      fn2();  // #document
    }
    
    let fn1;
    function fn2() {
      console.log(this);
      fn1 = () => {
        console.log(this)
      }
      // fn1 = function() {
      //   console.log(this) //Window
      // }
    }
    fn2();  // Window
    fn1();  // Window
    
    let fn1;
    function fn2() {
      console.log(this);
      fn1 = () => {
        console.log(this);
      }
      // f1 = function() {
      //   console.log(this);  //Window
      // }
    }
    fn2 = fn2.bind(document);
    fn2();  // #document
    fn1();  // #document
    
  • 默认值:
    fn1 = (a=8) => {
      console.log(a)
    }
    fn1()
    

数组

  • Array.from(list):把一个类数组转换成真正的数组。类数组:有下标有length。另一个方法:[...list]。
  • Array.of(1,2,3,'A'),将参数组成一个数组;
  • Array.isArray(data):检测一个数是否是数组(类数组返回false)
  • arr.find(callback):返回满足条件的第一个值,如果没有满足条件的就返回undefined。
  • flat:数组扁平化处理:
    let arr = [[1,2,3],[2,3,[2,3,[4,5]]],[3,4,5]];  // // [1, 2, 3, 2, 3, 2, 3, 4, 5, 3, 4, 5]
    console.log(arr.flat(Infinity))
    
  • fill:arr.fill(value,startIdx,endIdx);
  • includes:arr.includes(value,fromIdx)。

字符串

  • startsWith('aa',position):判断第position开始是否以'aa'开始;
  • endsWith('aa',position):判断前position位是否以'aa'结束;
  • repeat: str.repeat(count),将str重复count次.

模板字符串

  • 比较简单,这里不做过多赘述:${a}.

对象

  • 简洁表示法:
    let a = 1;
    let b = 2;
    let obj1 = {
      a: a,
      b: b,
      c: function() {}
    }
    // es6表示法
    let obj2 = {
      a,
      b,
      c() {}
    }
    
  • 属性名表示法:
    let name = 'yijiang';
    let obj = {
      [name]: 18
    }
    //  obj = {yijiang: 18}
    
  • 对象合并:
    let obj1 = {
      a: 1,
      b: 2
    };
    let obj2 = {
      c: 3,
      d: 4
    };
    let obj = Object.assign({}, obj1, obj2);
    // Object.assign(obj1, obj2); // 把 后面的 obj2 合并到第一个 obj1 中
    
    let obj1 = {
      a: 2,
      b: 3,
      c: {d: 4}
    };
    let obj2 = {
      x: 5,
      y: 6,
      z: {m: 8}
    };
    let object = Object.assign(obj1, obj2);
    // console.log(object);
    // {
    //   a: 2
    //   b: 3
    //   c: {d: 4}
    //   x: 5
    //   y: 6
    //   z: {m: 8}
    // }
    
    obj2.x = 88;
    obj1.z.m = 100;
    console.log(object);
    // {
    //   a: 2
    //   b: 3
    //   c: {d: 4}
    //   x: 5
    //   y: 6
    //   z: {m: 100}
    // }
    // assign 第一层是深拷贝,第二层是浅拷贝
    // 合并也可以通过展开运算符
    
  • Object.is(a, b):判断两个值是否相等,以下的值都为true:
    • 两个值都是 undefined;
    • 两个值都是 null;
    • 两个值都是 true,或者都是 false;
    • 两个值是由相同个数的字符按照相同的顺序组成的字符串;
    • 两个值指向同一个对象;
    • 两个值都是数字,并且都是 +0;都是 -0;都是 NaN.[这里和 === 结果不一样].
  • 对象冻结
    // 对象冻结
    let obj = { a: 1, b: { name: 'yjwtt' } };
    
    function deepFreeze(obj) {
      Object.freeze(obj);
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          const ele = obj[key];
          if (typeof ele === 'object') {
            deepFreeze(ele);
          }
        }
      }
    }
    
    deepFreeze(obj);
    obj.a = 2;
    obj.b.name = 'wyj';
    console.log(obj);
    
  • 深拷贝
    // 深拷贝
    let obj = {
      age: 18,
      name: 'yjw',
      play() {
        console.log('王者荣耀');
      },
      friend: '',
      house: undefined,
      books: ['Math', "Science"],
    }
    
    let obj2 = {...obj};
    obj2.age = 20;
    console.log(obj, obj2);
    
    // 解除引用的深拷贝
    // 1.通过序列化实现,缺点:值为undefined和函数会丢失
    let obj_1 = JSON.parse(JSON.stringify(obj));
    obj_1.age = 20;
    console.log(obj, obj_1);
    
    // 2.深拷贝函数
    let deepCopy = obj => {
      let newObj = Array.isArray(obj) ? [] : {};
      for(let key in obj ) {
        if(obj.hasOwnProperty(key)){
          if(typeof obj[key] === 'object') {
            newObj[key] = deepCopy(obj[key]);
          } else {
            newObj[key] = obj[key];
          }
        }
      }
      return newObj;
    }
    let obj_1 = deepCopy(obj);
    obj_1.age = 20;
    console.log(obj, obj_1);
    

arguments 和 ...arg 的区别

  function test(...arg) {
    console.log(arguments); // [1, 2, callee:(), length: 2, ...]
    console.log(arg); // [1, 2]
  }

  test(1,2);

面试题

  // 面试题
  // 1、var、let以及const区别
  /**
    1.var 没有块级作用域,只能是全局或者整个函数块
    2.var 有变量提升
    3.var 声明的变量会挂载到window上
    4.let和const,不会被预解析,let可以改变值但不能重复声明,const值不能改变。
  */

  // 2、说一下ES6对Object类型做了那些优化更新
  /**
    优化部分
    1.简写:
      let obj = {a:a, b:b, fn: function(){}} => let obj = {a, b, fn(){}};
    2.解构赋值;
    3.扩展运算符;
    更新部分:
    4.Object.is()、Object.assign({obj1, obj2)、Object.getOwnPropertyDescriptors(obj)
    5.Object.getPrototypeOf()、Object.setPrototypeOf()
    6.Object.keys()、Object.values()、Object.entries()
  */

  // let obj = {a: 1, name: {first:'yj', last: 'w'}};
  // console.log(Object.getOwnPropertyDescriptors(obj));
  // console.log(Object.getPrototypeOf(obj));
  // console.log(Object.keys(obj));
  // console.log(Object.values(obj));
  // console.log(Object.entries(obj));

案例

案例一员工列表
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body a {
      text-decoration: none;
      color: #0d3a4b;
    }

    .active {
      color: #4cbfe5;
    }

    .wrap {
      width: 700px;
      height: 500px;
      background-image: url(./images/bg.png);
      background-repeat: no-repeat;
      margin: 0 auto;
      position: relative;
    }

    .wrap #table {
      width: 460px;
      border-radius: 12px;
      position: absolute;
      left: 50%;
      top: 160px;
      transform: translateX(-50%);
      box-sizing: border-box;
      overflow: hidden;
    }

    .wrap #table thead {
      width: 100%;
      height: 30px;
      line-height: 30px;
      text-align: center;
      border-top-left-radius: 12px;
      border-top-right-radius: 12px;
      color: #fff;
      background: #4cbfe5;
    }

    .wrap #table thead a {
      color: #fff;
    }

    .wrap #table tbody {
      color: #19c2ff;
    }

    .wrap #table tbody a {
      color: #19c2ff;
    }

    .wrap #table tbody tr {
      background: #fff;
    }

    .ctrl {
      position: absolute;
      left: 200px;
      top: 100px;
    }

    .ctrl div {
      width: 300px;
      line-height: 30px;
      display: flex;
      flex-direction: row;
      justify-content: space-around;
    }
  </style>
</head>
<body>
  <div class="wrap">
    <div class="ctrl">
      <div class="age_sort nu">
        <a href="javascript:;">年龄从小到大</a>
        <a href="javascript:;">年龄从大到小</a>
        <a href="javascript:;" class="active">默认排序</a>
      </div>
      <div class="gender_show">
        <a href="javascript:;">只显示男性</a>
        <a href="javascript:;">只显示女性</a>
        <a href="javascript:;" class="active">默认</a>
      </div>
    </div>
    <table id="table">
      <thead>
        <tr>
          <th>id</th>
          <th>姓名</th>
          <th>年龄</th>
          <th>性别</th>
        </tr>
      </thead>
      <tbody>

      </tbody>
    </table>
  </div>
</body>

<script>
  // 员工列表
  // 数据优先 ,数据驱动 :先考虑数据,然后在渲染视图;
  let data = [
    {
      id: 1,
      name: '小明',
      age: 24,
      gender: '男'
    },
    {
      id: 2,
      name: '小芳',
      age: 30,
      gender: '女'
    },
    {
      id: 3,
      name: '小美',
      age: 31,
      gender: '女'
    },
    {
      id: 4,
      name: '小刚',
      age: 21,
      gender: '男'
    },
    {
      id: 5,
      name: '小琪',
      age: 18,
      gender: '女'
    }
  ];

  // 根据数据渲染视图
  const render = (data) => {
    let tbody = document.querySelector('tbody');
    tbody.innerHTML = '';
  
    data.forEach(ele => {
      let tr = document.createElement('tr');
      tr.innerHTML = `
        <th>${ele.id}</th>
        <th>${ele.name}</th>
        <th>${ele.age}</th>
        <th>${ele.gender}</th>`;
      tbody.appendChild(tr);
    })
  };

  // 初始化
  render(data);

  // 给各排序的种类赋初始排序默认值
  let ageIndex = 2;
  let genderIndex = 2;

  // 按照年龄排序的数据
  const ageData = [data => data.map(val=>val).sort((v1,v2)=>v1.age-v2.age), data => data.map(val=>val).sort((v1, v2)=>v2.age-v1.age), data=>data];
  // 获取年龄相关按钮
  const ageBtns = document.querySelectorAll('.age_sort a');
  // 绑定年龄相关按钮事件
  ageBtns.forEach((btn, index) => {
    btn.onclick = () => {
      // 去除所有年龄相关按钮激活样式
      ageBtns.forEach(btn => {
        btn.classList.remove('active');
      })
      // 给当前按钮绑定激活样式
      btn.classList.add('active');
      // 记录排序值
      ageIndex = index;
      // 根据各排序值计算排序后的数据
      const genderD = genderData[genderIndex](data);
      const ageD = ageData[ageIndex](genderD);
      render(ageD);
    }
  })

  const genderData = [data => data.filter(ele=>ele.gender==='男'), data => data.filter(ele=>ele.gender==='女'), data=>data];
  const genderBtns = document.querySelectorAll('.gender_show a');
  genderBtns.forEach((btn, index) => {
    btn.addEventListener('click', ()=> {
      genderBtns.forEach(btn => {
        btn.classList.remove('active');
      })
      btn.classList.add('active');
      genderIndex = index;
      const ageD = ageData[ageIndex](data);
      const genderD = genderData[genderIndex](ageD);
      render(genderD);
    })
  });
</script>
</html>
案例二百度音乐
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    ul {
      margin: 0;
      padding: 0;
      list-style: none;
    }

    h2 {
      margin: 0;
    }

    #wrap {
      margin: 30px auto;
      width: 482px;
      padding: 5px;
      position: relative;
      border: 1px solid #000;
      background: #eee;
    }

    .title {
      font: bold 18px/40px "宋体";
      text-align: center;
      border-bottom: 1px solid #000;
    }

    #list {
      padding-left: 2px;
    }

    #list li {
      opacity: 0.8;
      font: 14px/36px "宋体";
      border-bottom: 1px solid #000;
    }

    #list li:hover {
      opacity: 1;
    }

    #list label input {
      margin: 0 20px 0 30px;
    }

    input[type="chekbox"] {
      width: 20px;
      height: 20px;
    }

    .footer {
      font: 16px/36px "宋体";
    }
  </style>
</head>

<body>
  <section id="wrap">
    <h2 class="title">百度音乐榜单</h2>
    <ul id="list">
      <li>
        <input type="checkbox" class="check" />
        <span>第一条信息</span>
        <a href="javascript:;" class="collect">收藏</a>
        <a href="javascript:;" class="cancelCollect">取消收藏</a>
        <a href="javascript:;" class="remove">删除</a>
      </li>
    </ul>
    <footer class="footer">
      <label><input type="checkbox" id="checkAll" />全选/全不选</label>
      <a href="javascript:;" id="remove">删除</a>
      <input type="text" id="newInfo" />
      <a href="javascript:;" id="add">添加</a>
    </footer>
  </section>
</body>

<script>
  // 数据驱动视图
  // 模拟数据
  let data = [
    {
      id: 1,
      title: "残酷月光 - 费启鸣",
      checked: false,
      collect: true
    }, {
      id: 2,
      title: "兄弟 - 艾热",
      checked: false,
      collect: false
    }, {
      id: 3,
      title: "毕生 - 夏增祥",
      checked: true,
      collect: true
    }, {
      id: 4,
      title: "公子向北去 - 李春花",
      checked: false,
      collect: false
    }, {
      id: 5,
      title: "战场 - 沙漠五子",
      checked: true,
      collect: false //是否收藏 true 收藏 false 没有收藏
    }
  ];

  // 渲染视图
  render = (data) => {
    let list = document.querySelector('#list');
    list.innerHTML = ''
  
    data.forEach((val, index) => {
      let li = document.createElement('li');
      li.innerHTML = `
        <input type="checkbox" class="check" ${val.checked ? 'checked' : ''}/>
        <span>${val.title}</span>
        ${val.collect ? 
          '<a href="javascript:;" class="collect">收藏</a>' :
          '<a href="javascript:;" class="cancelCollect">取消收藏</a>'
        }
        <a href="javascript:;" class="remove">删除</a>
      `;
      list.appendChild(li);
    });

    // 判断是否已全选
    let checkAll = data.every(val => val.checked === true);
    document.querySelector('#checkAll').checked = checkAll;

    // 渲染视图之后,给对应元素绑定事件
    addEvent();
  }

  // 绑定事件
  addEvent = () => {
    const lis = document.querySelectorAll('#list li');
    lis.forEach((li, index) => {
      // 给li里面的元素添加点击事件
      li.onclick = (e) => {
        // 通过className来区分li中的各元素
        switch(e.target.className) {
          case 'check':
            console.log(e);
            data[index].checked = e.target.checked;
            break;
          case 'collect': 
            console.log('收藏');
            data[index].collect = false;
            break;
          case 'cancelCollect':
            data[index].collect = true;
            console.log('取消收藏');
            break;
          case 'remove':
            console.log('删除');
            data.splice(index,1);
            break;
        }
        // 处理完事件之后会获得对应的数据,然后进行渲染
        render(data);
      }
    });
  };

  // 处理底部按钮事件
  let footer = document.querySelector('.footer');
  footer.onclick = e => {
    switch(e.target.id) {
      case 'checkAll': 
        const checked = e.target.checked;
        data.forEach(val => {
          val.checked = checked;
        })
        break;
      case 'remove':
        data = data.filter(val => val.checked !== true);
        break;
      case 'add':
        let newInfo = document.querySelector('#newInfo');
        newInfo.value.trim() && data.push({
          title: newInfo.value, 
          id: data.length, 
          checked: false,
          collect: true
        });
        newInfo.value = '';
        break;
    }
    render(data);
  }

  // 首次进行视图渲染
  render(data)

</script>

</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274