ES6-函数参数默认值

235 阅读5分钟

ES6-函数参数默认值

定义函数的同时,可以给形参一个默认值

目前浏览器 支持的js的代码版本

主要都支持 es5 (for if while 函数 forEach ) 版本

新的语法 es6 (提供了更加简单强大的代码更能力) 提高我们的开发效率

示例

        // es6函数参数默认值
        // 你好 默认值
        function show(msg = '你好', str = '大家好'){
            console.log(msg,str);
        }
        show() // 没有传递参数 输出 你好 大家好
        show('大家不好') // 没有传递参数 输出 大家不好 大家好
        show('大家不好','我吐了呀') // 没有传递参数 输出 大家不好 我吐了呀

set( )

永远不会有重复元素的对象

可以理解为不重复的数组

set对象 是es6 才推出 主要的功能 去重处理

set是一个对象,不是一个数组!!

​ 实现 使用set转成数组的时候,需要考虑 (set对象转-数组 数组 - 转成对象)

​ 数组 - 转成对象 new Set(beforeArr)

​ set对象转-数组 const arr=[...set];

1650808451619.png

set( )

    <input type="text" />
    <ul></ul>
    <script>
      const input = document.querySelector('input');
      const ul = document.querySelector('ul');
      let arr = ['a', 'b'];
      render();

      input.addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
          const set = new Set(arr);
          set.add(this.value);
          arr = [...set];
          render();
        }
      });

      function render() {
        const html = arr.map((value) => `<li>${value}</li>`).join('');
        ul.innerHTML = html;
      }
    </script>

对象简写

在定义对象的时候,如果属性名和变量名一直,那么可以实现简写

示例

      // 简写 如果变量的名字和属性的名字 一致的话,对象可以简写

        // const obj = {
        //   // 属性名 和 属性值
        //   username: 123,
        // };
        const username = 123;
        const color = 'red';

        const say = function () { };

        function show() { }

        // 很常用
        const obj = {
            username, // username:username
            color, // color : color
            say,
            show,
            height: 100,
        };
        obj.height = 200;
        // console.log(obj);

        // 对象中方法的简写
        const person = {
            show: function () {
                console.log("show");
            },// 常规写法
            // es6 关于 方法简写
            say() {
                console.log("say");
            } // es6 关于 方法简写
        }
        person.show();
        person.say();

        /*
        小结:
        1 变量名如果和你的对象的属性名一致 可以简写
           let username='悟空'
           const obj = { username }
  
        2 对象的方法 简写
          const obj ={
            say(){  // 简写的方法
            }
          }
         */

解构

提供更加方便获取数组中元素或者对象中属性的写法

<div data-index="100" data-num="200">div</div>
    <script>
      // dataset = { index:100}
      // const dataset= document.querySelector('div').dataset;
      // const { index,num } = document.querySelector('div').dataset;
      // console.log(dataset);
      // const {index}=dataset;
      // console.log(index);
      // console.log(num);
      // const arr = ['悟空', '八戒', '龙马', '三藏'];
      // const a = arr[0];
      // const b = arr[1];
      // const c = arr[2];
      // const d = arr[3];

      // 数组解构
      // const  [a,b,c,d]=arr;
      // const [a, b, c, d] = ['悟空', '八戒', '龙马', '三藏',"沙僧"];
      // console.log(a, b, c, d);

      // 对象的解构
      // const obj = {
      //   username: '悟空',
      //   height: 100,
      // };

      // 声明两个变量 来获取obj的两个属性
      // low 代码!!!
      // const username = obj.username;
      // const height = obj.height;

      // 对象解构
      // const { username, height } = obj;
      // console.log(username, height);

      // 解构 + 默认值
      // const arr = [1,100];
      // const [a,b ] = arr; a = 1 b=undefined
      // const [a, b = 2] = arr;
      // console.log(a, b); // a =1  b = 2

      // b = 2 默认值 (你没有,就使用我,你有,使用你的)
      // const [a, b = 2] = arr;
      // console.log(a,b);

      const obj = {
        username: 100,
        height: 500,
      };
      const { username, height = 200 } = obj;
      console.log(username, height);

      /* 
      小结
      1 解构 对象 和 数组上
        对象 
        const  { username,height } = {username:"悟空",height:200}
        数组
        const [a,b]=[100,200];

     2 解构 + 默认值
       如果 右边的对象中没有height 属性 那么 height变量 =  1000 
       const  { username,height=1000 } = {username:"悟空",height:200} 
        
      //  c 在右边找不到对应的数据 c 就使用默认值 300 
        const [a,b,c=300]=[100,200];
       */
    </script>

拓展运算符-剩余运算符-延展运算符

通过 ...符号来获取剩下的参数

函数内获取

    function show(a, ...all) {		// 只能放最后
      console.log(a);
      console.log(all);
    }
    show(1);// 1 []
    show(1, 2, 3);// 1 [2,3]
    //   获取剩下 用在函数的形参上

      // 计算数据和的功能
      // calc(1,2)// 1 + 2
      // calc(1,2,3) // 1 + 2 + 3
      // calc(1,2,3,4) // 1 + 2 + 3 + 4
      function calc(...args) {
        // args 数组 装载这所有传给calc的参数
        // console.log(args);
        let sum = 0;
        args.forEach((value) => (sum += value));
        console.log(sum);
      }
      calc(1, 2); // ? [1,2]
      calc(1, 2, 3); // [1,2,3]
      calc(1, 2, 3, 4); // [1,2,3,4]

数组内获取

    const [a, ...rest] = [1, 2, 3, 4, 5];
    console.log(a); // 1
    console.log(rest);// [2, 3, 4, 5]
      const [...a]=[1,2,3,4];
      console.log(a);// [1,2,3,4]
      console.log(a.map);
      const lis = document.querySelectorAll('li');// lis 伪数组 没有map方法
      const newList = [...lis]; // 如何理解 ? 转成真正的数组
      console.log(newList.map);

      // 获取剩下 用在函数的形参上

对象内获取

    const obj={
      name:"悟空",
      skill:"72变",
      say(){}
    }

    const {name,...others}=obj;
    console.log(name); // 悟空
    console.log(others); // {skill: "72变", say: ƒ}
      // 获取剩下 对象
      const { a, ...c } = { a: 1, b: 2, c: 3 };
      const { a,b,c ,...d } = { a: 1, b: 2, c: 3 };
      console.log(c);// ? {b:2,c:3}
      console.log(d); // ?

剩余运算符

      1 数组中  const [a,b,...c]=[1,2,3,4,5,6,7];  c =[3,4,5,6,7]
        应用场景 伪数组转真正的数组
      2 对象中  const { a,...d } = { a: 1, b: 2, c: 3 }; // d = {b:2,c:3 }
      3 函数的形参中  
        calc(1, 2, 3);   function calc(...args) {}  // args = [1,2,3]
       计算数字总和 

计算数据和

练习题目

    getMax(1,2,3) // 输出3 
    getMax(1,4) // 输出4
    getMax(1,20,4) // 输出20 
    getMax(1,20,4,30,2) // 输出30
// 计算最大值的写法 
      function getMax(...args) {
        // args= 数组  接收 所有传递给 getMax方法的 参数
        // console.log(args);
        // 计算最大值 的
        let max = args[0];
        args.forEach((value) => {
          if (value > max) {
            max = value;
          }
        });
        console.log(max);
      }

      // getMax(1);
      // getMax(1, 2);
      // getMax(1, 2, 3);
      // getMax(11, 33, 2, 3);

      // Math对象 自己就封装过 计算最大值和最小值的代码
      // console.log(Math.max(1,3,4,2));// 4
      // console.log(Math.min(1,3,4,2));// 1

      function getMax2(...args) {
        // Math.max(1,3,4,2)
        // args=[1,3,4,3]
        // Math.max([1,3,4,3]) =>  Math.max(1,3,4,2)
        // 剩余运算符的

        console.log(  Math.max(...args));
      }
      // getMax2(1,2,3);
      // getMax2(1,2,33);
      // console.log(Math.max(...[1,3,4,3])); //  Math.max(1,3,4,2)

      getMax2(1,2,3,4); // 体现的思想 不再是 剩余 。  展开-延展-拓展 思想 
      
      
         // 计算最大值的写法 
        function getMax(...max){
            console.log(Math.max(...max));
        }
        getMax(1, 2, 3)
        getMax(1, 4)
        getMax(1, 20, 4)
        getMax(1, 20, 4, 30, 2)

展开 ... 对象的用法

      // 展开 ... 用法
      const obj = {
        username: '悟空',
        height: 200,
      };
      const newObj = obj;// 对象是引用类型   写 =  将 obj的地址 给了一份 newObj  两个变量指向的地址同样的 同一个对象
      newObj.color = 'yellow';
      console.log("新的对象",newObj);
      console.log("旧的对象",obj);
      const obj = {
        username: '悟空',
        height: 200,
      };

      // 新创建一个对象 这个对象 具有 所有 obj的属性
      // 同时 还有多一个属性,color

      const newObj = { ...obj, color: 'yellow' }; // 给newObj 开辟新的内存空间
      // const newObj={ username:"悟空",height:20}; // 给newObj 开辟新的内存空间
      newObj.username = '八戒';
      newObj.weight = 100;
      console.log(obj);
      console.log(newObj);

展开运算符 对数组操作

      const arr = ['a', 'b', 'c'];
      // 在数组的后面 新增一个 元素 'd'
      const newArr=[...arr,'d'];
      console.log(newArr);
      const arr = ['a', 'b', 'c'];
      // 在数组宅前面 新增一个属性 w
      const newArr = ['w', ...arr];
      console.log(newArr);

JQ的演示

    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
      <li>9</li>
      <li>10</li>
    </ul>
     <script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.js"></script>
     <script>
      //  简单 比js高级 简单多了 不是一个量级!! 
       $(function () {
         $("li").click(function () {
          //  1 点击 激活选中 其他li标签排他
          // $(this).css("backgroundColor","red").siblings().css("backgroundColor","#fff");

          // 2 点击 渐变 显示和消失
          // $(this).fadeToggle()

          // 3 手风琴
          // $(this).slideUp();
          
        })
       })
     </script>

函数的四种调用模式

根据函数内部this的指向不同,可以将函数的调用模式分成4种

  1. 函数调用模式
  2. 方法调用模式
  3. 构造函数调用模式
  4. 上下文调用模式(借用方法模式)

函数调用模式

如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window

1650808557465.png

<script>
      function func1() {
        console.log(this);
      }

      // func1(); // this =   window   定义在全局的函数 理解为window的一个属性
      // window.func1(); // this =   window   定义在全局的函数 理解为window的一个属性

      // const obj={
      //   name:"悟空",
      //   say(){
      //     console.log(this);
      //   }
      // }
      // obj.say();// this = ?

      function Person() {
        this.name = '悟空';
      }
      Person.prototype.say = function () {
        console.log(this);
      };
      const p1 = new Person();
      p1.say(); // this = p1
      console.log(p1);
    </script>

方法调用模式

当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象

const obj = {
  sayHi:function(){
    console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
  }
}
obj.sayHi();
<script>
      // 在js中,顶级的对象 就是window

      // 定义一个函数 形式是箭头函数的
      // const func = () => {
      //   console.log(this);
      // };

      // func();

      // const obj = {
      //   name: '悟空',
      //   say: () => {
      //     console.log(this);
      //   },
      // };
      // obj.say(); // window

      // const obj1 = {
      //   name: '悟空1',
      //   obj2: {
      //     name: '悟空2',
      //     say: () => {
      //       console.log(this);
      //     },
      //   },
      // };
      // obj1.obj2.say();

      const button = document.querySelector('button');
      // button.addEventListener('click', function () {
      //   console.log(this); // this = button
      // });
      button.addEventListener('click',  ()=> {
        console.log(this);// this = 谁 
      });

      /* 
      大部分情况,对于普通函数,this 等于这个函数的调用者
        (例外 - bind、call、apply)
      大部分情况,对于箭头函数,this 等于window
        箭头函数和this 一起用的话,要慎用!! 
        例外(面向对象用法,)
       */
    </script>

构造函数调用模式

如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上

function Person(){
  console.log(this);
}
Person();//this指向什么?
const p = new Person();//this指向什么?

方法借用模式

也叫上下文模式,分为 apply 与 call

call

call方法可以调用一个函数,并且可以指定这个函数的this指向

    const RichWumon = {
      name: "富婆",
      say: function () {
        console.log(this.name, " 我要重金求子");
      }
    }

    const obj = {
      name: "屌丝"
    }

    RichWumon.say();			// 富婆
    RichWumon.say.call(obj);	// 屌丝

apply

就是apply()方法接受的是一个包含多个参数的数组。而call()方法接受的是若干个参数的列表

        const obj = {
            name: '小明',
            skill(a, b) {
                console.log(this.name + ' ' + a + ' ' + b);
            }
        }

        const person = {
            name: '小红',
        };
        obj.skill.apply(person, [5, 6]) // 传参用数组方式填写

bind方法

bind()方法创建一个新的函数, 可以绑定新的函数的this指向

const name = '张三';
function Fn(){
    this.age = 1;
    
    console.log(this.name + this.age);
}

Fn();			// 张三 1

// 返回值:新的函数
// 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
let obj = {
    name:'小强',
}
const newFn = Fn.bind(obj);
newFn();		// 小强 1

bind-call-apply修改this指向

    <script>
        /* 
     1 bind call  apply 都可以实现修改this指向
     2 代码写法上有区别
       1 obj.skill.call(person);
       2 obj.skill.apply(person);
       3 const func = obj.skill.bind(person);
         func();
     3 传递参数
       1 obj.skill.call(person,参数1,参数2)
       2 obj.skill.apply(person,[参数1,参数2])
       3 const func = obj.skill.bind(person);
         func(参数1,参数2)
     
      */
        const obj = {
            name: '小明',
            skill(a, b) {
                console.log(this.name + ' ' + a + ' ' + b);
            }
        }

        const person = {
            name: '小红',
        };
        obj.skill.call(person, 5, 6) // 传参
        obj.skill.apply(person, [5, 6]) // 传参用数组方式填写
        const func = obj.skill.bind(person) // 
        func(8, 9)

        // obj.skill.call(person,1,2);// 传参
        // obj.skill.apply(person, [1, 2]); // 数组

        // 在早些时候 我们是这样来计算 数组最大值和最小值

        // const max = Math.max(1, 2, 3, 4);
        // console.log(max);
        // const arr=[1,2,3,4];
        // 借用 Math.max方法 目的不是修改this指向
        // 而是 计算数组最大值

        // const max = Math.max.apply(null,arr);


        // 这种
        // const arr=[1,2,3,4];
        // console.log(Math.max(...arr));
    </script>

bind-call-apply传递参数

    <script>
      /* 
      1 bind call apply 都可以修改this的指向  

      2 分别演示 修改this指向
        call  obj.skill.call(person)
        apply obj.skill.apply(person)
        bind  
         const func = obj.skill.bind(person);
         func(); 

      3 传递参数的时候不同写法上 

       */

      const obj = {
        name: '老王',
        skill() {
          console.log(this.name + '  翻墙');
        },
      };

      const person = {
        name: '大郎',
      };

      // call 方式来修改this的指向
      // obj.skill.call(person);// 大郎 借用老王的方法

      // apply 方式来修改this的指向
      // obj.skill.apply(person); // 大郎 借用老王的方法

      // bind 方式来修改this指向
      // bind 不会直接调用skill函数 而是 返回一个新的函数
      // 需要我们主动的调用新的函数- 调用skill()
      const func = obj.skill.bind(person);
      func();
    </script>

ES6 面向对象

es6的class 的出现 基本上可以替代了es5的构造函数和原型,使之代码结构上更加简洁。

  1. class
  2. 属性
  3. 方法
  4. 继承 extends
  5. 构造函数 constructor
  6. 方法重写 override:子类方法覆盖父类,super.父类方法()
  7. 父类的构造函数 super :子类有构造方法且使用this前,必须使用super()

es5的面向对象

<script>
      // es5 写一个 构造函数 首字母是大写
      // 当我们new 一个 对象的时候 Person 代码会被执行
      function Person(name) {
        // console.log("开始创建对象啦");
        this.name = name;
      }

      // 定义行为 引出 原型
      Person.prototype.say = function () {
        console.log('say方法被调用啦 ' + this.name);
      };

      // new 一个对象
      const p1 = new Person('悟空1');
      const p2 = new Person('悟空2');
      // console.log(p1);

      console.log(p1.say === p2.say);
    </script>
​```


ES6面向对象 新的方式 class

<script>
        // es6 面向对象 引出新的语法 类 class
        // constructor 会在 new Person的时候触发
        class Person {
            constructor(name) {
                // console.log("开始创建对象啦");
                this.name = name
            }
            // 直接写行为
            say() {
                console.log('say方法调用' + this.name);
            }
        }
        // 一样new一个对象
        const p1 = new Person('卡卡罗特')
        const p2 = new Person('贝吉塔')
        console.log(p1);
        console.log(p2);

        // 属性
        // 行为
        class SuperMan {
            constructor() {
                // 对象有什么属性都写在 这里
                this.name = '悟天'
                this.color = 'yellow'
            }
            // 行为
            say() {
                console.log('会变身');
            }
            fly() {
                console.log('超赛三');
            }
            sing() {
                console.log('超赛神');
            }
        }
        const w1 = new SuperMan()
        console.log(w1);
    </script>

以前es5-继承

<script>
     function Person(name) {
       this.name=name;
     }
     Person.prototype.say=function(){
       console.log("say方法我调用啦 "+ this.name);
     }
     Person.prototype.fly=function(){
       console.log("父亲 起飞");
     }

     function Student(name,color) {
      Person.call(this,name);// 继承属性
      this.color=color;
     }
     Student.prototype.say=Person.prototype.say;// 继承方法
     Student.prototype.fly=Person.prototype.fly;// 继承方法

     const s1=new Student("学生","red");
     console.log(s1);
     s1.say();
     
    </script>

现在的ES6继承

    <script>
        // ES6
        class Person {
            //   属性
            constructor(name) {
                this.name = name;
            }
            // 行为
            say() {
                console.log('say方法我调用啦 ' + this.name);
            }
            fly() {
                console.log('父亲的起飞');
            }
        }

        // 表示学生要继承父亲
        // extends 直接就实现了继承父亲的方法
        // 写了 extends 还写了 constructor 那必须在 constructor 调用方法 写 super();
        class Student extends Person {
            constructor(name, color) {
                // 写 super(); 代表继承父亲的哪个属性
                super(name); // 父亲的构造函数 =es5   Person.call(this,name);
                this.color = color;
            }
            // fly(){
            //   console.log("儿子 起飞");
            // }
            // fly = null; // 用儿子的新的null 去覆盖父亲的fly没有父亲的fly
        }

        const s1 = new Student('学生', 'red');
        s1.say();
        s1.fly();
      /*
        Must call super constructor in derived class before accessing 'this' or returning from derived constructor
        1 如果你写了 extends 而且还写了 constructor 那你必须要在 constructor 调用了方法 super();
        2 如果你只写了 extends 但是你没有写constructor 不需要管super 
  
        继承要继承父亲的属性和父亲的行为
        1 只实现了继承父亲的行为  还没有实现继承父亲的属性 (super 表示可以继承父亲的属性)
         */
    </script>

案例

使用es6的class 实现以下功能

1 父类 Element

  1 属性 this.dom
  2 方法 append

2 定义两个子类 都要继承父亲的属性和方法

  1 ElementDouble
  2 ElementSingle 

3 然后 通过编写代码 把以下程序运行起来

    <script>
      class Element {
        constructor(tagName) {
          const dom = document.createElement(tagName);
          this.dom = dom;
        }
        append(parentSelector) {
          document.querySelector(parentSelector).appendChild(this.dom);
        }
      }

      class ElementDouble extends Element {
        constructor(tagName, content) {
          super(tagName);
          this.dom.innerText = content;
        }
      }
      class ElementSingle extends Element {
        constructor(tagName, src) {
          super(tagName);
          this.dom.src = src;
        }
      }
      const divModel = new ElementDouble('div', '这个是div');
      divModel.append('body');

      const imgModel = new ElementSingle('img', './images/b_01.jpg');
      imgModel.append('div');
    </script>

以后就很少看到 es5 原型了

但是以后看别人的代码 可能有es5 原型 prototype 也有es6的class

假如让我来选择技术类型 我会优先选择es6 但是别人怎么选的 你没有办法控制 你能做只有一个 都懂!!

es6-class和箭头函数

es6 属性的定义 写法有两种

1 直接在构造函数内 constructor this.name=name

2 可以写在 大括号内

3 方法 三种写法

class Person {
        // color = 'yellow';
        // height = 180;
        // weight = 200;
        constructor(name) {
          this.name = name;
          // this.color = 'yellow';
          // this.height = 180;
          // this.weight = 200;
        }
        // 写法一
        // say() {
        //   console.log('say 方法被调用了 ' + this.name);
        // }
        // 写法二
        // say = function () {
        //   console.log('say 方法被调用了 ' + this.name);
        // };
        // // 写法三
        say =  ()=> {
          // 箭头函数中的this , 绝大部分指向  window
          // 例外 用在 es6的class 充当 方法  this 指向 p1 实例 
          console.log('say 方法被调用了 ' + this.name);
        };
      }
      const p1 = new Person('悟空');
      p1.say();
      // console.log(p1);

三种写法 哪个性能比较好

      class Person {
        // 性能最好 推荐方式!! 
        say1() {
          console.log('say1');
        }
        say2 = function () {
          console.log('s2');
        };
        say3 = () => {
          console.log('s3');
        };
      }
      const p1 = new Person();
      const p2 = new Person();

      console.log(p1.say1 === p2.say1); // true p1 和 p2 say1方法是同一个-节省内存
      console.log(p1.say2 === p2.say2); // false  p1 和 p2 say2方法不是同一个-性能不好
      console.log(p1.say3 === p2.say3); // false  p1 和 p2 say3方法不是同一个-性能不好

es5-原型链

原型链

一个对象 它可以通过 prototype 来 找到被它继承父亲的方法

如果一个对象从底层触发 可以通过 prototype 一层一层往上找到 继承的关系 = 原型链

1650809644012.png

    <script>
      // 1 创建数组的方式 有两种
      // const arr = ['a', 'b', 'c']; // 字面量 常用-直接和简单的写法

      // 2 数组 也是可以被new
      // const arr = new Array('a', 'b', 'c');
      // console.log(arr);

      function Person() {}
      const p1 = new Person();
      // 在 Person的原型上添加一个方法
      Person.prototype.show = function () {
        console.log('自己添加的方法');
      };
      // p1.show();

      // 给js内置的Array数据 原型也添加一个方法试试
      Array.prototype.show = function () {
        console.log('自定义的数组方法');
      };

      const arr = new Array('a', 'b', 'c');
      // const arr = ['a', 'b', 'c'];
      // arr.show();

      // 利用原型对象的方式,在任意的构造函数上添加想要的行为
      // 任意的构造函数 包括 自己定义的构造函数
      // 也包括 js中 -内置就有的构造函数 Array

      // arr.forEach
      // arr.push()
      // arr.map()
      // arr.filter

      // 对象的创建也分两种清空
      // const ojb={};// 字面量 常用 直接 简单
      const obj = new Object(); // 利用构造函数的方式来创建对象
      Object.prototype.show = function () {
        console.log('对象 自己的show方法');
      };
      obj.show();
    </script>

作用

1 如果我需要给 某个数据 (字符串、数组、对象) 统一添加一个方法 ,可以直接在原型上添加

2 初学者 不要乱在原型上定义方法 - 影响巨大

 */
      // const obj = {
      //   username: '悟空',
      //   say() {
      //     console.log('这个是say方法');
      //   },
      // };

      // //  万物皆对象
      // Object.prototype.show = function () {
      //   console.log('这个是原型上的show方法');
      // };

      // // 你看要 dom对象  大哥大
      // console.dir(document.querySelector("div"));

      // const arr = [];
      // console.log(arr);
      // arr.show();

      // console.log();
      // Math.show()

      // const str="123";
      // console.dir(str.show);
      // str.show();

      //  console.log(obj);// 直接看到定义在自己身上的属性和方法 看不见定义在 原型对象上的属性和方法
      //  console.log([]);
      // const arr=[];
      // arr.push
      // console.log(arr);
      // obj.say();
      // obj.show();
      // const arr1=[];
      // const arr2=[];
      // const arr3=[];


      // DNA 存在于你整个家族 不只是父亲和儿子



      Array.prototype.forEach=function(){
        console.log("老子罢工了");
      }
      Array.prototype.map=function(){
        console.log("老子罢工了");
      }
      const arr=[1,2,3];
      arr.forEach(); // forEach 循环 到了你这个项目 这个知识用不了