《JavaScript高级程序设计》读书笔记--6-面向对象的程序设计

来源:互联网 发布:mac发布会时间 编辑:程序博客网 时间:2024/03/29 17:29

理解对象

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

创建了person对象,添加了三个属性和一个方法。
属性类型
数据属性包含一个数据值的位置,这个位置可以读取和写入值。有4个描述其行为的特性:

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性或者能否把属性修改为访问属性。默认为true。
  • [[Enumerable]]:表示能否通过for-in循环返回属性,默认为true。
  • [[Writable]]:表示能否修改属性的值,默认为true。
  • [[Value]]:包含这个属性的数据值,读取属性值的时候从这个位置度,写入属性值的时候把新值保存在这个位置,默认为undefined。
var person = {    name: "Nicholas"};

这里创建了一个名为name的属性,为它指定的值是Nicholas,也就是说[[Value]]特性将被设置为Nicholas,而对这个值的任何修改都将反映在这个位置 。
修改属性默认特性,必须使用Object.defineProperty()方法。其接收三个参数,对象、属性名称和描述符对象。在调用该方法时,如果不指定,configurable、enumerable和writable特性的默认值都是false。
访问属性不包含数据值,包含一对getter和setter函数。
Object.defineProperties()方法可以通过描述符定义多个属性。
Object.getOwnPropertyDescriptor()方法可以读取属性的描述符。

创建对象

工厂模式

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");

函数createPerson()能够根据接收的参数来构建一个包含所有必要信息的Person对象,可以无数次的调用这个函数,而每次他都会返回一个包含三个属性和一个方法的对象。
构造函数模式

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");

这个例子中Person()函数取代了createPerson()函数,不同之处:

  • 没有显式地创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句

此外,构造函数应以大写字母开头,非构造函数应以小写字母开头。
要创建Person的新实例必须要使用new操作符,以这种方式调用构造函数实际上会经历以下4个步骤:

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 返回新对象

将构造函数当作函数
与其他函数的唯一区别在于调用方式的不同,任何函数只要通过new操作符来调用那他就可以作为构造函数,而任何函数,如果不通过new操作符来调用,那他跟普通函数也不会有什么两样。

构造函数的问题
就是每个方法都要在每个实例上重新创建一遍。
用原型模式解决。

原型模式
创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,使用原型对象的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象的实例信息,而是可以将这些信息直接添加到原型对象中。

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

person1和person2都是访问的同一组属性和方法。
若实例中重新创建了与原型中相同名字的属性,则该属性将会屏蔽实例原型中的属性。但是不会修改实例原型中的同名属性。
使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是原型中。存在于实例中则返回true。

原型与in操作符
单独使用时,in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
使用for-in循环时,返回的是所有能够通过对象访问的、可枚举属性,其中既包括存在于实例中id属性也包括存在于原型中的属性。
Object.keys()方法可以取得对象上所有可枚举的实例属性。
Object.getOwnPropertyNames()方法返回所有的实例属性,无论他是否可枚举。

更简单的原型语法

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

原型的动态性
实例中的指针仅指向原型,而不是指向构造函数。
尽管可以随时为原型添加属性和方法,并且修改能够立即在所有对象实例中反映出来,但是如果重写整个原型对象,将会切断现有原型和任何之前已经存在的对象实例之间的联系,他们引用的仍然是最初的原型。

原生对象的原型
不支持添加原生对象的原型属性和方法。

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

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);    }};

动态原型模式
可以通过检查摸个应该存在的方法是否有效来决定是否需要初始化原型。

if(typeof this.sayName!= "function"){    Person.prototype.sayName = function(){        alert(this.name);    };}

寄生构造函数模式
基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但是从表面上看,这个函数又很像是典型的构造函数。

稳妥构造函数
所谓稳妥对象,是没有公共属性,其方法也不用引用this的对象,适合在一些安全的环境中或者防止数据被其他应用程序改动时使用 使用。
创建对象的实例方法不引用this,不使用new操作符调用构造函数。

继承

js只支持实现继承,而且其实现继承主要是依靠原型链来实现。
原型链
基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
构造函数、原型和实例的关系:
每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

function SuperType(){    this.property = true;}SuperType.prototype.getSuperValue = function(){    return this.property;};function SubType(){    this.subproperty = false;}//继承了SuperTypeSubType.prototype = new SuperType();SubType.prototype.getSubValue = function(){    return this.subproperty;};var instance = new SubType();alert(instance.getSuperValue());//true

关系图
SubType继承了SuperType,而SuperType继承了Object。

确定原型和实例的关系
instanceof操作符,只要用这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回true。
isPrototypeOf()方法,同样返回true。

谨慎的定义方法不管怎样,给原型添加方法的代码一定要放在替换原型的语句之后。
在通过原型链实现继承时,不能使用对象字面量创建原型方法,这样会重写原型链。

借用构造函数
基本思想即在子类型构造函数的内部调用超类型构造函数。

组合继承
将原型链和借用构造函数的技术组合到一起,从而发挥二者之长的一种继承模式。思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数实现对实例属性的继承。这样即通过在原型上定义方法实现了函数复用,又能够保证每个实例都有他自己的属性。

原型式继承
寄生式继承
寄生组合式继承

0 0
原创粉丝点击