美文网首页
09-面向对象的三大特性

09-面向对象的三大特性

作者: 喝酸奶要舔盖__ | 来源:发表于2018-11-09 17:03 被阅读0次

    封装

    自定义构造函数原型对象

    • 由于原型对象也是一个对象, 所以我们可以自定义构造函数的原型对象

    注意点:
    自定义原型对象一定要保持三角恋的关系, 一定要设置constructor: 所属的构造函数

    // 自定义一个构造函数
        function Person(name,age) {
            this.name = name;
            this.age = age;
        }
    
        // 由于原型对象也是一个对象, 所以我们可以自定义构造函数的原型对象
        // 注意点: 自定义原型对象一定要保持三角恋的关系, 一定要设置constructor: 所属的构造函数
        Person.prototype = {
            constructor: Person,
            say: function () {
                console.log("我是方法");
            }
        };
    
        var per = new Person("wjh",19);
        per.say();
    
        console.log(per.__proto__);
    

    对象的公有属性(方法)和私有属性(方法)

    • 什么是全局变量和函数
      只要写在一对script标签中或者写在一个单独的JS文件中的变量和函数就是全局的变量和函数
    • 什么是局部的变量和函数
      只要在其它函数中定义的变量或者函数都是局部变量和局部函数
    var num = 666; // 全局变量
        function test() { // 全局函数
            console.log("test");
            console.log(num); // 在其它作用域中访问全局变量
        }
    
        console.log(num); // 在全局作用域中访问全局变量
        test(); // 在全局作用域中访问全局函数
    
        function demo() {
            test(); // 在其它作用域中访问全局函数
        }
        demo();
    
        function test() {
            var num = 123; // 局部的变量
            console.log(num); // 可以在当前作用域中访问当前作用域的局部变量
    
            function demo() {
                console.log("demo");
            }
            demo(); // 可以在当前作用域中访问当前作用域的局部函数
        }
    
        // console.log(num); // 不能在其它作用域中访问局部变量
        demo(); // 不能在其它作用域中访问局部函数
    
    • 默认情况下对象中的属性和方法都是公有的

    注意点:
    其实构造函数也是一个函数, 所以在构造函数中直接定义的变量, 就是局部变量, 外界就不能访问

    function Person(name,age) {
            this.name = name;
            this.age = age;
            //其实构造函数也是一个函数, 所以在构造函数中直接定义的变量, 就是局部变量, 外界就不能访问
            var num = 666;//私有属性
            function test() {//私有函数
                console.log(test);
            }
    
        }
    
        // console.log(num); 会报错
        // test();  会报错
        var p = new Person();
        // console.log(p.num); undefine
        // p.test(); 会报错
    

    对象的实例属性和方法

    • 什么是实例?
      通过构造函数创建出来的对象, 我们就称之为实例
      也就是实例就是对象的另一个名称而已
    • 什么是实例属性和实例方法?
      实例的属性就是通过对象才能访问的属性
      实例的方法就是通过对象才能访问的方法
    // 自定义一个构造函数
        function Person(name,age) {
            this.name = name;
            this.age = age;
            this.say = function () {
                console.log("say");
            }
        }
    
        var p  = new Person("wjh",19);
        console.log(p.name);//实例属性
        console.log(p.age);
        p.say();//实例方法
    
       /*
        // 这里通过new Person()创建出来的p对象我们就称之为实例
        var p = new Person("lnj", 13);
        // 这里通过p.xxx访问的属性, 我们就称之为实例属性
        console.log(p.name);
        console.log(p.age);
        // 这里通过p.xxx()访问的方法, 我们就称之为实例方法
        p.say();
        */
    

    对象的静态属性和方法

    • 什么是静态属性和静态的方法?
      通过构造函数就能够直接访问的属性和访问, 我们就称之为静态属性和方法
    // 自定义一个构造函数
        function Person(name,age) {
            this.name = name;
            this.age = age;
            this.say = function () {
                console.log("say");
            }
        }
    // 将属性和方法添加给了构造函数, 这里添加的属性和方法将来就只能通过构造函数来访问
        // 这里添加的属性和方法就是静态的属性和方法
        Person.type = "人";
        Person.eat = function () {
            console.log("eat");
        }
    
        //访问静态属性和方法
        console.log(Person.type);
        Person.eat();
    

    继承

    修改this指向的方法

    • bind方法的作用
      修改函数内部的this的, 但是不会调用这个函数, 会返回一个新的函数给我们
    //定义一个函数
        function test(a,b) {
            console.log(this);
            console.log(a, b);
        }
    //定义一个对象
        var obj = {
          name : "wjh"
        };
    
        test();
        //使用bind方法
        var fn = test.bind(obj);
        console.log(fn);
        fn();
    
    • call方法的作用
      修改函数内部的this的, 但是自动会调用这个函数
    //定义一个函数
        function test(a,b) {
            console.log(this);
            console.log(a, b);
        }
    
        //定义一个对象
        var obj = {
          name : "wjh"
        };
    
        test();
        //使用call方法
        test.call(obj,10,20);
    
    • apply方法的作用
      修改函数内部的this的, 但是会自动调用这个函数
     //定义一个函数
        function test(a,b) {
            console.log(this);
            console.log(a, b);
        }
    
        //定义一个对象
        var obj = {
          name : "wjh"
        };
    
        test();
        //使用apply方法
        test.apply(obj,[20,30]);
    

    注意点:
    call和apply的区别:
    传递参数的形式不同, 如果是call那么参数依次用逗号隔开即可, 如果是apply那么参数都要放到一个数组中

    子类继承父类的写法

      1. 借用父类构造函数, 动态给当前子类对象添加属性和方法
        也就是利用call函数,将父类构造函数中的this修改为子类构造函数
    • 2.将子类原型对象修改为父类的对象
    • 3.将子类原型对象的constructor属性指向对应的构造函数
       // 父类
        function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.say = function () {
            console.log("say");
        };
    
        //子类
        function Student(score, name, age) {
            //1. 借用构造函数, 动态给当前对象添加属性和方法
            Person.call(this,name,age);
            this.score = score;
        }
    
        Student.prototype.eat = function () {
            console.log("eat");
        };
    
        //2.将子类原型对象修改为父类的对象
        Student.prototype = new Person();
        //3.将子类原型对象的constructor属性指向对应的构造函数
        Student.prototype.constructor = Student;
    
        var stu = new Student(66,"wjh",20);
        console.log(stu.name);
        console.log(stu.score);
    
        //子类可以访问父类的原型方法
        stu.say();
        var per = new Person("lnj",30);
        //父类的原型对象没有改变
        console.log(per.__proto__);
        //父类不能访问子类原型对象的方法
        per.eat();
    

    多态

    • js是弱类型语言,没有明确的多态,传入任何类型都可以

    对象的增删改查

    • 如何访问对象的属性(查询)
      对象.属性名称方式, 操作属性
      对象["属性名称"]方式, 操作属性
    • 删除对象属性
      使用delete 关键字删除对应的属性
    • 增加属性
      对象中如何没有就会新增属性
      对象.属性名称方式
    function Person(name, age) {
            this.name = name;
            this.age = age;
            this.say = function () {
                console.log(this.name, this.age);
            }
        }
    
        // 给Person的原型对象添加了一个type属性
        Person.prototype.type = "人";
        //创建一个对象
        var per = new Person("HH",20);
        // 2.如何访问对象的属性(查询)
        // 2.1对象.属性名称方式, 操作属性
        // 2.2对象["属性名称"]方式, 操作属性
        console.log(per.name);
        console.log(per.age);
        console.log(per["name"]);
        console.log(per["age"]);
    
        // 3.如何新增属性
        // 对象中如何没有就会新增(新增)
        per.score = 50;
        console.log(per);
    
        // 4.如何删除对象中的属性
        console.log(per);
        delete per.age;
        console.log(per);
    
    
    • 如何判断对象中有没有某个属性
      通过 "属性名称" in 对象方式来判断, 如果有就返回true, 如果没有就返回false
      // 5.如何判断对象中有没有某个属性
    
        // 5.1通过 "属性名称" in 对象方式来判断, 如果有就返回true, 如果没有就返回false
        // 注意点:属性名称一定是字符串类型
        //    特点: 会先在当前对象中找有没有, 如果没有会去当前对象的原型对象上找有没有, 一直找到null都没有就会返回false
        console.log("name" in per);
        console.log("age" in per);
        console.log("type" in per);
        // 5.2通过对象.hasOwnProperty("属性名称")方式来判断, 只会在当前对象上查找, 如果当前对象上有就返回true, 如果当前对象上没有就返回false, 不会去 当前对象的原型对象上查找
        console.log(per.hasOwnProperty("name"));
        console.log(per.hasOwnProperty("age"));
        console.log(per.hasOwnProperty("type"));//false
    
        // 问题: 我们可以判断某个属性是否是当前对象的属性
        //       我们也可以判断某个属性是否是当前对象或者原型上的属性
        //       那么我们能不能判断某个属性时候是原型上的属性呢?
    
        if (!per.hasOwnProperty("type")){
            if ("type" in per){
                console.log("原型对象上的属性type");
            }
        }
    
        //将判断是否是原型上的属性封装成方法
        function prototyProperty(obj,name) {
            if (!obj.hasOwnProperty(name)){
                if (name in obj){
                    return true
                }
            }
            return false
        }
    
        var flag = prototyProperty(per,"name");
        console.log(flag);
    

    对象的遍历

    • 在JavaScript中对象是可以直接遍历的利用高级for循环就可以直接遍历对象
      for(var key in obj){ }
      会将对象中的每一个属性依次取出来赋值给key对象中有多少个属性,循环就会执行多少次
     function Person(name, age) {
            this.name = name;
            this.age = age;
            this.say = function () {
                console.log(this.name, this.age);
            }
        }
        var p = new Person("lnj", 33);
    
        for (var key in p){
            //打印属性和方法名称
            // console.log(key);
            //打印属性和方法对应的值
            // console.log(p[key]);
    
            if (p[key] instanceof Function){
                continue;
            } else {
                console.log(p[key]);
            }
        }
    

    对象的深拷贝和浅拷贝

    • 什么是对象的拷贝?
      将一个对象赋值给另外一个对象, 我们称之为对象的拷贝
    • 什么是深拷贝, 什么是浅拷贝?
      例如将A对象赋值给B对象
      深拷贝是指, 修改B对象的属性和方法不会影响到A对象的属性和方法, 我们称之为深拷贝
      浅拷贝是指, 修改B对象的属性和方法会影响到A对象的属性和方法, 我们称之为浅拷贝

    注意点:
    3.1 默认情况下对象之间的直接赋值都是浅拷贝
    3.2 默认情况下一个对象的属性如果是基本数据类型, 那么都是深拷贝
    3.3 如果对象的属性包含了引用数据类型, 才真正的区分深拷贝和浅拷贝

    浅拷贝

     function Person(name, age, dog) {
            this.name = name;
            this.age = age;
            this.say = function () {
                console.log(this.name, this.age);
            };
            this.dog = dog;
        }
        var p1 = new Person("lnj", 13, {
            name: "wc",
            age: "3"
        });
    
        // 1.对象之间的直接赋值
    
        // 将p1对象赋值给p2对象
        // 本质上是p1和p2都指向了同一块存储空间
        // 所以无论是修改p1还是p2都会影响到另外一个
        // 所以下列代码是浅拷贝
        var p2 = p1;
        console.log(p1.name);//lnj
        p2.name = "haha";
        console.log(p1.name);//haha p1对象的属性被修改
    

    深拷贝

    • 深拷贝思想:如果是基本数据类型直接赋值,如果是引用类型就新创建一个对象,然后把对象的值给到新创建的对象
        // 2.对象属性的逐一赋值
        var p2 = new Person();
        p2.name = p1.name;
        p2.age = p1.age;
        p2.dog = p1.dog;
    
        //可以使用遍历对象逐一拷贝
        for (var key in p1){
            p2[key] = p1[key];
        }
    
    • 深拷贝封装方法
    function Person(name, age, dog) {
            this.name = name;
            this.age = age;
            this.say = function () {
                console.log(this.name, this.age);
            };
            this.dog = dog;
        }
    
        var p1 = new Person("lnj", 13, {
            name: "wc",
            age: "3"
        });
    
        var p2 = new Person();
    
        //深拷贝思想:如果是基本数据类型直接赋值,如果是引用类型就新创建一个对象,然后把对象的值给到新创建的对象
        function deepCopy(obj1, obj2) {
            // 取出第一个对象的每一个属性
            for (var key in obj1) {
                // 取出第一个对象当前属性对应的值
                var item = obj1[key];
                // 判断当前的值是否是引用类型
                // 如果是引用类型, 我们就重新开辟一块存储空间
                if (item instanceof Object) {
                    var temp = new Object();
                    deepCopy(item, temp);
                    //把新创建的对象赋值给obj2
                    obj2[key] = temp;
                } else {
                    // 基本数据类型
                    obj2[key] = item;
                }
    
            }
        }
    
        deepCopy(p1,p2);
        console.log(p1.dog.name);
        p2.dog.name = "miaomiao";
        console.log(p1.dog.name);
    

    相关文章

      网友评论

          本文标题:09-面向对象的三大特性

          本文链接:https://www.haomeiwen.com/subject/hjnbxqtx.html