美文网首页
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-面向对象的三大特性

    封装 自定义构造函数原型对象 由于原型对象也是一个对象, 所以我们可以自定义构造函数的原型对象 注意点:自定义原型...

  • 面向对象编程(二)

    面向对象编程(二) -------面向对象的基本特性 1、面向对象的基本特性 面向对象的编程是把现实客观存在的...

  • 面向对象

    面向对象:OOP 面向对象三大特性

  • 面向对象语言基础

    面向对象语言的特性 面向对象的语言的特性:封装、继承、多态。 面向对象语言的设计原则 面向对象的语言在进行程序设计...

  • 面向对象三大特性(一):封装

    面向对象有三大特性:封装、继承和多态。注意,是面向对象的三大特性而不是Java的三大特性,Java只是面向对象语言...

  • Class 的封装及调用-Python教学【StudyQuant

    前言:面向对象的三大特性是指:封装、继承和多态。论Class 的封装及调用 面向对象三大特性 面向对象的三大特性是...

  • 理解面向对象

    理解面向对象 阅读知乎大牛对面向对象的讨论后,写下自己的总结和理解。知乎 面向对象的原本特性 面向对象原本的特性(...

  • 面向对象:创建对象&继承

    博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...

  • 面向对象三大基本特性,五大基本原则

    面向对象三大基本特性,五大基本原则 透切理解面向对象三大基本特性是理解面向对象五大基本原则的基础. 三大特性是:封...

  • 面向对象特性

    面向对象主要由三大特性: 封装继承多态 1.封装:封装的思想保证了类内部数据结构的完整性,使用户无法轻易直接操作类...

网友评论

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

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