ES6中定义类.继承以及对象和数组的操作0712

ES6中定义类.继承以及对象的操作0712

1.定义类的不同

回顾一下以前学习的在ES6之前定义一个类(不明显,和普通的函数区别不大)
  •  function Person(myName, myAge) {
        // 实例属性
        // this.name = "lnj";
        // this.age = 34;
        this.name = myName;
        this.age = myAge;
    
        // 实例方法
        this.say = function () {
            console.log(this.name, this.age);
        }
        // 静态属性
        Person.num = 666;
        // 静态方法
        Person.run = function () {
            console.log("run");
        }
    }
    // let p = new Person();
    let p = new Person("zs", 18);
    p.say();
    console.log(Person.num);
    Person.run();
    
从ES6开始系统提供了一个名称叫做class的关键字, 这个关键字就是专门用于定义类的(以后就这样写)
  • 注意里面的注意点哦

  •  class Person{
         // 当我们通过new创建对象的时候, 系统会自动调用constructor
         // constructor我们称之为构造函数
         constructor(myName, myAge){
             this.name = myName;
             this.age = myAge;
         }
         // 注意点:实例属性,不是正式写法,大部分浏览器不支持,所以我们还是写在constructor里好
         // name = "lnj";
         // age = 34;
         // 注意点:实例方法,如果写在constructor外面,系统会将这个方法添加到原型对象上面,想添加在实例对象上还是得写在里面,所以定义在constructor外的方法就相当于以前定义在原型对象上的方法
         say(){
             console.log(this.name, this.age);
         }
         // 注意点:以下定义"静态属性"的方式并不是ES6正式版标准中的写法, 大部分的浏览器不支持
         // 在ES标准中static只支持定义静态方法不支持定义静态变量,所以想要定义静态属性,应定义在类外
         // 静态属性
         static num = 666;
         // 静态方法
         static run() {
             console.log("run");
         }
     }
    //以下自定义一个原型对象在ES6中不可用,如果想将属性和方法保存到原型中, 只能动态给原型对象添加属性和方法
    let obj = {
              constructor: Person,
              type: "人",
              say: function () {
                  console.log(this.name, this.age);
              }
          };
    
     let p = new Person("zs", 18);
     p.say();
     console.log(Person.num);
     Person.run();
    

综上所述,我们来写一个最标准的类的定义

  •  class Person{
         constructor(myName, myAge){
             //方法和属性都写在里面
             this.name = myName;
             this.age = myAge;
             this.say = function(){
              console.log(this.name, this.age);
          }
         }
         //只能写静态方法
         static run() {
             console.log("run");
         }
     }
    //动态给原型对象添加方法和属性
     Person.prototype.type = "人";
     Person.prototype.say = function () {
         console.log(this.name, this.age);
    };
    //静态实行需要类外定义
     Person.num = 666;
    
     let p = new Person("zs", 18);
     p.say();
     console.log(Person.name);
     Person.run();
    

2.继承的不同

  • 在ES6中如何继承:在子类后面添加extends并指定父类的名称,在子类的constructor构造函数中通过super方法借助父类的构造函数

  • class Person{
        constructor(myName, myAge){
            // this = stu;
            this.name = myName; // stu.name = myName;
            this.age = myAge; // stu.age = myAge;
        }
        say(){
            console.log(this.name, this.age);
        }
    }
    // 以下代码的含义: 告诉浏览器将来Student这个类需要继承于Person这个类
    class Student extends Person{
        constructor(myName, myAge, myScore){
            // 1.在子类中通过call/apply方法借助父类的构造函数
            // Person.call(this, myName, myAge);相当于下面那条代码
            super(myName, myAge);
            this.score = myScore;
        }
        study(){
            console.log("day day up");
        }
    }
    let stu = new Student("zs", 18, 98);
    stu.say();
    

3.获取对象类型

现在我们有如下需求,获取各自对应的类型

  • /*
    let obj = new Object();  --> object
    let arr = new Array(); --> Array
    let p = new Person(); --> Person
    */
    console.log(typeof obj);
    console.log(typeof arr);
    console.log(typeof p);
    
  • 但是通过typeof获取的类型都是object(理解一下),那怎么满足我们的需求呢.看以下的

  •  function Person() {
        // let obj = new Object();
        // let this = obj;
        this.name = "lnj";
        this.age = 34;
        this.say = function () {
            console.log(this.name, this.age);
        }
        // return this;
    }
    let p = new Person();
    // console.log(typeof p); // object
    console.log(p.constructor.name); // Person
    
  • 为什么p.constructor.name 能获得是什么类型呢,如下我们调用arr.constructor,就从原型对象找见了,然后指向了构造函数,构造函数里面有一个name属性就能得到是啥类型

  • [图片上传失败...(image-692cc1-1562946030563)]

4. instanceOf关键字

什么是instanceof关键字?

  • instanceof用于判断 "对象" 是否是指定构造函数的 "实例"

  • 注意点: 只要构造函数的原型对象出现在实例对象的原型链中都会返回true

  • 例如下面的例子

  •  function Person(myName) {
         this.name = myName;
     }
     function Student(myName, myScore) {
         Person.call(this, myName);
         this.score = myScore;
     }
     Student.prototype = new Person();
     Student.prototype.constructor = Student;
    
     let stu = new Student();
     console.log(stu instanceof Person); // true  这就说明了上面的观点
     console.log(stu instanceof Student);
    

5.isPrototypeOf属性

  • 什么是isPrototypeOf属性

  • isPrototypeOf用于判断 一个对象是否是另一个对象的原型 (前面的是不是后面的)

  • 注意点: 只要调用者在传入对象的原型链上都会返回true

  • function Person(myName) {
         this.name = myName;
     }
     function Student(myName, myScore) {
         Person.call(this, myName);
         this.score = myScore;
     }
     Student.prototype = new Person();
     Student.prototype.constructor = Student;
    
     let stu = new Student();
     console.log(Person.prototype.isPrototypeOf(stu)); // true
    

6.判断对象是否有某个属性

6.1判断某一个对象是否拥有某一个属性
  • "属性名" in 对象名
  • in的特点: 只要类中或者原型对象中有, 就会返回true
6.2 判断某一个对象自身是否拥有某一个属性
  • 对象名.hasOwnProperty("属性名");
  • 特点: 只会去类中查找有没有, 不会去原型对象中查找

7.对象的增删改查

  •  class Person{}
    let p = new Person();
    
7.1增
  • p.name = "lnj";
  • p["name"] = "zs";
7.2 删
  • delete p.name;
  • delete p["name"];
7.3 改
  • p.name = "lnj"; 覆盖就行

8.对象遍历

在JavaScript中对象和数组一样是可以遍历的

  • 对象的遍历就是依次取出对象中所有的属性和方法

在JS中可以通过高级for循环来遍历对

  • for(let key in obj){}

  • 将指定对象中所有的属性和方法的名称取出来了依次的赋值给key这个变量

  • for(let key in p){
        if(p[key] instanceof Function){
            continue;
        }
        // console.log(key); // name / age / say
        // 注意点: 以下代码的含义取出p对象中名称叫做当前遍历到的名称的属性或者方法的取值
        console.log(p[key]); // p["name"] / p["age"] / p["say"]
        // 注意点: 以下代码的含义取出p对象中名称叫做key的属性的取值
        // console.log(p.key); // undefined
    }
    
js遍历对象.png

10.深拷贝与浅拷贝

10.1深拷贝
  • 修改新变量的值不会影响原有变量的值
  • 默认情况下基本数据类型都是深拷贝
10.2浅拷贝
  • 修改新变量的值会影响原有的变量的值

  • 默认情况下引用类型都是浅拷贝

  • class Person{
         name = "lnj";
         age = 34;
     }
     let p1 = new Person();
     let p2 = p1;
     p2.name = "zs"; // 修改变量的值
     console.log(p1.name); //变为zs
    
  • 原理如下

  • 浅拷贝.png
10.3 对象深拷贝

以下两种只能拷贝基本数据类型

  • 1.可以通过在新建一个对象,然后通过for循环遍历来实现拷贝(low)
  • 2.Object.assign(p2,p1); 将p1中属性和方法拷贝到p2中

在看一下有引用类型的

  • class Person{
        name = "lnj";
        cat = {
            age : 3
        };
        scores = [1, 3, 5];
    }
    let p1 = new Person();
    let p2 = new Object();
    p2.cat = p1.cat;
    
  • 执行完上面代码后会发生什么

  • 深拷贝下.png

这不就出事了吗

  • 所以我们需要自定义一个函数来实现深拷贝,图示如下

  • function depCopy(target, source) {
        // 1.通过遍历拿到source中所有的属性
        for(let key in source){
            // console.log(key);
            // 2.取出当前遍历到的属性对应的取值
            let sourceValue = source[key];
            // console.log(sourceValue);
            // 3.判断当前的取值是否是引用数据类型
            if(sourceValue instanceof Object){
                // console.log(sourceValue.constructor);
                // console.log(new sourceValue.constructor);
                //这样如果是object就会创建一个object类型,如果是array类型就会创建一个array类型
                let subTarget = new sourceValue.constructor;
                target[key] = subTarget;
                //递归调用实现拷贝,
                depCopy(subTarget, sourceValue);
            }else{
                target[key] = sourceValue;
            }
        }
    }
    
  • 深拷贝自定义.png

11.数组高级API

11.1 遍历对象 forin
  • forin用来遍历对象,但是对象的属性是无序的, 所以forin循环就是专门用于遍历无序的东西的, 所以不推荐使用forin循环来遍历数组

  • for(let key in obj){    
        console.log(obj[key]);
    }
    
11.2 遍历数组
  • 利用Array对象的forEach方法来遍历数组

    • forEach方法会自动调用传入的函数

    • 每次调用都会将当前遍历到的元素和当前遍历到的索引和当前被遍历的数组传递给这个函数

    • arr.forEach(function (currentValue, currentIndex, currentArray) {
           // console.log(currentValue, currentIndex, currentArray);
            console.log(currentValue);
      });
      //自己来实现一个
       Array.prototype.myForEach = function (fn) {
          // this === [1, 3, 5, 7, 9]
          for(let i = 0; i < this.length; i++){
              fn(this[i], i, this);
          }
      };
      arr.myForEach(function (currentValue, currentIndex, currentArray) {
          console.log(currentValue, currentIndex, currentArray);
      });
      
  • 利用ES6中推出的for of循环来遍历数组

    • for(let value of arr)
11.3数组的findIndex方法
  • findIndex方法: 定制版的indexOf, 找到返回索引, 找不到返回-1

  • let arr = [3, 2, 6, 7, 6];
    let index = arr.findIndex(function (currentValue, currentIndex, currentArray) {
        // console.log(currentValue, currentIndex, currentArray);
        // if(currentValue === 6){
        if(currentValue === 10){
            return true;
        }
    });
    //自己实现了一个
    rray.prototype.MyfindIndex = function (fn) {
        // this === [1, 3, 5, 7, 9]
        for(let i = 0; i < this.length; i++){
            let re = fn(this[i], i, this);
            if (re === true){
                return i;
            }
            if(i == this.length-1) return  -1;
        }
    };
    
11.4 数组的find方法
  • find方法返回索引, find方法返回找到的元素,find方法如果找到了就返回找到的元素, 如果找不到就返回undefined

  •  let value = arr.find(function (currentValue, currentIndex, currentArray) {
        // console.log(currentValue, currentIndex, currentArray);
        // if(currentValue === 6){
        if(currentValue === 10){
            return true;
        }
    });
    
11.5 数组的filter方法
  • 将满足条件的元素添加到一个新的数组中

  • let newArray = arr.filter(function (currentValue, currentIndex, currentArray) {
        // console.log(currentValue, currentIndex, currentArray);
        if(currentValue % 2 === 0){ //要满足的条件
            return true;
        }
    });
    console.log(newArray); // [2, 4]
    //自己实现一下
    Array.prototype.myFilter = function (fn) {
        let newArray = [];
        for(let i = 0; i < this.length; i++){
            let result = fn(this[i], i, this);
            if(result){
                newArray.push(this[i]);
            }
        }
        return newArray;
    }
    
11.6 数组的map方法(和filter的区别看一下)
  • 将满足条件的元素映射到一个新的数组中(新数组的长度与原数组一样,没有就返回undefined)

  • let newArray = arr.map(function (currentValue, currentIndex, currentArray) {
        // console.log(currentValue, currentIndex, currentArray);
        if(currentValue % 2 === 0){
            return currentValue;
        }
    });
    console.log(newArray); // [undefined, 2, undefined, 4, undefined]
    //自己实现
     Array.prototype.myMap = function (fn) {
        let newArray = new Array(this.length);
        newArray.fill(undefined);
        for(let i = 0; i < this.length; i++){
            let result = fn(this[i], i, this);
            if(result !== undefined){
                newArray[i] = result;
            }
        }
        return newArray;
    }
    
11.7 删除数组元素注意点
  • let len = arr.length;
    for(let i = 0; i < arr.length; i++){
        arr.splice(i,1);
    }
    //删不干净,因为每删一次,数组中的元素会往前移,导致最后没法删了
    //解决办法,从后往前删
    for(let i = len - 1; i >= 0; i--){
        // console.log(arr.length); // 5, 4, 3
        // console.log(len);
        arr.splice(i, 1);
    }
    //解决办法二,采用delete
     for(let i = 0; i < arr.length; i++){
        console.log(arr.length);
        // 注意点: 通过delete来删除数组中的元素, 数组的length属性不会发生变化
        delete arr[i];
    }
    
11.8 数组排序
  • // 如果元素是字符串类型, 那么比较的是字符串的Unicode编码
    let arr = ["c", "a", "b"];
     arr.sort(function (a, b) {
        if(a > b){
            return -1;
        }else if(a < b){
            return 1;
        }else{
            return 0;
        }
    });
    //如果数组中的元素是数值类型
    //如果需要升序排序, 那么就返回a - b;
    //如果需要降序排序, 那么就返回b - a;
    arr.sort(function (a, b) {
        return b - a;
    });
    //按长度排序
     let arr = ["1234", "21", "54321", "123", "6"];
     arr.sort(function (str1, str2) {
         // return str1.length - str2.length; 短的排前面
         return str2.length - str1.length;
     });
    //对象数组的排序
     let students = [
         {name: "zs", age: 34},
         {name: "ls", age: 18},
         {name: "ww", age: 22},
         {name: "mm", age: 28},
     ];
    students.sort(function (o1, o2) {
        // return o1.age - o2.age;
        return o2.age - o1.age;
    });
    
    

12.字符串操作

在js中字符串可以看做一个特殊的数组, 所以大部分数组的属性/方法字符串都可以使用

  • // 1.获取字符串长度  .length
     let str = "abcd";
     console.log(str.length);
    
    // 2.获取某个字符 [索引] / charAt
     let str = "abcd";
     let ch = str[1];//高级浏览器才支持 
     let ch = str.charAt(1);
     console.log(ch);
    
    // 3.字符串查找 indexOf / lastIndexOf / includes
     let str = "vavcd";
     let index = str.indexOf("v");
     let index = str.lastIndexOf("v");
     console.log(index);
     let result = str.includes("p");
     console.log(result);  //返回true和false
    
    // 4.拼接字符串 concat / +
     let str1 = "www";
     let str2 = "it666";
     let str = str1 + str2; // 推荐
     let str = str1.concat(str2);
     console.log(str);
    
    // 5.截取子串 slice / substring / substr
    let str = "abcdef";
    let subStr = str.slice(1, 3);
    let subStr = str.substring(1, 3);
    let subStr = str.substr(1, 3);
    console.log(subStr);
    // 6.字符串切割
    let arr = [1, 3, 5];
    let str = arr.join("-");//将数组换成一个字符串,用-链接
     console.log(str);
     let str = "1-3-5";
     let arr = str.split("-");//切割
     console.log(arr);
    
    // 7.判断是否以指定字符串开头 ES6
     let str = "http://www.it666.com";
     let result = str.startsWith("www");
     console.log(result);
    // 8.判断是否以指定字符串结尾 ES6
    let str = "lnj.jpg";
    let result = str.endsWith("png");
    console.log(result);
    // 4.字符串模板 ES6
    let str = ""; 以前定义字符串
    let str = '';
    let str = `www.it666.com`;//新增定义字符串
    console.log(str);
    console.log(typeof str);
    //以前得通过+拼接
    let str =   "<ul>\n" +
                "    <li>我是第1个li</li>\n" +
                "    <li>我是第2个li</li>\n" +
                "    <li>我是第3个li</li>\n" +
                "</ul>";
    //现在直接写在``中就行
    let str = `<ul>
                    <li>我是第1个li</li>
                    <li>我是第2个li</li>
                    <li>我是第3个li</li>
                </ul>`;
    
    let name = "lnj";
    let age = 34;
    //以前的拼接方法
    let str = "我的名字是" + name + ",我的年龄是" + age;
    //通过``拼接
    let str = `我的名字是${name},我的年龄是${age}`;
    console.log(str);
    
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容