Javascript之 面向对象的程序设计

对象:

创建对象的方式:
  • 实例化对象:

    var obj = new Object();
    
  • 对象字面量:

    var obj = { ... };
    
属性类型:
数据属性:

包含一个数据值的位置。在这个位置可以读取和写入值。

var person = { name: xuchao, ... };     // name为数据属性
4个描述其行为的特性:
  • [ [ Configurable ] ]:表示能否通过delete删除属性,能否修改属性的特性,能否把属性修改为访问器属性。默认为true。
  • [ [ Enumerable ] ] :表示能否通过for-in循环返回属性。默认为true。
  • [ [ Writable ] ] :表示能否修改属性的值。默认为true。
  • [ [ Value ] ] :属性的数据值。默认为undefined。
修改属性默认的特性:
Object.defineProperty( Object , propertyName, obj );
/********************************************
 Object: 属性所在的对象,
 propertyName: 属性名,
 obj: 描述符对象  { Writable : false, ..... }
********************************************/

使用Object.defineProperty()创建新属性时,如果不指定,则ConfigurableEnumerableWritable默认为 false

访问器属性:

不包含数值。不能直接定义,智能通过Object.defineProperty()定义。

  • [ [ Configurable ] ]:表示能否通过delete删除属性,能否修改属性的特性,能否把属性修改为访问器属性。
  • [ [ Enumerable ] ] :表示能否通过for-in循环返回属性。默认为true。
  • [ [ Get ] ] :读取属性时调用的函数。默认为undefined。
  • [ [ Set ] ] :在写入属性时调用的函数。默认为undefined。
定义多个属性:
Object.defineProperties( Object , {
    propertyName_1: {
		writable: ... ,
          ...
    },
    propertyName_2: {
        writable: ... ,
          ...
    },
    ....
});
读取属性的特性:
var obj = Object.getOwnPropertyDescriptor( Object , propertyName );
//返回一个对象,如果是数据属性,则对象属性为数据属性的特性,访问器属性同理。

创建对象:

工厂模式:

用函数封装对象:

function createPerson (name, age, job) {
    var o  = new Object();
    o.name = name;
    o.age  = age;
    a.job  = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}
// 实例化一个对象
var person_1 = createPerson("Xuchao", 23, "Web Security Engineer");

缺点:没有解决对象识别问题

构造函数模式:

创造自定义的函数构造属性和方法:

function Person (name, age, job) {
    this.name = name;
    this.age  = age;
    this.job  = job;
    this.sayName = function() {
        alert(this.name);
    };
}
// 实例化一个对象
var person_1 = new Person("Xuchao", 23, "Web Security Engineer");

实例化对象后会产生一个constructor(构造函数)属性,该属性指向原型,既 person_1.constructor = Person

优点:解决工厂模式的缺点。

缺点:每个方法需要在每个实例上重新创建一遍。

原型模式:

让所有对象实例共享原型对象的属性和方法:

function Person () {
    Person.prototype.name = "Xuchao";
    Person.prototype.age  = 23;
    Person.prototype.job  = "Web Security Engineer";
    Person.prototype.sayName = function () {
        alert(this.name);
    };
}
//实例化一个对象
var person_1 = new Person();
person_1.sayName();   // "Xuchao"
alert(person_1.sayName() == person_2.sayName());  // "true"
理解原型对象:

1、Obj.prototype.isPrototypeOf( obj_x ); 判断obj_x中是否有Obj.prototype的指针

2、Object.prototype.getPrototypeOf( obj_x ); 返回obj_x中[ [ prototype ] ]的值

​ 为实例添加名字相同的属性,会将指针指向实例属性而屏蔽掉原型属性上的值,若想让指针重新指向原型属性,需用 delete 删除实例属性。

Obj.hasOwnPrototype( propertyName ) 判断属性值是实例属性还是原型属性

原型与in操作符:

单独使用 in 操作符,可以判断指定属性是否可以通过对象访问到(与实力属性、原型属性无关,只要能访问该属性都返回true

hasOwnProperty()方法结合使用可以判断该属性是存在于实例对象中,还是存在于原型中。

Object.keys( Element )

Object.getOwnPropertyNames( Element )

更简单的原型语法:

通过对象字面量重写原型对象:

function Person(){
}
Person.prototype = {
    name: 'Xuchao',
    age: 23,
    job: 'Web',
    sayName: function(){
        alert(this.name);
    }
};

使用该方法重写原型,constructor不再指向Person,而是指向Object,解决方法如下:

Person.prototype = {
    constructor: Person,   //解决constructor不指向Person的问题
      ...
};//此方法会将constructor变为可枚举对象,即[ [ Enumberable ] ]特性被设置为true
原型的动态性:

对原型对象所进行的任何修改都能够立即从实例上反映出来,因为指向原型的是一个指针而不是一个副本

var friend = new Person();
Person.prototype.sayHi = function(){
    console.log("Hi");
};
friend.sayHi();    // "Hi"

重写原型对象后,实例指向的依旧是原来的原型对象而非新的原型对象

原型对象的问题:
  1. 省略了为构造函数传递初始化参数的环节,结果会导致所有的实例具有相同的属性值。
  2. 原型中所有的属性都是被很多实例共享的,在一个实例中修改原型属性其他实例也同样会修改。
组合使用构造函数模式和原型模式:

构造函数模式用于定义实例属性,原始模式用于定义方法和共享的属性

> 每一个实例都会有一份实例属性的副本,但又同时共享着对方法的引用
寄生构造函数模式:

创建一个函数,封装创建对象的代码,再返回新创建的对象。

function Person (name, age, job) {   //一般情况下不建议使用
    var o  = new Object();
    o.name = name;
    o.age  = age;
    a.job  = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}
// 实例化一个对象
var person_1 = new Person("Xuchao", 23, "Web Security Engineer");

与工厂模式区别:使用new操作符,包装函数叫做构造函数

稳妥构造函数模式:
  1. 没有公共属性
  2. 其方法不引用this对象

与其他模式不同:

  1. 新建方法不引用this
  2. 不使用new操作符调用构造函数

适合在安全执行环境下使用

继承

利用原型链实现继承。

原型链

一个实例指向原型对象,而原型对象又是另一个原型的实例,层层叠进,构成原型链。

默认原型:

所有的引用类型都继承了Object,所有函数都是Object的实例。因此默认原型都会包含一个指针指向Object.prototype

原型和实例的关系:

  1. instanceof操作符
instance instanceof Object      //实例instance是否在对象Object中  true/false
  1. isPrototypeOf方法
Object.prototype.isPrototypeOf(instance)  //同上
原型链定义需要注意的问题:
  1. 给原型添加方法的代码一定要放在替换原型的语句以后
  2. 通过原型链事先继承时,不能使用对象字面量创建原型方法。因为这样会重写原型链。
借用构造函数(伪造对象、经典继承)

在子类型构造函数的内部调用超类型构造函数

function SuperType(){
    this.colors = ['red','green','blue'];
}
function SubType(){
    // 继承了SuperType
    SuperType.apply(this);
}

不会共享属性,而是会通过apply()方法产生一个副本

  1. 可以在子类型构造函数中向超类型构造函数传递参数
function SuperType( name ){
    this.name = name;
}
function SubType(){
    // 继承了SuperType,同时还传递了参数
    SuperType.apply(this, 'Xuchao');
}
  1. 方法函数无法复用,在超类型原型定义的方法,对子类型也不可见。
组合继承(伪经典继承)

将原型链和借用构造函数的技术结合到一块

function SuperType(name){
    // 利用构造函数模式创建原型属性
    this.name = name;
}
SuperType.prototype.sayName = function(){
    // 利用原型链的方式创建原型方法
    console.log(this.name);
}
原型式继承

借助原型中可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

function object(o){
    function F(){}     // 创建一个临时性的构造函数
    F.prototype = o;   // 将传入的对象作为这个构造函数的原型
    return new F();    // 返回了这个临时类型的一个新实例
} // 其本质是object对传入的对象进行了一次浅复制

ES5通过新增Object.create()方法规范了原型式继承:

Object.create(protoObj, propeytyObj[可选])  //新对象的原型对象, 为新对象定义额外属性的对象

包含引用类型值得属性始终都会共享相应的值,就像是用原型模式一样

寄生类继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再返回对象

function createAnother( func_1 ){
    var clone = object( func_1 );   // 通过调用函数创建一个新对象[可以用其他方式]
    clone.sayHi = function(){       // 以某种方式来增强这个对象
        alert("Hi");
    };
    return clone;   // 返回这个对象
}
寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混合形式来继承方法。

function inheritPrototype( subType, superType ){
    var prototype = object(superType.prototype);   // 创建对象
    prototype.constructor = subType;               // 增强对象
    subType.prototype = prototype;                 // 指定对象
}// 只调用一次SuperType构造函数,避免了在SubType.prototype上创建不必要的、多余的属性,且原型链不变
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值