• javascript高级程序设计笔记(第6章 面向对象的程序设计)


    1、访问器属性:

    var book = {
      _year: 2004,
      edition: 1
    };
    Object.defineProperty(book, "year", {
      get: function(){
        return this._year;
        },
      set: function(newValue){
        if (newValue > 2004) {
          this._year = newValue;
          this.edition += newValue - 2004;
        }
    }
    });
    book.year = 2005;
    alert(book.edition); //2

    非标准方法:

    var book = {
        _year : 2004,
        edition : 1
    };
    //定义访问器的旧有方法
    book.__defineGetter__("year", function () {
        return this._year;
    });
    book.__defineSetter__("year", function (newValue) {
        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    });
    book.year = 2005;
    alert(book.edition); //2

    2、创建对象

      2.1 工厂模式(没有解决对象识别的问题(即怎样知道一个对象的类型))

    function createPerson(name, age, job) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function () {
            alert(this.name);
        };
        return o;
    }
    var person1 = createPerson("Nicholas", 29, "Software Engineer");
    var person2 = createPerson("Greg", 27, "Doctor");

    2.2 构造函数模式

    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function () {
            alert(this.name);
        };
    }
    var person1 = new Person("Nicholas", 29, "Software Engineer");
    var person2 = new Person("Greg", 27, "Doctor");

    alert(person1.constructor == Person); //true
    alert(person2.constructor == Person); //true

    alert(person1 instanceof Object); //true
    alert(person1 instanceof Person); //true
    alert(person2 instanceof Object); //true
    alert(person2 instanceof Person); //true

    把上面的构造函数当做函数

    // 当作构造函数使用
    var person = new Person("Nicholas", 29, "Software Engineer");
    person.sayName(); //"Nicholas"
    // 作为普通函数调用
    Person("Greg", 27, "Doctor"); // 添加到window
    window.sayName(); //"Greg"
    // 在另一个对象的作用域中调用
    var o = new Object();
    Person.call(o, "Kristen", 25, "Nurse");
    o.sayName(); //"Kristen"

    构造函数的问题:就是每个方法都要在每个实例上重新创建一遍。在前面的例子中,person1 和person2 都有一个名为sayName()的方法,但那两个方法不是同一个Function 的实例

    可以把函数定义转移到构造函数外部来解决这个问题:

            function Person(name, age, job){
                this.name = name;
                this.age = age;
                this.job = job;
                this.sayName = sayName;
            }
            
            function sayName(){
                alert(this.name);
            }
            
            var person1 = new Person("Nicholas", 29, "Software Engineer");
            var person2 = new Person("Greg", 27, "Doctor");
            
            person1.sayName();   //"Nicholas"
            person2.sayName();   //"Greg"
            
            alert(person1 instanceof Object);  //true
            alert(person1 instanceof Person);  //true
            alert(person2 instanceof Object);  //true
            alert(person2 instanceof Person);  //true
            
            alert(person1.constructor == Person);  //true
            alert(person2.constructor == Person);  //true
            
            alert(person1.sayName == person2.sayName);  //true 

    但是新的问题又来了:在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。而更让人无法接受的是:如果对象需要定义很多方法,那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了。好在,这些问题可以通过使用原型模式来解决。

    2.3 原型模式

    function Person() {}
    Person.prototype.name = "Nicholas";
    Person.prototype.age = 29;
    Person.prototype.job = "Software Engineer";
    Person.prototype.sayName = function () {
        alert(this.name);
    };
    var person1 = new Person();
    person1.sayName(); //"Nicholas"
    var person2 = new Person();
    person2.sayName(); //"Nicholas"
    alert(person1.sayName == person2.sayName); //true

    可以通过画图分析:非常重要图见书中

    下面这个函数可以用于断属性到底是存在对象中还是存在于原型中

    function hasPrototypeProperty(object, name) {
        return !object.hasOwnProperty(name) && (name in object);
    }

    ie BUG :ie不会枚举默认不可枚举的所有属性和方法包括:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()和valueOf()。

    var o = {
        toString : function () {
            return "My Object";
        }
    };
    for (var prop in o) {
        if (prop == "toString") {
            alert("Found toString"); //在IE 中不会显示
        }
    }

    枚举对象上的可枚举属性:keys/Object.getOwnPropertyNames

    function Person() {}
    Person.prototype.name = "Nicholas";
    Person.prototype.age = 29;
    Person.prototype.job = "Software Engineer";
    Person.prototype.sayName = function () {
        alert(this.name);
    };
    var keys = Object.keys(Person.prototype);
    alert(keys);     //"name,age,job,sayName"
    var p1 = new Person();
    p1.name = "Rob";
    p1.age = 31;
    var p1keys = Object.keys(p1);
    alert(p1keys);       //"name,age"
    var keys = Object.getOwnPropertyNames(Person.prototype);
    alert(keys);       //"constructor,name,age,job,sayName"

    使用对象直接量,不用每次都打一遍Person.prototype

    function Person() {}
    Person.prototype = {
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        sayName : function () {
            alert(this.name);
        }
    };

    但是这样上面的代码constructor 属性不再指向Person 了。

    解决方法:

    function Person() {}
    Person.prototype = {
        constructor : Person,
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        sayName : function () {
            alert(this.name);
        }
    };
    ----------------------------------------------------------------------------------------------------------------------------------------------------
    function Person() {}
    Person.prototype = {
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        sayName : function () {
            alert(this.name);
        }
    };
    Object.defineProperty(Person.prototype, "constructor", {
        enumerable : false,
        value : Person
    });

    原型的动态性:

    比较下面两段代码的不同:图表分析见书中

    var friend = new Person();
    Person.prototype.sayHi = function(){
    alert("hi");
    };
    friend.sayHi(); //"hi"(没有问题!)

    //注意这里的顺序:

    function Person() {}
    var friend = new Person();
    Person.prototype = {
        constructor : Person,
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        sayName : function () {
            alert(this.name);
        }
    };
    friend.sayName(); //error

    修改原生对象的原型:如给所有的字符串类型添加一个方法

    原型对象的问题:

    即两个实例的属性不可能完全相同

    如这个例子中两个人的朋友不可能完全相同,

    function Person() {}
    Person.prototype = {
        constructor : Person,
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        friends : ["Shelby", "Court"],
        sayName : function () {
            alert(this.name);
        }
    };
    var person1 = new Person();
    var person2 = new Person();
    person1.friends.push("Van");
    alert(person1.friends); //"Shelby,Court,Van"
    alert(person2.friends); //"Shelby,Court,Van"
    alert(person1.friends === person2.friends); //true

    2.4组合使用构造函数模式和原型模式

    构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,

    最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。下面的代码重写了前面的例子

    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ["Shelby", "Court"];
    }
    Person.prototype = {
        constructor : Person,
        sayName : function () {
            alert(this.name);
        }
    }
    var person1 = new Person("Nicholas", 29, "Software Engineer");
    var person2 = new Person("Greg", 27, "Doctor");
    person1.friends.push("Van");
    alert(person1.friends); //"Shelby,Count,Van"
    alert(person2.friends); //"Shelby,Count"
    alert(person1.friends === person2.friends); //false
    alert(person1.sayName === person2.sayName); //true

    2.5 动态原型模式

    可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。来看一个例子。

    function Person(name, age, job) {
        //属性
        this.name = name;
        this.age = age;
        this.job = job;
        if (typeof this.sayName != "function") {
            Person.prototype.sayName = function () {
                alert(this.name);
            };
        }
    }
    var friend = new Person("Nicholas", 29, "Software Engineer");
    friend.sayName();


    这里只在sayName()方法不存在的情况下,才会将它添加到原型中。这段代码只会在初次调用构造函数时才会执行。此后,原型已经完成初始化,不需要再做什么修
    改了。不过要记住,这里对原型所做的修改,能够立即在所有实例中得到反映。因此,这种方法确实可以说非常完美。其中,if 语句检查的可以是初始化之后应该存在的任何属性或方法——不必用一大堆if 语句检查每个属性和每个方法;只要检查其中一个即可。对于采用这种模式创建的对象,还可以使用instanceof 操作符确定它的类型。但是记住,使用动态原型模式时,不能使用对象字面量,

    2.6 寄生构造函数模式

    2.7 稳妥构造函数模式

  • 相关阅读:
    给WPF程序增加玻璃效果
    几款不错的VisualStudio2010插件
    一种快捷的解析HTML方案
    控制台输出螺旋型数字
    POJ 3692 Kindergarten(二分图匹配)
    HDU 1150 Machine Schedule(最小点覆盖)
    POJ 1847 Tram(最短路)
    HDU 1054 Strategic Game(树形DP)
    POJ 2195 Going Home(二分图最大权值匹配)
    POJ 1811 Prime Test(大素数判断和素因子分解)
  • 原文地址:https://www.cnblogs.com/liguwe/p/3965473.html
Copyright © 2020-2023  润新知