ES6新特性

函数默认值

  • 第二个参数 type不传,直接使用函数默认值

    function  fnDefault(num,type='¥'){
       return num+type
    }
    console.log(fnDefault('999'))
    
  • 第二个参数 type传,直接传进来的参数

    function  fnDefault(num,type='¥'){
       return num+type
    }
    console.log(fnDefault('999','$'))
    

模板字符串

  • 模板字符串便于字符串拼接,通过反引号 (`)。

    常规写法

    function getDate(){
    	const date = new Date()
    	const year = date.getFullYear()
    	const month = date.getMonth() + 1 ;
        const dayDate = date.getDate()
        return year + '年' + month + '月' + dayDate + '日'
    }
    console.log(getDate())
    
  • 模板字符串写法

    function getDate(){
    	const date = new Date()
    	const year = date.getFullYear()
    	const month = date.getMonth() + 1 ;
        const dayDate = date.getDate()
        return `${year}${month}${dayDate}`
    }
    console.log(getDate())
    

解构赋值

数组解构

  • 解构对象对应的是下标,如需要跳过个别元素,则需要留有相对于空位。如要跳过的元素处于数组末端,则在形参数组中可以不予留空。
    var [a, , ,b] = [1, 2, 3, 4, 5];
    console.log(a); // => 1
    console.log(b); // => 4
    

对象解构

  • 对象解构的形参名必须与待解构的目标对象中的属性名/方法名完全相同才可以,否则undefined
    function resObj(){
        return {name:'张三',age:18,sex:1}
    }
    
    const {name,age,sex} = resObj()
    
    console.log(name,age,sex)
    

函数入参解构

  • 函数入参解构的形参名必须与待解构的目标对象中的属性名/方法名完全相同才可以,否则undefined
    function example({name,age,sex}) {
        return `姓名${name},年龄${age},sex${sex}` ;
    }
    let body = {
        name:'张三',
        age:18,
        sex:1
    }
    console.log(example(body)); //
    

let、const

  • 无变量提升,变量提升只存在var声明的

  • 使用 var 声明的变量会自动提升到当前作用域的顶部,如果声明位置与作用域顶部之间有另一个同名变量,很容易引起难以预知的错误。使用 let,const 声明的变量则不会进行变成提升,规避了这个隐患。

    console.log(num); // => undefined
    var num = 1;
    
    console.log(num2); // => Uncaught ReferenceError: num2 is not defined
    let num2 = 1;
    
    console.log(num3); // => Uncaught ReferenceError: num2 is not defined
    const num3 = 1;
    
  • let 禁止重复声明

  • const 禁止重复声明 禁止二次赋值,必须赋初始化值

箭头函数

  • 简写代码,前后对比很容易理解,可以明显看出箭头函数极大地减少了代码量。
    var arr = [1, 2, 3, 4, 5, 6];
    
    // 不使用箭头函数
    arr.filter(function(v) {
        return v > 3;
    });
    // 使用箭头函数后
    arr.filter(v => v > 3); // => [4, 5, 6]
    

函数上下文this指向

  • 普通函数的this指向window

    var obj = {
        arr: [1, 2, 3, 4, 5, 6],
        getMaxPow2: function() {
            var that = this,
                getMax = function() {
                	console.log('this',this) // Window {window: Window, self: Window, document: document, name: '', location: Location, …}
                    return Math.max.apply({}, that.arr);
                };
            
            return Math.pow(getMax(), 2);
        }
    }
    console.log(obj.getMaxPow2())
    
  • 箭头函数的this指向当前调用者

    var obj = {
        arr: [1, 2, 3, 4, 5, 6],
        getMaxPow2: function() {
            var getMax = () => {
                console.log('this',this) //{arr: Array(6), getMaxPow2: ƒ}
                return Math.max.apply({}, this.arr);
            }
    
            return Math.pow(getMax(), 2);
        }
    }
    

新增库函数

Number

isNaN(any)

  • isNaN() 函数可确定值是否为非数字(Not-a-Number),如果该值等于 NaN,则此函数返回 true。否则返回 false。全局 isNaN() 函数将测试值转换为数字。
isNaN(123) // => false
isNaN('123') // => false
isNaN(Number('123)) // => false
isNaN('abc') // => true
isNaN(Number('abc')) // => true

String

includes(String)

  • inclueds() 方法用来判断一个字符串中是否存在指定字符串
'abcde'.includes('cd'); // => true
'abcde'.includes('ad'); // => false
'12345'.includes('123'); // => true
'12345'.includes(123); // => true
'12345'.includes('13'); // => false

repeat(Number)

  • repeat() 方法用来重复一个字符串生成一个新的字符串
'abc'.repeat(3); // => 'abcabcabc'

startsWith(String)

  • startsWith() 方法用来判断一个字符串是否以指定字符串开头,可以传入一个整数作为第二个参数,用来设置查找的起点下标,默认为 0,即从字符串第一位开始查找
'abc'.startsWith('a');  // => true
'abc'.startsWith('a',0);  // => true
'abac'.startsWith('a',1);  // => false
'abac'.startsWith('a',2);  // => true

endsWith(String)

  • endsWith() 方法用来判断一个字符串是否以指定字符串结尾,可以传入一个整数作为第二个参数,用来设置查找的起点下标,默认为 0,即从字符串最后一位开始查找
'abc'.startsWith('c');  // => true
'abc'.startsWith('c',0);  // => true
'abcac'.startsWith('c',1);  // => false
'abcac'.startsWith('c',2);  // => true

Array

Array.from()

  • from() 方法,该方法可以将一个类数组对象转换成一个真正的数组。
document.querySelectorAll('*') // => 获取一个类数组
Array.from(document.querySelectorAll('*')) // => 转换成真正的数组

fill(value,startIndex,endIndex)

  • fill()用来填充一个数组,第一个参数为将要被填充到数组中的值,可选第二个参数为填充起始索引(默认为 0),可选第三参数为填充终止索引(默认填充到数组末端)。
[0,0,0,0,0,0,0,0,0,0,0,0].fill(7); // => [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
[0,0,0,0,0,0,0,0,0,0,0,0].fill(7, 1); // => [0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
[0,0,0,0,0,0,0,0,0,0,0,0].fill(7, 1,5); // => [0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0]

findIndex()

  • Array.findIndex()返回符合条件的元素的索引位置,之后的值不会再调用执行函数。如果没找到则返回-1
[1, 2, 3].findIndex(x => x===2); // => 1
[1, 2, 3, 2].findIndex(x => x===2); // => 1
[1, 2, 3, 2].findIndex(x => x===22); // => -1

entries()

Array.entries()
  • Array.entries() 方法返回一个数组的迭代对象,该对象包含数组的键值对 (key/value)。
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var x = fruits.entries();// => Array Iterator {}
x.next(); // => {"value": [ 0,"Banana"],"done": false}
x.next(); // => {"value": [ 0,"Orange"],"done": false}
x.next(); // => {"value": [ 0,"Apple"],"done": false}
x.next(); // => {"value": [ 0,"Mango"],"done": false}
x.next(); // => {"value": undefined ,"done": true}

Array.from(x) // =>  [Array(2), Array(2), Array(2), Array(2)] 转换成真数组
Object.entries(Array/Object)
Object.entries(Array)
  • 传入数组,
var arr = [1, 2, 3]; 
console.log(Object.entries(arr));  // [['0', 1], ['1', '2'], ['2', '3']]

var arr = [1, 2, 3,undefined]; 
var res = Object.entries(arr).map(item=>{
    return item[1]
}).every(item=>{
    return item!==''&&item!==undefined&&item!==null
})
console.log(res) // => false
Object.entries(Object)
  • 通过`Object.entries()转换对象成数组,通过map返回每一项的值,再通过every去判断是否存在空值,如果都存在值并且不为空则返回true
var obj = { foo: 'bar', baz: 'abc' }; 
console.log(Object.entries(obj));  // [['foo', 'bar'], ['baz', 'abc']]

var obj = { foo: 'bar', baz: 'abc',dd:'' }; 
var res = Object.entries(obj).map(item=>{
    return item[1]
}).every(item=>{
    return item!==''&&item!==undefined&&item!==null
})
console.log(res) // => false

arguments

  • arguments 这样一个伪数组对象,该对象中包含该函数所有的入参(显示入参 + 隐式入参),当函数体中有另外一个函数,并且该函数为箭头函数时,该箭头函数的函数体中可以直接访问父级函数的 arguments 对象。
    function getSum() {
        var example = () => {
            return Array
                .prototype
                .reduce
                .call(arguments, (pre, cur) => pre + cur);
        }
    
        return example();
    }
    getSum(1, 2, 3); // => 6
    
    • 由于箭头函数本身没有 arguments 对象,所以如果他的上层函数都是箭头函数的话,那么 arguments 对象将不可用。

类、继承

  • 类的定义
    class Animal {
        constructor(name) {
            this.name = name;
        }
    
        sleep() {
            console.log(`The ${this.name} is sleeping...`);
        }
    
        static type() {
            console.log('This is an Animal class.');
        }
    }
    let puppy = new Animal('puppy');
    
    puppy.sleep();    // => The puppy is sleeping...
    
    
    /* 实例化后无法访问静态方法 */
    puppy.type();     // => TypeError
    
    Animal.type();    // => This is an Animal class.
    
    /* 实例化前无法访问动态方法 */
    Animal.sleep();   // => TypeError
    
    
    • 两点注意事项:
      1. 在类的定义中有一个特殊方法 constructor(),该方法名固定,表示该类的构造函数(方法),在类的实例化过程中会被调用(new Animal(‘puppy’));
      2. 类中无法像对象一样使用 prop: value 或者 prop = value 的形式定义一个类的属性,我们只能在类的构造方法或其他方法中使用 this.prop = value 的形式为类添加属性。
    • 最后对比一下我们之前是怎样写类的:
      function Animal(name) {
          this.name = name;
      }
      
      Animal.prototype = {
          sleep: function(){
              console.log('The ' + this.name + 'is sleeping...');
          }
      };
      
      Animal.type = function() {
          console.log('This is an Animal class.');
      }
      
  • 类的继承
    class Programmer extends Animal {
        constructor(name) {
            /* 在 super 方法之前 this 不可用 */
            console.log(this); // => ReferenceError
            super(name);
            console.log(this); // Right!
        }
        
        program() {
            console.log("I'm coding...");
        }
    
        sleep() {
            console.log('Save all files.');
            console.log('Get into bed.');
            super.sleep();
        }
    }
    
    let coder = new Programmer('coder');
    coder.program(); // => I'm coding...
    coder.sleep();   // => Save all files. => Get into bed. => The coder is sleeping.
    
    • 这里我们使用 class 定义了一个类 Programmer,使用 extends 关键字让该类继承于另一个类 Animal。.
    • 如果子类有构造方法,那么在子类构造方法中使用 this 对象之前必须使用 super() 方法运行父类的构造方法以对父类进行初始化。
    • 在子类方法中我们也可以使用 super 对象来调用父类上的方法。如示例代码中子类的 sleep() 方法:在这里我们重写了父类中的 sleep() 方法,添加了两条语句,并在方法末尾使用 super 对象调用了父类上的 sleep() 方法。

  • 俗话讲:没有对比就没有伤害 (゜ー゜),我们最后来看一下以前我们是怎么来写继承的:
    function Programmer(name) {
        Animal.call(this, name);
    }
    
    Programmer.prototype = Object.create(Animal.prototype, {
        program: {
            value: function() {
                console.log("I'm coding...");
            }
        },
        sleep: {
            value: function() {
                console.log('Save all files.');
                console.log('Get into bed.');
                Animal.prototype.sleep.apply(this, arguments);
            }
        }
    });
    
    Programmer.prototype.constructor = Programmer;
    

模块化

  • 封闭的代码块
    每个模块都有自己完全独立的代码块,跟作用域类似,但是更加封闭。

  • 无限制导出导出
    一个模块理论上可以导出无数个变量、函数、对象属性、对象方法,甚至一个完整的类。但是我们应该时刻牢记单一职责这一程序设计的基本原则,不要试图去开发一个臃肿的巨大的面面俱到的模块,合理控制代码的颗粒度也是开发可维护系统必不可少的一部分。

  • 严格模式下运行
    模块默认情况下在严格模式下运行(‘use strict;’),这时候要注意一些取巧甚至有风险的写法应该避免,这也是保证代码健壮性的前提。

  • 模块的定义与导出

    • 内联导出
      export const DEV = true;
      export function example() {
          //...
      }
      export class expClass {
          //...
      }
      export let obj = {
          DEV,
          example,
          expClass,
          //...
      }
      
      • 使用 export 关键字,后面紧跟声明关键字(let、function 等)声明一个导出对象,这种声明并同时导出的导出方式称作内联导出。
      • 未被导出的内容(变量、函数、类等)由于独立代码块的原因,将仅供模块内部使用(可类比成一种闭包)。
    • 对象导出
      // module example.js
      const DEV = true;
      function example() {
          //...
      }
      class expClass {
          //...
      }
      let obj = {
          DEV,
          example,
          expClass,
          //...
      }
      // module example.js
      export {DEV, example, expClass, obj};
      export {DEV, example as exp, expClass, obj};
      
    • 相对于内联导出,上边的这种方式为对象导出。我们可以像写普通 JS 文件一样写主要的功能逻辑,最后通过 export 集中导出。
    • 在导出时我们可以使用 as 关键字改变导出对象的名称。
  • 默认导出

    export default {DEV, example as exp, expClass, obj};
    // OR
    export default obj;
    // OR
    export default const DEV = true;
    
    • 我们可以在 export 关键字后接 default 来设置模块的默认导出对象,需要注意的是:一个模块只能有一个默认导出。
  • 模块的导入与使用

    • 前文我们定义了一个名为 example 的模块,写在文件 example.js中,下面我们来导入并使用这个模块。
      import example from './example.js';
      // OR 
      import default as example from './example.js';
      
      
    • 使用 import 关键字导入一个模块,上边这两种写法是等效的。默认导入对象既是模块默认导出对象,即对应模块定义中的 export default 所导出的内容。
  • 此外我们还可以这样导入一个模块:

    import {DEV, example} from './example.js';
    import * as exp from './example.js';
    import {default as expMod, * as expAll, DEV, example as exp} from './example.js';
    
  • 这种导入方式对应模块定义中的 export {DEV, example, expClass, obj} 或 export const DEV = true。下面我们逐行分析:

  • 第一行,我们使用对象导入的方式导入一个模块内容,可能有些人已经发现,这跟解构赋值很相似,但也有不同,下面会讲到。需要注意的是形参对象({DEV, example})与模块定义中导出的名称必须保持一致。

  • 第二行,导入时可以使用通配符 * 配合 as 关键字一次性导出模块中所有内容,最终导入的内容放在 exp 对象中。

  • 第三行,在使用对象导入来导入一个模块的指定内容时,也可以使用 as 关键字更改最终导入对象的名称,这里表现出与解构赋值的一个不同之处,忘记解构赋值的小伙伴可以翻翻前文对比一下哈~

  • 最后,在导入一个模块后我们就可以直接使用模块的函数、变量、类等了,完整的代码示例:

    import {DEV, example, expClass as EC} from './example.js';
    
    if(DEV) {
        let exp = new EC();
        // anything you want...
        example();
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码の搬运工

记录学习,记录认知,记录。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值