<读书笔记>JavaScript系列之7种创建对象(面向对象)



写在前面:

以下三选一:

  • 阅读博文JavaScript 对象详解.
  • 阅读《JavaScript权威指南》第6章。
  • 阅读《JavaScript高级程序设计》第6章。
    • 注意:只需要看“理解对象”(Understanding Objects)部分。

6.2 创建对象

6.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("tianyuan", 22, "web-front-end");
   var person2 = createPerson("zhangsen", 21, "analysis");

   alert(person1.name);
   alert(person2.sayName());

6.2.2 构造函数模式

  • 三个特点:

    • 1.没有显示地创建对象
    • 2.直接将属性和方法赋给了this对象
    • 3.没有return语句
    • ⚠️注意:构造函数命名:开头大写
  • 代码实现:

function Person(name, age, job) {
       this.name = name;
       this.age = age;
       this.job = job;
       this.sayName = function() {
           alert(this.name);
       };
   }

   var person1 = new Person("tianyuan", 22, "web-front-end");
   var person2 = new Person("zhangsen", 21, "analysis");

   console.log(person1.name);
   console.log(person2.sayName());

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

   alert(person1 instanceof Object); // 检查person1是否是否为Objetct的实例, Objetct注意首位大写
   alert(person1 instanceof Person); // 检查person1是否是否为Person的实例
   alert(person2 instanceof Object); // 检查person2是否是否为Objetct的实例, Objetct注意首位大写
   alert(person2 instanceof Person); // 检查person2是否是否为Person的实例

6.2.3 原型模式

  • 每个函数都有一个prototype(原型)属性.

  • 1.prototype:

    • 这个属性是一个指针: [[Prototype]];
    • 通过调用构造函数而创建的那个对象实例的原型对象
    • 使用其的好处是: 可以让所有对象实例共享它所包含的属性和方法.
    • 也就是说:不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中.
    • 与构造函数不同的是: 其新对象的这些属性和方法是由所有实例共享的.
    • 这里需要理解原型对象,才能理解这种模式的原理.
    • __ proto __
    • p148 图解,秒懂
      • 原理: 原型对象是真实存在的,而person1,person2的prototype则是以虚拟的指针形式来引用真实的原型对象以达到共享属性和方法的目的.
    • isPrototypeOf()用来确定对象之间是否存在这种原型关系.
    • Object.getPrototypeOf,这个方法返回:[[Prototype]](ECMAScript 5 新增的方法)
    • delete操作符,实例属性会屏蔽原型中的同名属性,除非使用delete操作符删掉实例属性.
    • hasOwnProperty: 实例属性返回true, 原型属性则返回false
  • 2.in操作符与原型

    • in操作符: alert("name" in person); //true or false
    • hasPrototypeProperty()函数
    • in: IE早期版本 bug
    • Object.keys()
    • Object.getOwnPropertyNames(): 无论是否可以枚举,可得到所有实例属性.
    • 15,16皆可代替for-in循环枚举
  • 3.更简单的原型语法:

    • 提取prototype至于person后() {},代码如下
    • 简单版的字面量创建对象的方法会导致constructor不再指向Person
    • 通过设定将constructor值改为: Person后,会导致它的[[Enumerable]]被设置为true.
    • 重设构造函数(只适用于ECMAScript兼容的浏览器)
    function Person() {
    }

    Person.prototype = {
        name : "tianyuan",
        age : 29,
        job: "web",
        sayName: function() {
            alert(this.name);
        }
    };
  • 4.原型的动态性

  • 5.原生对象的原型

    • 可自定义方法:startWith()
  • 6.原型对象的问题:

    • 共享的话,一旦改,则全变,从而无法单独使用此模式,需要结合构造函数模式.
  • 代码实现:

function Person() {
}

Person.prototype.name = "tianyuan";
Person.prototype.age = 29;
Person.prototype.sayName = function() {
    alert(this.name);
}

var person1 = new Person();
var person2 = new Person();

person1.sayName();
person2.sayName();

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" 可枚举属性


// 在此种模式中,false问题得以解决;且新对象的这些属性和方法是由所有实例共享的.
alert(person1.sayName == person2.sayName); //true


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

  • 这是结合两种模式的长处所成的一个成熟模式

  • 优点:

    • 每个实例都会有自己的一份实例属性的副本
    • 同时又共享着对方法的引用
    • 最大限度地节省了内存。
  • 代码实现:

// 混合模式重写例子
// 这是目前ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法,可以说是定义引用类型的默认模式.
    function Person(name, age, job) {
        this.name = name;
        this.job = job;
        this.age = age;
        this.friends = ["tianyuan", "zhangsen"];
    }

    Person.protptype = {
        constructor : Person, // 指向Person原型
        sayName : function() {
            alert(this.name);
        }
    };

    var person1 = new Person("tianyuan", 22, "web-front-end");
    var person2 = new Person("zhangsen", 21, "analysis");

    person1.friends.push("Van");

    alert(person1.friends); // tianyuan,zhangsen,Van
    alert(person2.friends); // tianyuan,zhangsen
    alert(person1.friends === person2.friends); // false
    alert(person1.sayName === person2.sayName); // true

6.2.6 寄生构造函数模式

  • 代码实现类似于: 工厂模式与构造函数模式的结合体

  • 总的来说,建议在可以使用其它模式的情况下,不要使用此模式.

  • instanceof 操作符对此对象无意义

  • 代码实现:

    function Person(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 friend = new Person("tianyuan", 18, "web");
    friend.sayName();   // tianyuan*/


    // 这个模式可以在特殊的情况下用来为对象创建构造函数.(因为不能直接修改Array构造函数)
    function SpecifialArray() {
        // 创建数组
        var values = new Array();

        // 添加值
        values.push.apply(values, arguments);

        // 添加方法
        values.toPipedString = function() {
            return this.join("|");
        };

        // 返回数组
        return values;
    }

    var colors = new SpecifialArray("red", "ok", "blue");
    alert(colors.toPipedString());  // "red|ok|blue"

6.2.7 稳妥构造函数模式

  • 所谓的稳妥对象: 没有公共属性,且其方法也不引用this的对象.

  • 稳妥对象最适合在一些安全的环境中(禁止使用this or new),或者在防止数据被其它应用程序改动时使用.

  • 稳妥构造函数是与寄生构造函数类似的模式,但有2点不同: (1)新创建对象的实例方法不引用this. (2)不使用new操作符调用构造函数

  • 变量friend中保存的是一个稳妥对象,且instanceof 操作符对此对象无意义

  • ⚠️: 这种模式下,除了使用sayName()外,没有其它办法访问name值.

  • 代码实现:

function Person(name, age ,job) {

        var o = new Object();

        // 可以在这里定义私有变量和函数

        // 添加方法
        o.sayName = function() {
            alert(name);
        }

        // 返回对象
        return o;
    }

    var friend = Person("tianyuan", 18, "web");
    friend.sayName(); 	// tianyuan



定义访问器属性(新法)

   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.year);
   alert(book.edition);

定义访问器属性(旧法)

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.year);
   alert(book.edition);

Object.defineProperties

  • 定义多个属性(合起来)
 var book = {};

   Object.defineProperties(book, {
       _year: {
           value: 2004
       },

       edition: {
           value: 1
       },

       year: {
           get: function() {
               return this._year;
           },
           set: function(newValue) {

               if (newValue > 2004) {
                   this._year = newValue;
                   this.edition += newValue - 2004;
               }
           }
       }
   });

   var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
   alert(descriptor.value);
   alert(descriptor.configurable);
   alert(typeof descriptor.get);

   var descriptor = Object.getOwnPropertyDescriptor(book, "year");
   alert(descriptor.value);
   alert(descriptor.configurable);
   alert(typeof descriptor.get);

对象字面量创建对象

 //     对象字面量创建对象
    var person = {
        name: "TianYuan",
        age: "22",
        job: "web-front-end",

        sayName: function() {
            alert(this.name);
        }
    };
    alert(person.name);
    alert(person.age);
    alert(person.sayName());



【Javascript高级程序设计 】
第三版
p25
对未经声明变量调用delete不会导致错误?
p27
布尔类型:0,NaN,null,undefined会转化为false
p29
Number.MAX_VALUE==1.7976931348623157e+308。Infinity。
isFinite()
isNaN()
Number()
parseInt()指定基数,
parseFloat()

p34拼接字符串过程
toString()
p37
var num1=2;
var num2=20;
var num3=num1-- + num2;//等于22
var num4=num1 + num2;//等于21
p38
一元操作符 a=+a //a
一元操作符 b=-b //-b

p40-26
p42按位异或XOR
p43左移右移各种
Boolean()
短路操作符false
p47.8skip

p57for-in 枚举
p58label语句需配合for循环p59循环
with()

2016.03.17.08:40
p69 不能给基本类型值添加属性,只能对象


推荐译文:如何正确的学习JavaScript

posted @ 2016-06-01 11:31  箫声远  阅读(231)  评论(0编辑  收藏  举报