zoukankan      html  css  js  c++  java
  • es6 新特性

    一、let、const 声明变量

    • var 是允许重新赋值、重新定义的,只有 global 和 function scope 作用域,在 if 内无作用域

    • letconst 拥有 block scope 作用域,有 {} 的时候就表明它的作用域范围

    • letconst 不可重复声明一个变量,所以使用 var 容易不小心覆盖原来的变量

    • let 可以重新赋值,const 不可以重新赋值

    • const 也是可以修改的,不过要是引用类型,相当于人(Person)是不可改变的,但我的年龄会随着时间改变

    const person = {
      name: 'Jelly',
      age: 20
    }
    
    person.age = 21;

    实在不希望改变,可以通过 Object.freeze

    阻止修改现有属性的特性和值,并阻止添加新属性。

    const person = {
      name: 'Jelly',
      age: 20
    }
    
    const Jelly = Object.freeze(person);
    
    person.age = 21; // 无法修改,返回值依旧是 20

    应用场景

    1、通过 letconst 实现私有变量

    window 对象下有一个 name 属性

    window.name = 'Jelly'; // 这样就影响到 window 下的 name 属性

    为了保证我们不影响到 window 下的 name 属性,我们通过 IIFE(立即执行函数)去实现私有化变量,但为了这个目的而去写这个函数,不利于代码的可读性

    (function() {
      var name = 'Jelly';
    })();
    
    window.name // ""

    有了 letconst 就可以通过它们的特性 block scope 来实现了

    {
      const name = 'Jelly';
    }
    
    window.name // ""

    2、for 循环应用场景

    for (var i = 0; i < 10; i++) { // 每次循环都重写了 i 的值
      setTimeout(function() { // 模拟 ajax 请求
        console.log(`i:${i}`); // i:10(10个重复)
      }, 1000);
    }
    
    console.log(window.i); // 10

    上面返回 10个 i:10 的原因就在于,在 setTimeout 1秒后执行的时候,循环已经结束

    只需将 var 改为 let 声明,每次声明的都属于当前的块级作用域,setTimeout 只认这个作用域

    for (var i = 0; i < 10; i++) { // 每次循环都重写了 i 的值
      setTimeout(function() { // 模拟 ajax 请求
        console.log(`i:${i}`); // 输出 i:0 到 i:9
      }, 1000);
    }
    
    console.log(window.i); // 10

    PS:const 不能使用,const 的值是不能重新赋值的

    3、临时性死区(Temporal dead zone)

    console.log(color);
    var color = 'yellow';
    
    console.log(color); // undefined

    原因是变量提升(是 JS 将声明移到作用域的顶部)

    相当于是:

    var color;
    console.log(color);
    color = 'yellow';

    使用 letconst 呢?

    console.log(color);  // ReferenceError
    let color = 'yellow';

    同样有变量提升,它们会存在于临时性死区,所以这个特征让我们养成在变量未声明的时候,不要使用

    二、箭头函数(arrow function)

    三个特点:

    • 简明的语法
    • 隐式返回
    • 不绑定 this

    简明的语法

    // 传统写法
    const numbers = [5, 6, 13, 5];
    
    const double = numbers.map(function(number) {
      return number * 2;
    })
    
    console.log(double); 
    // 简化
    const numbers = [5, 6, 13, 5];
    
    const double = numbers.map(number => { // 一个参数不需要括号,多个参数需要,没有参数需要保留括号
      return number * 2;
    })
    
    console.log(double); 

    隐式返回

    有 return 则表示是显示返回

    const numbers = [5, 6, 13, 5];
    
    const double = numbers.map(number => number * 2); // 放在一行,在我们需要简单返回一个东西的时候特别有用
    
    console.log(double); 

    不绑定 this

    const Jelly = {
      name: 'Jelly',
      hobbies: ['Coding', 'Reading', 'Sleeping'],
      printHobbies: function() {
        console.log(this); // printHobbies 的 this 指向调用它的对象 Jelly
        this.hobbies.map(function(hobby) { // map 函数是独立的函数,独立运行时候,没通过 call、apply、bind 来改变 this 的情况下,这个 this 则指向 window、global 或者在严格模式下指向 undefined
          console.log(`${this.name} loves ${hobby}`);
        });
      }
    }
    
    Jelly.printHobbies(); // 打印不对,this.name 是空

    老方法是通过:var self = this

    新方法则通过箭头函数,箭头没有自己的 thisthis 是继承父级的

    this.hobbies.map(hobby => {
      console.log(`${this.name} loves ${hobby}`);
    });

    箭头函数都是匿名函数(如何使用命名函数的箭头函数)

    首先了解什么是命名函数:

    function greet(name) { // 在递归和解除绑定的时候特别有用
      console.log(`Hello ${name}`);
    }
    
    greet('lth'); // Hello lth

    箭头函数要写成命名函数可:

    let greet = name => {console.log(`Hello ${name}`)};
    greet('lth'); // Hello lth

    应用场景

    1、作为构造函数,一个方法需要绑定到对象

    const Person = (name, points) => {
      this.name = name; // 这里用了箭头函数,this 并没有绑定到 Jelly 这个对象上去
      this.points = points;
    }
    
    const Jelly = new Person('jelly', 5);
    
    // new Person 会完成四个步骤:
    // 生成一个新的对象、把构造函数中的 this 值指向这个新生成的对象、把这个绑定到它的原型对象、返回这个新生成的对象
    
    Person.prototype.updatePoints = () => {
      this.points++; // 这里的 this 指向 window,所以要使用正常的 function,这样才能绑定到对象上去
      console.log(this.points)
    }
    
    // 以上代码会报错
    
    const Person = function(name, points) {
      this.name = name;
      this.points = points;
    }
    
    const Jelly = new Person('jelly', 5);
    
    Person.prototype.updatePoints = function() {
      this.points++;
      console.log(this.points)
    }
    
    Jelly // object  name: 'jelly', points: 5
    Jelly.updatePoints(); // 6

    2、当你真的需要 this 时

    const button = document.querySelector('.zoom');
    button.addEventListener('click', () => {
      this.classList.add('in'); // 找不到绑定的对象 button,此时的 this 指向 window
      setTimeout(() => {
        this.classList.remove('in');
      }, 2000)
    })
    
    const button = document.querySelector('.zoom');
    button.addEventListener('click', function() {
      this.classList.add('in'); 
      setTimeout(() => {
        this.classList.remove('in');
      }, 2000)
    })

    3、需要使用 arguments 对象

    // 这个功能返回所有参数的和
    const sum = () => {
      return Array.from(arguments) // 在箭头函数中是没有 arguments 这个对象的
                  .reduce((prevSum, value) => prevSum 
                  + value, 0)
    }
    
    
    const sum = function() {
      return Array.from(arguments) // 这个 from 是将类数组对象转化为真正的数组对象
                  .reduce((prevSum, value) => prevSum 
                  + value, 0)
    }

    三、参数默认值

    // 老方法
    function userInfo(a, b) { 
      a = a || 5; // 参数默认声明,不需要重新声明
      b = b || 6;
      return a * b;
    }
    // ES6 新方法
    function userInfo(a = 5, b = 6) { // 提高可读性
      return a * b;
    }
    
    
    userInfo(); // 30
    userInfo(4); // 24
    userInfo(undefined, 5); // 25 不是第一个值的时候,传 undefined

    四、模版字符串

    字符串拼接可以简化,不用各种 ++++++ 了

    const person = 'Jelly';
    const age = 5;
    const sentence = `${person} is ${age} years old.`;
    // 老方法
    const template = [
      '<div class="greet">',
        '<p>Hello</p>',
      '</div>'
    ].join('');
    
    console.log(template);
    // 新方法,模版字符串会保留空格
    const template = `
      <div class="greet">
        <p>Hello</p>
      </div>
    `.trim();
    
    console.log(template);

    应用场景

    1、通过模版字符串输出列表

    const Jelly = {
      name: 'jelly',
      date: '2017-05-07',
      todos: [
        {
          name: 'Go to Store', completed: false
        },
        {
          name: 'Watch Movie', completed: true
        },
        {
          name: 'Running', completed: true
        }
      ]
    }
    
    const template = `
      <ul>
        ${Jelly.todos.map(todo => `
          <li>
            ${todo.name} ${todo.completed ? '✅' : '❌'}
          </li> 
        `).join('')}
      </ul>
    `
    
    document.body.innerHTML = template;

    2、给传入的参数加标签

    function highlight(strings, ...values) { // strings 是个数组表示中间的字符串,values 表示 ${} 那些值
    
      // debugger; // 这样可以看到 highlight 的组成
      const highlighted = values.map(value => `<span class="highlight">${value}</span>`);
      
      let str = '';
      strings.forEach((string, i) => str += `${string}${highlighted[i] || ''}`);
      
      return str;
      
      // 上面的 for return 也可以用 reduce 来处理
      // return strings.reduce((prev, curr, i) => `${prev}${cur}${highlighted[i] || ''}`, '');
    }
    
    const user = 'Mary';
    const topic = 'Learn to use markdown';
    const sentence = highlight`${user} has commented on your topic ${topic}`;

    3、过滤用户输入

    防止用户在输入框的内容中,插入非法字符串或脚本来实现 XSS (跨站脚本攻击),她们可以从在实现获取 Cookie、Session、密码之类的敏感信息

    使用到的库:DOMPurify.js

    下面这个案例就过滤掉了内嵌的 onload 事件

    function sanitize(strings, ...values) {
      const dirty = strings.reduce((prev, curr, i) => `${prev}${curr}${values[i] || ''}`, '');
      return DOMPurify.sanitize(dirty);
    }
    
    addCommentForm.addEventListener('submit', function(event) {
      event.preventDefault();
      const newComment = textarea.value.trim();
      if (newComment) {
        CommentDiv.innerHTML = sanitize`
          <div class="comment-header">${user}</div>
          <div class="comment-body">${textarea.value}</div>
        `
        
        textarea.value = '';
      }
    });

    五、字符串新增方法

    • .startsWith()
    • .endsWidth()
    • .includes()
    • .repeat()
    const id = '51030019800730366x';
    const fan = 'I love Laravist';
    
    
    id.startsWith('51'); // true // 是不是以 51 开头的
    id.startsWith('1980', 6); // true // 第 6 位开始是不是以 1980 开头的
     
    // 区分大小写
    fan.startsWith('I'); // true 
    fan.startsWith('i'); // false
    
    
    id.endsWith('x'); // true
    id.endsWith('X'); // false
    fan.endsWith('love', 6); // true
    
    // 在 includes 方法之前我们用 indexOf
    
    fan.indexOf('Laravist') !== -1 // true
    
    fan.includes('Laravist') // true
    
    fan.includes('Laravist', 10) // false 第十位开始有没有 Laravist
    
    
    '哈'.repeat(10)

    应用场景

    1、实现右对齐

    function padder(string, length = 25) {
      return `${' '.repeat(Math.max(length - string.length), 0)}${string}`
    }

    六、对象解构

    const Tom = {
      name: 'Tom Jones',
      age: 25,
      family: {
        mother: '123',
        father: '456',
        brother: '789'
      }
    }
    
    
    const name = ''; // 会报错!
    const { name, age } = Tom; // 先声明,然后去 Tom 对象找同名的属性
    
    console.log(name); // 'Tom Jones'
    console.log(age); // 25
    
    
    // 如果你想自己声明的话,用一堆括号包裹
    let name = '';
    ({ name, age } = Tom); // 会解析成代码块,而不是对象解构的语法
    
    console.log(name);
    console.log(age);
    
    
    // 要访问 family 也可以这么写
    const { fater, mother, brother } = Tom.family;

    对象解构重命名

    // 如果 father 已经别人提前声明了
    
    const { father: f, mother, brother } = Tom.family; // 讲 father 重命名为 f,但要注意的是,并没有声明 father,而是声明了 f,然后去 Tom.family 里找 father 属性
    
    console.log(f); // 123
    console.log(father); // not defined
    console.log(sister); // undefined

    对象解构默认值

    // 可设置默认值,属性值要是 undefined 的时候
    const { father: f, mother, brother, sister = 'have no sister' } = Tom.family;
    console.log(sister); // have no sister

    常用于一些库,会提供一个 options 的选项让你来自定义属性,它们会有默认值

    function appendChildDiv(options = {}) {
      const { parent = 'body', width = '100px', height = '80px', backgroundColor = 'pink' } = options;
      const div = document.createElement('div');
      div.style.width = width;
      div.style.height = height;
      div.style.backgroundColor = backgroundColor;
      
      document.querySelector(parent).appendChild(div);
    }
    
    appendChildDiv({
      parent: '.container',
      width: '200px',
      height: '150px',
      backgroundColor: 'blue'
    })

    七、数组解构

    const numbers = ['one', 'two', 'three', 'four'];
    
    const [one, two] = numbers;
    
    console.log(one, two); // one two
    
    
    // 想获取 1、3
    const [one, ,three] = numbers;
    console.log(one, three); // one three
    
    
    // 获取所有
    const [one, ...others] = numbers; // ...other 只能存在于最后一个,不能是 const [one, ...others, five] = numbers;
    console.log(one, others); // one ['two', 'three', 'four']

    数组解构默认值

    const details = ['JellyBool', 'laravist.com'];
    
    const [name, website, category = 'PHP'] = details; // 默认值为 undefined 时才生效
    
    console.log(name, website, category); // JellyBool laravist.com PHP

    应用场景

    1、交换变量

    // 老办法
    let a = 10;
    let b = 20;
    
    let temp;
    
    temp = a;
    a = b;
    b = temp;
    
    
    // 新办法
    [a, b] = [b, a]

    八、for-of 遍历

    传统的有三种方法:for、forEach、for-in

    for 在于繁琐
    forEach 缺点在于:不能中止 break、continue、return
    for in 在于会遍历所有可枚举的属性
    for-of 现在暂时不支持对象

    // for-in  需要注意的是,遍历对象上可枚举的属性
    friuts.describe = 'My favorite fruits';
    
    // 或者给原型加一个方法
    friuts.prototype.first = function() {
      return this[0];
    }
    
    // 新增的属性和方法都会被遍历出来

    for-of 的使用

    // 只需将 for in 改为 for of 即可
    
    for (let fruit of fruits) { // 要用 let 
      if (fruit === 'Orange') { // 可中止
        break;
      }
      console.log(fruit)
    }

    应用场景

    1、可用于可迭代对象

    对象有内置了遍历器接口

    fruits.entries()
    
    // 会返回
    Array Iterator{} // 这个就是它的遍历接口
    const fruits = ['Apple', 'Banana', 'Orange', 'Mango'];
    
    for (let [index, fruit] of fruits.entries()) {
      console.log(`${fruit} ranks ${index + 1} in my favorite fruits`);
    }
    
    // Apple ranks 1 in my favorite fruits
    // Banana ranks 2 in my favorite fruits
    // Orange ranks 3 in my favorite fruits
    // Mango ranks 4 in my favorite fruits

    2、转换类数组 arguments

    function sum() {
      let total = 0;
      for (let num of arguments) {
        total += num;
      }
      return total;
    }
    
    sum(1,2,3,4,5,6,7,8,9,10); // 55

    3、绑定事件

    const lis = document.querySelector('li');
    for (let li of lis) {
      li.addEventListener('click', function() {
        this.classList.toggle('completed');
      })
    }
  • 相关阅读:
    WebClien简单示例(一)
    关于WQS二分算法以及其一个细节证明
    Scut游戏服务器免费开源框架快速开发(1)
    Scut游戏服务器免费开源框架快速开发(3)
    Scut游戏服务器免费开源框架快速开发(2)
    Struts中的 saveToken的方法
    CKEditor 3.6
    Oracle 笔记 day01
    Oracle日期格式问题
    Oracle 笔记 day03
  • 原文地址:https://www.cnblogs.com/small-zhh/p/9860239.html
Copyright © 2011-2022 走看看