2

面向对象程序设计

工厂模式

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"); 
缺点: 不知道一个对象的类型,没有构造函数

构造函数模式

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"); 
缺点: 每个方法都会被重新创建一遍,方法是可以被重用的,多次创建会造成资源浪费

原型模式

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(); 
缺点: 属性值是引用类型的数值,如果修改属性值那么就会在所有的实例中反映出来

混合模式(原型 + 构造函数)

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

注意:

  1. 属性值、对象使用构造函数,方法使用原型
  2. 原型直接赋值,会覆盖默认原型,对应的将construtor属性覆盖,如果需要此属性,需要手动赋值

对象知识点

  • 每个函数都有原型,prototype属性指向原型
  • 每个原型对象都有一个constructor指向构造函数本身
  • 每一个构造函数实例化对象都有一个__proto__对象指向构造函数的原型对象prototype
  • delete只能删除实例上的属性,不能删除原型上的属性
  • 给实例属性名赋新值,只是创建在实例上覆盖了原型的值,不会修改原型上的值

    var Person = function(){};
    
    Person.prototype.name = 'wang';
    
    var person1 = new Person();
    
    person1.name = 'li';
    
    console.log(person1.name); // li  只是覆盖了原型上的值,不能修改
  • isPrototypeOfgetPrototypeOf方法都可以判断实例化对象的原型

    Person.prototype.isPrototypeOf(person1); // true
    Object.getPrototypeOf(person1) === Person.prototype; // true

hasOwnPropertyin区别

  • hasOwnProperty 如果属性在实例上那么返回true,如果是原型上那么返回false
  • in 属性只要是可以访问到,那么就返回true,不管是实例上还是原型上
var person1 = new Person();
var person2 = new Person();

person1.name = 'zhang';

person1.hasOwnProperty('name'); // true
person2.hasOwnProperty('name'); // false

'name' in person1; // true
'name' in person2; // false

Object.getOwnPropertyNamesObject.keys 比较

相同点

  • 都可以用来获取对象的属性名,都不能获取原型上的对象

#### 不同点

  • getOwnPropertyNames 可以获取不可枚举属性,但keys 不能

面向对象的程序设计

  • 工厂函数
  • 构造函数
  • 原型设计
  • 原型 + 构造函数

确定原型和实例的关系

  • instanceofisPrototypeOf 都可以用来判断原型和实例的关系,且有一个共同点,只要是出现在原型链上的构造函数,都可以返回true
person1 instanceof Person; // true
person1 instanceof Object; // true

Person.prototype.isPrototypeOf(person1); // true
Object.prototype.isPrototypeOf(person1); // true
所有构造函数的原型默认是Object的实例

继承

原型链

通俗的说就是一个构造函数的原型引用了另一个构造函数的实例,而引用的构造函数原型又引用了其他构造函数实例....,层层引用,形成一个引用链条

优点

  • 可以很好实现继承,定义一次,可以复用

缺点

  • 层层递进会形成共用属性,一个实例修改,那么所有引用会全部修改
  • 创建子类型的实例时,不能给超类型构造函数传递参数

借用构造函数

通过call或者 apply 方法将一构造函数属性复用为自己的属性
var Person = function(){
  this.name = 'wang';
}

var Child = function(){
  Person.call(this);
  this.age = 23;
}

var child = new Child();

child.hasOwnProperty('name'); // true 是对象的自有属性,而不是继承自原型链

优点

  • 可以给超类型传参数
  • 可以解决共享属性问题

缺点

  • 不可见借用构造函数原型上的方法
  • 无法复用函数,每实例化一个对象,就会创建一个函数,造成资源浪费

组合继承(最常用)

  • 使用构造函数继承属性值
  • 使用原型链继承原型上的属性和方法
Person.prototype.getName = function(){};

var Child = function() {
  Person.call(this);
  this.sex = 'female';
}

Child.prototype = new Person();
Child.prototype.getSex = function(){};

listenWind
271 声望3 粉丝

下一篇 »
递归