zoukankan      html  css  js  c++  java
  • 浅谈javascript的面向对象思想

    面向对象的三大基本特性

    封装(把相关的信息(无论数据或方法)存储在对象中的能力)

    继承(由另一个类(或多个类)得来类的属性和方法的能力)

    多态(一个对象在不同情况下的多种形态)

    定义类或对象

    第一种:基于Object对象

    var person = new Object();
    person.name = "Rose";
    person.age = 18;
    person.getName = function () {
        return this.name;
    };
    console.log(person.name);//Rose
    console.log(person.getName);//function () {return this.name;}
    console.log(person.getName());//Rose

    缺点:不能创建多个对象。

    第二种:基于字面量方式

    var person = {
        name : "Rose",
        age : 18 ,
        getName : function () {
            return this.name;
        }
    };
    console.log(person.name);//Rose
    console.log(person.getName);//function () {return this.name;}
    console.log(person.getName());//Rose

    优点:比较清楚的查找对象包含的属性和方法;

    缺点:不能创建多个对象。

    第三种:工厂模式

    方式一:

    function createPerson(name,age) {
        var object = new Object();
        object.name = name;
        object.age = age;
        object.getName = function () {
            return this.name;
        };
        return object;
    }
    var person1 = createPerson("Rose",18);
    var person2 = createPerson("Jack",20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName);//false//重复生成函数,为每个对象都创建独立的函数版本

    优点:可以创建多个对象;

    缺点:重复生成函数getName(),为每个对象都创建独立的函数版本。

    方式二:

    function createPerson(name,age) {
        var object = new Object();
        object.name = name;
        object.age = age;
        object.getName = getName;
        return object;
    }
    function getName() {
        return this.name;
    }
    var person1 = createPerson("Rose",18);
    var person2 = createPerson("Jack",20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName);//true//共享同一个函数

    优点:可以创建多个对象;

    缺点:从语义上讲,函数getName()不太像是Person对象的方法,辨识度不高。

    第四种:构造函数方式

    方式一:

    function Person(name,age) {
        this.name = name;
        this.age = age;
        this.getName = function () {
            return this.name;
        }
    }
    var person1 = new Person("Rose",18);
    var person2 = new Person("Jack",20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName); //false//重复生成函数,为每个对象都创建独立的函数版本

    优点:可以创建多个对象;

    缺点:重复生成函数getName(),为每个对象都创建独立的函数版本。

    方式二:

    function Person(name,age) {
        this.name = name;
        this.age = age;
        this.getName = getName ;
    }
    function getName() {
        return this.name;
    }
    var person1 = new Person("Rose",18);
    var person2 = new Person("Jack",20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName); //true//共享同一个函数

    优点:可以创建多个对象;

    缺点:从语义上讲,函数getName()不太像是Person对象的方法,辨识度不高。

    第五种:原型方式

    function Person() {
    }
    Person.prototype.name = 'Rose';
    Person.prototype.age = 18;
    Person.prototype.getName = function () {
        return this.name;
    };
    var person1 = new Person();
    var person2 = new Person();
    console.log(person1.name);//Rose
    console.log(person2.name);//Rose//共享同一个属性
    console.log(person1.getName === person2.getName);//true//共享同一个函数

    缺点:它省略了为构造函数传递初始化参数,这在一定程序带来不便;另外,最主要是当对象的属性是引用类型时,它的值是不变的,总是引用同一个外部对象,所有实例对该对象的操作都会影响其它实例:

    function Person() {
    }
    Person.prototype.name = 'Rose';
    Person.prototype.age = 18;
    Person.prototype.lessons = ["语文","数学"];
    Person.prototype.getName = function () {
        return this.name;
    };
    var person1 = new Person();
    person1.lessons.push("英语");
    var person2 = new Person();
    console.log(person1.lessons);//["语文", "数学", "英语"]
    console.log(person2.lessons);//["语文", "数学", "英语"]//person1修改影响了person2

    第六种:构造函数+原型方式(推荐)

    function Person(name,age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype.getName = function () {
        return this.name;
    };
    var person1 = new Person('Rose', 18);
    var person2 = new Person('Jack', 20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName);//true//共享原型中定义的方法

    缺点:属性定义在构造函数内,方法定义在构造函数外,与面向对象的封装思想不符。

    第七种:构造函数+动态原型方式(推荐)

    方式一:

    function Person(name,age) {
        this.name = name;
        this.age = age;
        if (typeof Person._getName === "undefined"){
            Person.prototype.getName = function () {
                return this.name;
            };
            Person._getName = true;
        }
    }
    var person1 = new Person('Rose', 18);
    var person2 = new Person('Jack', 20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName);//true//共享原型中定义的方法

    方式二:

    function Person(name,age) {
        this.name = name;
        this.age = age;
        if (typeof this.getName !== "function"){
            Person.prototype.getName = function () {
                return this.name;
            };
        }
    }
    var person1 = new Person('Rose', 18);
    var person2 = new Person('Jack', 20);
    console.log(person1.name);//Rose
    console.log(person2.name);//Jack
    console.log(person1.getName === person2.getName);//true//共享原型中定义的方法

    对象属性的扩展及删除

    Javascript的对象可以使用 ’.’ 操作符动态的扩展其属性,可以使用 ’delete’ 关键字或将属性的值设置为 ’undefined’ 来删除属性。

    function Person(name,age) {
        this.name = name;
        this.age = age;
        if (typeof Person._getName === "undefined"){
            Person.prototype.getName = function () {
                return this.name;
            };
            Person._getName = true;
        }
    }
    var person = new Person("Rose",18);
    person.job = 'Engineer';//添加属性
    console.log(person.job);//Engineer
    delete person.job;//删除属性
    console.log(person.job);//undefined//删除属性后值为undefined
    person
    .age = undefined;//删除属性
    console.log(person.age);//undefined//删除属性后值为undefined

    对象属性类型

    数据属性

    特性:

    [configurable]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;

    [enumberable]:表示是否可通过for-in循环返回属性。默认true;

    [writable]:表示是否可修改属性的值。默认true;

    [value]:包含该属性的数据值。读取/写入都是该值。默认为undefined;如上面实例对象person中定义了name属性,其值为’My name’,对该值的修改都反正在这个位置

    function Person(name,age) {
        this.name = name;
        this.age = age;
        if (typeof Person._getName === "undefined"){
            Person.prototype.getName = function () {
                return this.name;
            };
            Person._getName = true;
        }
    }
    var person = new Person("Rose",18);
    Object.defineProperty(person,"name",{configurable:false,writable:false});
    person.name = "Jack";
    console.log(person.name);//Rose//重新赋值无效
    delete person.name;
    console.log(person.name);//Rose//删除无效

    注意:

    一旦将configurable设置为false,则无法再使用defineProperty将其修改为true(执行会报错:cannot redefine property : propertyName)

    function Person(name,age) {
        this.name = name;
        this.age = age;
        if (typeof Person._getName === "undefined"){
            Person.prototype.getName = function () {
                return this.name;
            };
            Person._getName = true;
        }
    }
    var person = new Person("Rose",18);
    Object.defineProperty(person,"name",{configurable:false,writable:false});
    person.name = "Jack";
    console.log(person.name);//Rose//重新赋值无效
    delete person.name;
    console.log(person.name);//Rose//删除无效
    Object.defineProperty(person,"name",{configurable:true,writable:true});//Cannot redefine property: name

    访问器属性

    特性:

    [configurable]:是否可通过delete操作符删除重新定义属性;

    [numberable]:是否可通过for-in循环查找该属性;

    [get]:读取属性时调用,默认:undefined;

    [set]:写入属性时调用,默认:undefined;

    访问器属性不能直接定义,必须使用defineProperty()或defineProperties来定义:如下

    function Person(name,age) {
        this.name = name;
        this._age = age;
        if (typeof Person._getName === "undefined"){
            Person.prototype.getName = function () {
                return this.name;
            };
            Person._getName = true;
        }
    }
    var person = new Person("Rose",18);
    Object.defineProperty(person,"age",{
        get:function () {
            return this._age;
        },
        set:function (age) {
            this._age = age;
        }});
    person.age = 20;
    console.log(person.age);//20//person.age=20是使用set方法将20赋值给_age,person.age是使用get方法将_age的读取出来
    console.log(person._age);//20

    获取所有的属性和属性的特性

    使用Object.getOwnPropertyNames(object)方法可以获取所有的属性;

    使用Object.getOwnPropertyDescriptor(object,property)方法可以取得给定属性的特性;

    function Person(name,age) {
        this.name = name;
        this._age = age;
        if (typeof Person._getName === "undefined"){
            Person.prototype.getName = function () {
                return this.name;
            };
            Person._getName = true;
        }
    }
    var person = new Person("Rose",18);
    Object.defineProperty(person,"age",{
        get:function () {
            return this._age;
        },
        set:function (age) {
            this._age = age;
        }});
    console.log(Object.getOwnPropertyNames(person));//["name", "_age", "age"]
    console.log(Object.getOwnPropertyDescriptor(person,"age"));//{enumerable: false, configurable: false, get: function, set: function}

    对于数据属性,可以取得:configurable,enumberable,writable和value;

    对于访问器属性,可以取得:configurable,enumberable,get和set;

    继承机制实现

    对象冒充

    function Father(name) {
        this.name = name ;
        this.getName = function () {
            return this.name;
        }
    }
    function Son(name,age) {
        this._newMethod = Father;
        this._newMethod(name);
        delete  this._newMethod;

        this.age = age;
        this.getAge = function () {
            return this.age;
        }
    }
    var father = new Father("Tom");
    var son = new Son("Jack",18);
    console.log(father.getName());//Tom
    console.log(son.getName());//Jack//继承父类getName()方法
    console.log(son.getAge());//18

    多继承(利用对象冒充可以实现多继承)

    function FatherA(name) {
        this.name = name ;
        this.getName = function () {
            return this.name;
        }
    }
    function FatherB(job) {
        this.job = job;
        this.getJob = function () {
            return this.job;
        }
    }
    function Son(name,job,age) {
        this._newMethod = FatherA;
        this._newMethod(name);
        delete  this._newMethod;
        this._newMethod = FatherB;
        this._newMethod(job);
        delete  this._newMethod;

        this.age = age;
        this.getAge = function () {
            return this.age;
        }
    }
    var fatherA = new FatherA("Tom");
    var fatherB = new FatherB("Engineer");
    var son = new Son("Jack","Programmer",18);
    console.log(fatherA.getName());//Tom
    console.log(fatherB.getJob());//Engineer
    console.log(son.getName());//Jack//继承父类FatherA的getName()方法
    console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法
    console.log(son.getAge());//18

    call()方法

    function Father(name) {
        this.name = name ;
        this.getName = function () {
            return this.name;
        }
    }
    function Son(name,job,age) {
        Father.call(this,name);

        this.age = age;
        this.getAge = function () {
            return this.age;
        }
    }
    var father = new Father("Tom");
    var son = new Son("Jack","Programmer",18);
    console.log(father.getName());//Tom
    console.log(son.getName());//Jack//继承父类getName()方法
    console.log(son.getAge());//18

    多继承(利用call()方法实现多继承)

    function FatherA(name) {
        this.name = name ;
        this.getName = function () {
            return this.name;
        }
    }
    function FatherB(job) {
        this.job = job;
        this.getJob = function () {
            return this.job;
        }
    }
    function Son(name,job,age) {
        FatherA.call(this,name);
        FatherB.call(this,job);

        this.age = age;
        this.getAge = function () {
            return this.age;
        }
    }
    var fatherA = new FatherA("Tom");
    var fatherB = new FatherB("Engineer");
    var son = new Son("Jack","Programmer",18);
    console.log(fatherA.getName());//Tom
    console.log(fatherB.getJob());//Engineer
    console.log(son.getName());//Jack//继承父类FatherA的getName()方法
    console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法
    console.log(son.getAge());//18

    apply()方法

    function Father(name) {
        this.name = name ;
        this.getName = function () {
            return this.name;
        }
    }
    function Son(name,job,age) {
        Father.apply(this,new Array(name));

        this.age = age;
        this.getAge = function () {
            return this.age;
        }
    }
    var father = new Father("Tom");
    var son = new Son("Jack","Programmer",18);
    console.log(father.getName());//Tom
    console.log(son.getName());//Jack//继承父类getName()方法
    console.log(son.getAge());//18

    多继承(利用apply()方法实现多继承)

    function FatherA(name) {
        this.name = name ;
        this.getName = function () {
            return this.name;
        }
    }
    function FatherB(job) {
        this.job = job;
        this.getJob = function () {
            return this.job;
        }
    }
    function Son(name,job,age) {
        FatherA.apply(this,new Array(name));
        FatherB.apply(this,new Array(job));

        this.age = age;
        this.getAge = function () {
            return this.age;
        }
    }
    var fatherA = new FatherA("Tom");
    var fatherB = new FatherB("Engineer");
    var son = new Son("Jack","Programmer",18);
    console.log(fatherA.getName());//Tom
    console.log(fatherB.getJob());//Engineer
    console.log(son.getName());//Jack//继承父类FatherA的getName()方法
    console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法
    console.log(son.getAge());//18

    原型链方法

    function Father() {
    }
    Father.prototype.name = "Tom";
    Father.prototype.getName = function () {
      return this.name;
    };
    function Son() {
    }
    Son.prototype = new Father();
    Son.prototype.age = 18;
    Son.prototype.getAge = function () {
        return this.age;
    };
    var father = new Father();
    var son = new Son();
    console.log(father.getName());//Tom
    console.log(son.getName());//Tom//继承父类FatherA的getName()方法
    console.log(son.getAge());//18

    混合方式(call()+原型链)

    function Father(name) {
        this.name = name;
    }
    Father.prototype.getName = function () {
      return this.name;
    };
    function Son(name,age) {
        Father.call(this,name);
        this.age = age;
    }
    Son.prototype = new Father();
    Son.prototype.getAge = function () {
        return this.age;
    };
    var father = new Father("Tom");
    var son = new Son("Jack",18);
    console.log(father.getName());//Tom
    console.log(son.getName());//Jack//继承父类Father的getName()方法
    console.log(son.getAge());//18

    多态机制实现

    function Person(name) {
        this.name = name;
        if (typeof this.getName !== "function"){
            Person.prototype.getName = function () {
                return this.name;
            }
        }
        if (typeof this.toEat !== "function"){
            Person.prototype.toEat = function (animal) {
                console.log( this.getName() + "说去吃饭:");
                animal.eat();
            }
        }
    }
    function Animal(name) {
        this.name = name;
        if (typeof this.getName !== "function"){
            Animal.prototype.getName = function () {
                return this.name;
            }
        }
    }
    function Cat(name) {
        Animal.call(this,name);
        if (typeof this.eat !== "function"){
            Cat.prototype.eat = function () {
                console.log(this.getName() + "吃鱼");
            }
        }
    }
    Cat.prototype = new Animal();
    function Dog(name) {
        Animal.call(this,name);
        if (typeof this.eat !== "function"){
            Dog.prototype.eat = function () {
                console.log(this.getName() + "啃骨头");
            }
        }
    }
    Dog.prototype = new Animal();

    var person = new Person("Tom");
    person.toEat(new Cat("cat"));//Tom说去吃饭:cat吃鱼
    person
    .toEat(new Dog("dog"));//Tom说去吃饭:dog啃骨头

  • 相关阅读:
    PAT (Advanced Level) Practice 1097 Deduplication on a Linked List (25分) (静态链表+测试实例)
    PAT (Advanced Level) Practice 1096 Consecutive Factors (20分)
    POJ
    LightOJ
    LibreOJ
    SGU 223 国王 状压DP
    HDU
    CodeForces
    【模板】 拉格朗日插值
    模板 求二次剩余
  • 原文地址:https://www.cnblogs.com/zhuwenqi2016/p/7405961.html
Copyright © 2011-2022 走看看