8.1 ES6

304 阅读8分钟

1. 变量定义

1. var

  • 变量提升
  • 重新定义会覆盖
  • 变量提升只会提升变量名的声明,而不会提升变量的赋值初始化
    //相当于声明提升
    //var a;
    console.log(a);
    var a = 1;

2. let

  • 无变量提升

  • 不可重新定义

  • 块作用域

    作用于{ }内部

    for(let i = 0 ;i < aLi.length ; i++){
        console.log(i);
        //输出0 1 2
    }
    console.log(i);
    //报错
  • 闭包
  • 外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。
    for(let i = 0 ;i <= aLi.length ;i++){
        //一级作用域
        aLi[i].onclick = function(){
            //二级作用域
            console.log(i);
        }
    }

3. const

  • const 用于声明一个或多个常量,声明时必须进行初始化,不可重新赋值
  • 块级作用域
  • 不能和它所在作用域内的其他变量或函数拥有相同的名称
  • 使用 const 定义的对象或者数组,其实是可变的。下面的代码并不会报错
     const obj = {
            name:'xiaoming';
            age:'2';
        }
        obj.age = '3';
        console.log(obj);//修改成功
        obj = {
            name:'xiaoming';
            age:'4';
        }
        console.log(obj);//报错
  • const 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的

2. 暂时性死区

  • 在代码块内,使用let声明变量之前,该变量都是不可用的
    var x =5; 
    var fun = function(){
        console.log(x);
        //报错
        let x;
    }

3. 冻结

  • 冻结后不可修改 但修改后不报错 显示原来信息
    Object.freeze(obj);

4. 变量解构赋值

解构 :从数组和对象中提取值,对变量进行赋值

1. 数组的解构

  • 按照顺序依次赋值
    var [a,b,c] = [1,2,3];

2. 对象的解构

  • 按照key赋值
    let {name,age} = {name:'xm',age:4};
    console.log(name,age);
    //取别名
    let {name:x,age} = {name:'xm',age:4};
    console.log(x,age);

3. 字符串的解构

  • 把字符串中每一个字符提取出来分别进行赋值
    const [a,b,c,d,e] = 'hello';
    console.log(a); //h
    console.log(b); //e
    console.log(c); //l
    console.log(d); //l
    console.log(e); //o
    
    let { length : len} = 'yahooa';
    console.log(len); //5

4. 解构用途

  • 深拷贝
    let x = 2;
    let y = 3;
    [y,x]=[x,y];
    console.log(x);//3
    console.log(y);//2

5. 扩展运算符(...)

1. 数组

  • 数组合并
  • 数组复制(深拷贝)
    • JSON.stringify( ) JSON.parse
    • deepClone()
    • 解构运算符
    • concat( ) silce( ) 只是对数组的第一层进行深拷贝
    let array = [1,2,3]
    var a1 = [...array]; // 复制一个数组 可以实现数组的深拷贝
    console.log(a1); //[1,2,3]
    
    let a2 = [...array,'a','b'] //作为数组的一部分
    console.log(a2);//[1,2,3,'a','b']
    
    let a3 = array;
    console.log(a3) //[1,2,3]
    array[0] = 4;
    console.log(a3) //[4,2,3]
    console.log(a1); //[1,2,3]
    
    let a4 = [4,5,6]
    let a5 = [...array,...a4] // 数组的合并
    console.log(a5)//123456
    console.log(array)//123
    console.log(a4)//456
    
    let a6 = [1,2,3]
    let a7 = [4,5,6]
    console.log(a6.concat(a7))//123456
    console.log(a6)//123
    console.log(a7)//456

2. 对象

  • 合并对象
  • 不同的属性会合并,相同的属性 后面的会把钱前面的覆盖
  • 对象深拷贝
    • deepClone( )
    • 扩展运算符
    let p1 = {
        name: 'xm',
        age: '4'
        }
    let p2 = {...p1}
    p1.age = 2;//p2不会改变

    let p1 = {
        name: 'xm',
        age: '4'
        }
    let p2 = {
        weight: '8kg',
        age: '2'
    }
    let p3 ={...p2,...p1} // 对象的合并 

.

3. 类数组转数组

  • 扩展运算符
  • Array.from( )
    let aLi = document.querySelectorAll('li'); //NodeList
    console.log(aLi);
    let b = [];
    for(let c = 0; c<aLi.length; c++){
        b[c] = aLi[c]
    }
    console.log(b)
    let aList = [...aLi]; // 可以将类数组转换成数组
    console.log(aList);
    aList.push('wxc');
    console.log(aList);
    let b1 = document.getElementsByTagName('li'); //HTMLCollection
    console.log(b1)
    //  rest 剩余的
    function fun(x,...rest){
        console.log(x);
        console.log(rest);
    }
    fun(1,2,3,4)
    console.log('----------')
    function fun1(){
        // arguments.callee 当前方法
        console.log(11111)
        // arguments.callee() 递归调用
    }
    fun1(1,2,3,4)

6. rest

    function fun(x...rest){
        console.log(x);//1
        console.log(rest);//234
    }
    fun(1,2,3,4);

7. 函数的扩展

1. fun.length

获取没有设置默认值的形参个数

2. fun.name

获取方法名

3. 箭头函数 =>

  • this指向父作用域this
  • 不可以使用arguments获取参数,可以使用rest获取参数
  • 函数中只有一行代码 { } 可以省略
    // 箭头函数中不可以使用arguments获取参数,可以使用rest获取参数
    var fun3 = (...rest) => {
        console.log(rest);
        rest[0];
    }
    fun3(1,2,3)

4. arguments

  • 一个数组
  • 方法不设形参时 用arguments接受传的参数
  • arguments.callee 当前正在执行的函数(本身),递归
    function fun([x,y,z=4]){ // 设置默认值 
    //只有是undefined的时候才会使用默认值
          console.log(x,y,z)
        }

8. 模板字符串

  • 使用 `` 包裹字符串
  • 拼接 `` 括起来后 用${ }拼接
    `Hello ${name}, how are you ${time}?`

9. 字符串方法

1. Number.includs( )

检索字符串 返回true/false

2. Number.startsWith( )

返回布尔值 表示参数字符串是否在原字符串的头部

3. Number.endsWith( )

返回布尔值 表示参数字符串是否在原字符串的尾部

4. padStart()用于头部补全,padEnd( )用于尾部补全

  • 如果省略第二个参数,默认使用空格补全长度
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(0, 'ab') // 'x'

5. repeat(n)

  • 返回一个新字符串,表示将原字符串重复n次
    'x'.repeat(3) // "xxx"

10. 数值的扩展

1. Number.isFinite( )

  • 用来检查一个数值是否为有限finite
    Number.isFinite(15); // true
    Number.isFinite(0.8); // true
    Number.isFinite(NaN); // false
    Number.isFinite(Infinity); // false
    Number.isFinite(-Infinity); // false
    Number.isFinite('foo'); // false
    Number.isFinite('15'); // false
    Number.isFinite(true); // false
  • 如果参数类型不是数值,Number.isFinite返回false。

2. Number.isNaN( )

  • 用来检查一个值是否为NaN。
    Number.isNaN(NaN) // true
    Number.isNaN(15) // false
    Number.isNaN('15') // false
    Number.isNaN(true) // false
    Number.isNaN(9/NaN) // true
    Number.isNaN('true' / 0) // true
    Number.isNaN('true' / 'true') // true
  • 如果参数类型不是NaN,Number.isNaN返回false。

3. Number.isInteger( )

  • 用来判断一个数值是否为整数
    Number.isInteger(25) // true
    Number.isInteger(25.1) // false
    Number.isInteger('15') // false

5. Number.parseInt( )Number.parseFloat( )

  • 转为整数/浮点数
    Number.parseInt('12.34') // 12
    Number.parseInt(5.1) // 5
    Number.parseFloat('123.45#') // 123.45

11. Math对象扩展

1. Math.trunc( )

  • Math.trunc方法用于去除一个数的小数部分,返回整数部分。
    Math.trunc(4.1) // 4
    Math.trunc(4.9) // 4
    Math.trunc(-4.1) // -4
    Math.trunc(-4.9) // -4
    Math.trunc(-0.1234) // -0

2. Math.sign( )

  • 判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。

    • 正数 返回 +1
    • 负数 返回 -1
    • 0 返回 0
    • -0 返回-0
    • 其他 返回 NaN

12. 数组扩展

1. Array.from( )

  • 将对象转为真正的数组(类数组的对象/对象)

2. Array.of( )

  • 将值转换为数组
    Array.of(3, 11, 8) // [3,11,8]
    Array.of(3) // [3]

3. array.copyWithin( )

  • 在当前数组内部,将指定位置的成员复制到其他位置(覆盖原有成员),然后返回当前数组,会修改当前数组
    Array.prototype.copyWithin(target, start = 0, end = this.length)
- target(必需):从该位置开始替换数据。如果为负值,表示倒数。
- start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
    // 将3号位复制到0号位
    [1, 2, 3, 4, 5].copyWithin(0, 3, 4)
    // [4, 2, 3, 4, 5]
    
    // -2相当于3号位,-1相当于4号位
    [1, 2, 3, 4, 5].copyWithin(0, -2, -1)
    // [4, 2, 3, 4, 5]
    
    // 将3号位复制到0号位
    [].copyWithin.call({length: 5, 3: 1}, 0, 3)
    // {0: 1, 3: 1, length: 5}
    
    // 将2号位到数组结束,复制到0号位
    let i32a = new Int32Array([1, 2, 3, 4, 5]);
    i32a.copyWithin(0, 2);
    // Int32Array [3, 4, 5, 4, 5]
    
    // 对于没有部署 TypedArray 的 copyWithin 方法的平台
    // 需要采用下面的写法
    [].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
    // Int32Array [4, 2, 3, 4, 5]

4. array.find( )

  • 用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
    //找出数组中第一个小于 0 的成员。
    [1, 4, -5, 10].find((n) => n < 0)
    // -5
    
    [1, 5, 10, 15].find(function(value, index, arr) {
      return value > 9;
    }) // 10

5. array.findIndex( )

  • 返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
    [1, 5, 10, 15].findIndex(function(value, index, arr) {
      return value > 9;
    }) // 2

6. array.fill( )

  • 使用给定值,填充一个数组。
    ['a', 'b', 'c'].fill(7)
    // [7, 7, 7]
    
    new Array(3).fill(7)
    // [7, 7, 7]
    
  • fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
    ['a', 'b', 'c'].fill(7, 1, 2)
    // ['a', 7, 'c']

7. for...of

  • 循环输出数组每一项值
  • keys()是对键名的遍历
  • values()是对键值的遍历
  • entries()是对键值对的遍历
    for(ietm of p){
        console.log(item);
    }
    
    for (let index of ['a', 'b'].keys()) {
      console.log(index);
    }
    // 0
    // 1
    
    for (let elem of ['a', 'b'].values()) {
      console.log(elem);
    }
    // 'a'
    // 'b'
    
    for (let [index, elem] of ['a', 'b'].entries()) {
      console.log(index, elem);
    }
    // 0 "a"
    // 1 "b"

8. array.includes( )

  • Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值
    [1, 2, 3].includes(2)     // true
    [1, 2, 3].includes(4)     // false
    [1, 2, NaN].includes(NaN) // true

9. array.forEach( )

  • 遍历数组
    p.forEach(function(value,key,arry){
        console.log(value);
    })

10. array.filter( )

  • 返回所有符合条件的内容的数组
    [1, 5, 10, 15].filter(function(value, index, arr) {
      return value > 9;
    }) // 10 15

13. 对象的扩展

1. 属性的简洁表示法

    let name = 'xc';
    let age = '18';
    
    let obj = {
        name,//属性简写
        age,
        eating(){//方法简写
            console.log('meat');
        }
    }

2. 属性名表达式

  • JavaScript 定义对象的属性,有两种方法
    // 方法一
    obj.foo = true;
    
    // 方法二
    obj['a' + 'bc'] = 123;
    let lastWord = 'last word';
    
    const a = {
      'first word': 'hello',
      [lastWord]: 'world'
    };
    
    a['first word'] // "hello"
    a[lastWord] // "world"
    a['last word'] // "world"

3. Object.is( )判断严格相等

    +0 === -0 //true
    Object.is('-0',+0) //false
    NaN === NaN //false
    Object.is('NaN',NaN) //true

4. assign( )

  • 方法用于对象的合并
  • 如果只有一个参数,Object.assign会直接返回该参数。
  • 如果该参数不是对象,则会先转成对象,然后返回。
    const target = { a: 1, b: 1 };
    
    const source1 = { b: 2, c: 2 };
    const source2 = { c: 3 };
    
    Object.assign(target, source1, source2);
    //target {a:1, b:2, c:3}
    
    //如果只有一个参数,Object.assign会直接返回该参数。
    const obj = {a: 1};
    Object.assign(obj) === obj // true
    
    //如果该参数不是对象,则会先转成对象,然后返回。
    typeof Object.assign(2) // "object"

5. Object.keys Object.values Object.entries

  • 作为遍历一个对象的补充手段,供for...of循环使用
  • 返回数组
    let {keys, values, entries} = Object;//对象解构赋值
    let obj = { a: 1, b: 2, c: 3 };
    
    for (let key of keys(obj)) {
      console.log(key); // 'a', 'b', 'c'
    }
    
    for (let value of values(obj)) {
      console.log(value); // 1, 2, 3
    }
    
    for (let [key, value] of entries(obj)) {
      console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
    }

6. 'name' in object

  • 对象是否具有属性
  • 返回布尔值

14. AJAX

  • 异步 JavaScript 和 XML。
  • AJAX 是一种用于创建快速动态网页的技术。

1. 创建XMLHttpRequest对象

  • 为了应对所有的现代浏览器,请检查浏览器是否支持 XMLHttpRequest 对象。如果支持,则创建 XMLHttpRequest 对象。如果不支持,则创建 ActiveXObject
    var xmlhttp;
    if (window.XMLHttpRequest){//code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    }
    else{//code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }

2. 请求

方法 描述
open(method,url,async) 规定请求的类型、URL 以及是否异步处理请求。
method:请求的类型GET 或 POST
url:文件在服务器上的位置
async:true(异步)或 false(同步)
send(string) 将请求发送到服务器。
string:仅用于 POST 请求
    xmlhttp.open("GET","test1.txt",true);
    xmlhttp.send();

3. 响应

  • XMLHttpRequest 对象的三个重要的属性
属性 描述
onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState 存有 XMLHttpRequest 的状态。
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
status 200: "OK"
400:请求出现语法错误
404: 未找到页面
500:服务器错误
505:HTTP版本不受支持”,当服务器不支持请求中所使用的HTTP协议版本
304:客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。
    xmlhttp.onreadystatechange=function(){
        if (xmlhttp.readyState==4 && xmlhttp.status==200){
        document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
        }
    }

15. jquery ajax

1. jQuery.ajax( url [, settings ] )

  • 执行一个异步的HTTP(Ajax)的请求。

  • url

    类型: String 一个用来包含发送请求的URL字符串。

  • settings

    类型: PlainObject 一个以"{键:值}"组成的AJAX 请求设置。所有选项都是可选的。可以使用$.ajaxSetup()设置任何默认参数。看jQuery.ajax( settings )下所有设置的完整列表。

    $.ajax({
      accepts: {
        mycustomtype: 'application/x-some-custom-type'
      },
      // Instructions for how to deserialize a `mycustomtype`
      converters: {
        'text mycustomtype': function(result) {
          // Do Stuff
          return newresult;
        }
      },
      // Expect a `mycustomtype` back from server
      dataType: 'mycustomtype'
    });

2. jQuery.get( url [, data ] [, success ] [, dataType ] )

  • 使用一个HTTP GET请求从服务器加载数据。
    • url

      类型:String 一个包含发送请求的URL字符串.

    • data

      类型:PlainObject or String 一个普通对象或字符串,通过请求发送给服务器。

    • success

      类型:Function( PlainObject data, String textStatus, jqXHR jqXHR ) 当请求成功后执行的回调函数。 如果提供dataType选项,那么这个success选项是必须的, 但你可以使用null或jQuery.noop作为占位符。

    • dataType

      类型:String 从服务器返回的预期的数据类型。默认:智能猜测(xml, json, script, text,html)。

    $.ajax({
        url: url,
        data: data,
        success: success,
        dataType:dataType,
        method:method
    });
    $.get('ajax/test.html', function(data) {
        $('.result').html(data);
        alert('Load was performed.');
    });

16. 基本数据类型

1. symbol

  • 独一无二的值不会与其他属性重复
  • 对象下属性是symbol不会在for...in循环出来
    let obj = {
        name : 'xiaoming',
        age : '18'
    }
    let height = Symbol ( );
    obj [height] = "180cm"//for in中无

2. set

  • 类似于数组
  • 数组去重
    let arr = [4, 1, 3, 3, 2, '2'];
    let uniqueArr = [...new Set(arr)];
    console.log(uniqueArr); // [4, 1, 3, 2, "2"]
  • set.add(value) 添加某个值
  • set.delete(value) 删除某个值,返回布尔值,表示删除是否成功
  • set.has(value) 返回一个布尔值,表示该值是否为Set的成员
  • set.clear() 清除所有成员,没有返回值
  • set.size长度
    let s =  new  Set();
    
    s.add(1).add(2).add(2);
    // 注意2被加入了两次
    
    s.size // 2
    
    s.has(1) // true
    s.has(2) // true
    s.has(3) // false
    
    s.delete(2);
    s.has(2) // false

3. map

  • 类对象
  • map.set('key', 'value')
  • map.get('key')
  • map.delete('key') 删除某个值,返回布尔值,表示删除是否成功
  • map.has('key') 返回一个布尔值,表示该值是否为Map的成员
  • map.clear() 清除所有成员,没有返回值
  • set.size长度
  • 类对象转化成对象
    let a = new Map([
        [1, 'one'],
        [2, 'two'],
        [3, 'three'],
    ]);
    let b = {};
    a.forEach(function (value, key) {
        console.log(key);
        b[key] = value;
    })
    console.log(b);

17. promise(异步编程)

  • Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
  • resolve 成功回调
  • reject 失败回调

1. Promise.prototype.then()

  • 为 Promise 实例添加状态改变时的回调函数

2. Promise.prototype.catch()

  • 用于指定发生错误时的回调函数
    const promise = new Promise(function(resolve, reject) {
        if (/* 异步操作成功 */){
            resolve(value);
        } else {
            reject(error);
        }
    });
    //方法一
    const promise = new Promise(function(resolve, reject) {
        setTimeout(function(){
           reject(); 
        },2000)
 
    }).then(function(){//成功
        //code
    }).catch(function(){//失败
        //code
    });
    
    //方法二
    const promise = new Promise(function(resolve, reject) {
        setTimeout(function(){
           reject(); 
        },2000)
 
    }).then(function(){//成功
        //code
    },function(){//失败
        //code
    });

3. Promise.prototype.finally()

  • finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

4. Promise.all

  • 用于将多个 Promise 实例,包装成一个新的 Promise 实例。
  • 接受一个数组作为参数,p1、p2、p3都是 Promise实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
    // 生成一个Promise对象的数组
    const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
      return getJSON('/post/' + id + ".json");
    });
    
    Promise.all(promises).then(function (posts) {
      // ...
    }).catch(function(reason){
      // ...
});

5. Promise.race

  • 同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
  • 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
    const p = Promise.race([p1, p2, p3]);

18. 类

1. ES5继承

  • ES5继承
    function Person(_name, _age){
        this.name = _name,
        this.age = _age
    }
    Person.prototype.eat = function(){
        console.log(111)
    }
    function Student(_name,_age){
        Person.call(this, _name, _age);//继承父类属性
   }
   Student.prototype = new Person();//指向父类原型
   Student.prototype.constructor = Student;//指向自己构造方法
   let s1 = new Student('jj',18);
   console.log(s1.eat);
   s1.eat();//调用父类方法

2. ES6继承

  • ES6 可以通过extends关键字实现继承
  • 父类的静态方法,也会被子类继承。
  • 静态方法只能通过类名调用
    class Point {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }
        static hello() {
            console.log('hello world');
        }
        toString() {
            console.log('red')
        }
    }
    
    class ColorPoint extends Point {
        constructor(x, y, color) {
            this.color = color; // ReferenceError
            super(x, y);// 调用父类的constructor(x, y)
            this.color = color; // 正确
        }
        toString() {
            return this.color + ' ' + super.toString(); // 调用父类的toString()
        }
    }
    ColorPoint.hello();//hell world

19. Generator(异步编程)

  • Generator函数是ES6提供的一种异步编程解决方案
    function* fun() {
        console.log("start");
        yield request();//yield语句执行完成后停止
        console.log("end");
    }
    function request() {
        setTimeout(() => {
            console.log("success");
        }, 2000)
    }
    let _fun = fun();//指针对象
    console.log(_fun.next());//{value: yield返回值, done: false}
    _fun.next();
    console.log(_fun.next());//next可传值,是上一个表达式返回值

20. async(异步编程)

    async function fun() {
        console.log("start...");
        let data = await request();
        console.log(data);//14
        let data1 = await request1(data);//拿到上次的返回结果
        console.log(data1);//16
        console.log("end...");
    }
    function request(){
        return new Promise(function(resolve,reject){
        setTimeout(() => {
            let obj = {
                name: 'jj',
                age: 18
            }
            console.log("success");
            resolve(obj);
            }, 2000)
        })
    }
    function request1(_tmp){
        console.log(_tmp);//32
        return new Promise(function (resolve, reject) {
            setTimeout(() => {
                let obj = {
                    name: 'ccc',
                    age: 1
                }
                console.log("success1");
                resolve(obj);
            }, 2000)
        })
    }
    fun();
    //打印结果
    1.html:12 start...
    1.html:26 success
    1.html:14 {name: "jj", age: 18}
    1.html:32 {name: "jj", age: 18}age: 18name: "jj"__proto__: Object
    1.html:39 success1
    1.html:16 {name: "ccc", age: 1}
    1.html:17 end...

21. proxy

  • Proxy 用于修改某些操作的默认行为(拦截)
    let obj = {
        name: 'ccc',
        age: 1
    }
    //拦截对象
    let pro  = new Proxy(obj,{
        set(target,key,property){
            console.log(target, key, property);//{name: "ccc", age: 1} "name" "11111"
            target[key] = property;//实际应用中property改写成需要的数值
        },
        get(target, key, property){
            console.log(target, key, property);//{name: "11111", age: 1}"name" Proxy-{name: "11111", age: 1}
            return target[key];
        }
    })
    pro.name = '11111';
    console.log(obj);//{name: "11111", age: 1}
    console.log(pro.name);//11111