2019-10-19:

-- 对比学习:ES3、ES5、ES6怎么实现同一个东西

我的学习:


  

一、课程环境准备:

前端大杂烩:http://github.com/cucygh/fe-material

webpack: 自动编译ES6代码。

  JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。


二、常量:

// ES5 中常量的写法:

Object.definceProperty(window,"PI2", {
   value: 3.1415926,
    writable: false,   // read only

})

console.log(window.PI2)
// ES6 中常量的写法:

const PI = 3.1415926
console.log(PI)

// 如果重新赋值会报错:
PI = 4

三、作用域:

// ES5 中的作用域

var callbacks = [];
for(var i=0; i<=2; i++){
    callbacks[i] = function() {
        return i*2
    }
}

console.table([
     callback[0](),
     callback[1](),
     callback[2](),
])

// 结果都是6, 原因:i变量提升了,(i*2)是一个闭包,循环完对闭包求值,此时全局i已经是3了。
// ES6 中的作用域

const callbacks2 = []
for (let j = 0; j <= 2; j++){
    callbacks2[j] = function(){
        return j * 2
    }
}

console.table([
    callbacks2[0](),
    callbacks2[1](),
    callbacks2[2](),
])


// 结果分别是:0, 2, 4
// 原因是:let建立的对象只用于当前块作用域,它会保存到这个块中,供这个闭包使用

立即执行函数:

// ES6中会转成箭头函数
(() ==>{
   const foo = function(){
        return 1
    }
})()

// ES5 常量作用域隔离写法:(复杂)
((function)(){
    var foo = function(){return 1}
    console.log("foo() ===1", foo() === 1)
     ((function){
        var foo = function(){return 2}
        console.log("foo() ===2", foo() === 2)
     }())
})())
// ES6 中常量的作用域隔离:

{
    function foo() {
        return 1
    }
    console.log("foo() ===1:", foo() === 1);
    {
        function foo() {
        return 2
        }
         console.log("foo() ===2:", foo() === 2);
    }

}

// 结果: 两个都是true。一个花括号就是一个作用域的隔离

三、箭头函数:

  省去function,简洁;

      () 为了放参数,只有一个时可以省略;

  { } 里直接作为返回值的话,可以省略。

/* eslint-disable */
{
     // ES3, ES5 的遍历
     var evens = [1, 2, 3, 4, 5];
     var odds = evens.map(function(v){
           return v + 1
     })
     console.log(evens, odds);
}
// ES6

{
    let evens = [1, 2, 3, 4, 5];
    let odds = evens.map(v => v + 1);
    console.log(evens, odds)
}
// ES5 声明类

{
    var factory = function(){
         this.a = 'a';
         this.b = 'b';
         this.c = 'c';
         a: 'a+',
         b: function(){
             return this.a
         }
    }
}

console.log(new factory().c.b());


// new factory()   new一个对象
// c 是新的实例,b()是方法
// 运行结果是 'a+', 因为this的指向是该函数被调用的对象,b()是c调用的,所以this指向c
// 箭头函数this的指向:

{
var factory=function(){ this.a = 'a'; this.a = 'a'; this.a = { a: 'a+', b: () => { return this.a } } } } console.log(new factory().c.b()) // 结果是a。原因是箭头函数this指向是定义时实例,就是factory

四、默认参数:

(1):

// ES3/ES5 默认参数的写法

{
      function f(x, y, z){
      if(y===undefined){
           y = 7;
      }
      if (z===undefined){
          z = 42
      }
      return x+y+z
   }
   console.log(f(1,3))
}

// 所有参数都要这样检查,很麻烦
// ES6 的默认参数:

{
    function f(x, y = 7, z = 42){
         return x+y+z
    }
    console.log(f(1,3))
}
// ES6 检查参数是否为空(没赋值):

{
    function checkParameter(){
         throw new ERROR('can\'t be empty')
    }
    function(x = checkParameter(), y=7, z=42){
        return x+y+z
    }
    console.log(f(1));
    try {
        f()
    }  catch (e) {
        console.log(e);
    }finally{

    }
}

// 利用异常函数提示错误

(2)函数对不定数量参数实现的区别:

// ES3/ES5 的可变参数: 不定数量参数的求和

{
    function f(x){
       var a = Array.prototype.slice.call(arguments)
       car sum=0;
       a.forEach(function(item){
           sum+=item*1;
    })
       return sum
    }
    console.log(f(1,2,3,6));
}

// Array.prototype.slice.call(arguments)  创建伪数组,利用数组实现不定量
// ES6 可变(数量)参数:

{
    function f(...a){
       var sum = 0;
       a.forEach(item=>{
           sum+=item*1
       });
       return sum
    }
     console.log(f(1,2,3,6))
}


// ... : 可变运算符,后面的a是一个列表表示可变数量

(3)合并数组的区别:

// ES5:

{
    var params = ['hello', true, 7];
    var other = [1, 2].concat(params);
    console.log(other);
}
// ES6:利用扩展运算符合并数组

{
     var params = ['hello', true, 7];
     var other  = [
     1,2, ...params
     ];
     console.log(other);
}

五、对象代理:

  proxyer是代理,打到保护proxy的目的。

(1):

//ES3 中数据保护:

{
    var person = function(){
         let data = {
              name: 'es3',
              sex: 'male',
              age: 15,
         }
          this.set = function(key, value){
              if (key !== 'sex'){
                  data[key] = value
              }
          }
    }
}

// 声明一个实例:
var person = new Person();
console.table({name: person.get('name')})
person.set('name', 'es3-cname');
console.table({name: person.get('name')})  // 名字被修改

person.set('sex', 'female');
console.table({sex: person.get('sex')})   // 性别修改无用
// ES5 中数据保护:只读要求固定死,过于死板

{
   var Person = {
       name: 'es5',
       age: 15
   };

   Object.defineProperty(Person, 'sex',{
       writable: false,
       value: 'male'
   });

   Person.name = 'es5-cname';
   console.table({name: Person.name});  // 成功修改

   Person.sex = 'female';
   console.table({sex: Person.sex});  // 报错,实现保护
}
// ES6 数据保护实现:操作的都是代理,元数据不受影响和操作。

{
   let Person = {
     name: 'es6',
     sex: 'male',
     age: 15
   };

   let Person = new Proxy(Person, {
      get(target, key) {
         return target[key]
      },
      set(target,  key, value){
         if (key!=='sex'){
            target[key]=value;
         }
      }
   });


   try{
      person.sex='female';
   } catch(e) {
      console.log(e);
   } finally {

   }
   console.table({})
}
01-16 01:06