javascript的面向对象程序设计(一)

JavaScript中没有类的概念,与传统的有类的面向对象程序的语言有所不同;

1.1.理解对象;

创建一个对象最简单的方式,就是创建一个object()实例;然后再为它添加属性和方法;

var person = new person();
person.name="t";
person.age = 21;
person.job = "student";
person.sayName= function (){
  alert(this.name);        
}
View Code

用创建对象字面的方式创建;

var person ={
    name:"t",
    age:20,
    job:"student",
    sayName:function(){
        alert(this.name);
    }                 
 }
View Code

1.2.属性类型;

属性的各种特征;

1.2.1数据属性;[[configurable]],[[Enumerable]],[[Writeable]],[[Value]];

[[configurable]],[[Enumerable]],[[Writeable]]设为true; 而[[Value]]设置为值;

要修改属性的默认属性;Object.defineProperty();接收三个参数:对象名,属性名,描述符对象;

var person = new Object();
Object.defineProperty(person,"name",{
  writeable:false,
  value:"zht"
}

1.2.2 访问器属性:访问器属性不包含数值,它们包含一对set和get函数,不过这两个函数都不是必须的。

Get:在读取属性时调用的函数;Set:在写入属性时调用的函数;

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   
View Code

1.3.读取属性的特性;使用Object.getOwnPropertyDesciptor();返回值是一个对象;

2.1创建对象;

虽然object构造函数和对象字面量能够创建对象;使用这样的单一的接口,创建类似的对象时,会造成代码的冗余,所以,我们必须进行代码的封装;

工产模式使我们大家都比较熟悉的创建型设计模式;

考虑到JavaScript无法创建类,开发人员就发明了一种构造函数,用这个函数来封装;

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(1,1,1);
var person2 = createPerson(2,2,2);
View Code

2.2构造函数模式;

像object和Array这样的原生构造函数,自己也可以定义自己的构造函数;

代码如下:

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

}
var person1 = new person(1,1,1);
var person2 = new person(2,2,2);
View 

跟上面的例子有些不同:1.没有显示的创建对象;2.直接将属性和方法赋给this对象;3.没有return语句;

用上面的方法创建对象时,会经历以下步骤;1.创建新对象:2.将构造函数的作用域赋给新对象(因此this就指向了新对象);3.执行构造函数的代码(初始化属性)4.返回对象;

person1和person2这两个对象都会有个constructor(构造函数)属性;该属性指向person;

但是对象类型检测 instanceof 会好一些;

2.3将构造函数当做函数;

构造函数与其他函数的区别在于调用的方式不同,任何函数只要通过new来调用,就可以称作是构造函数; 

//当做构造函数使用
var person = new person(1,1,1);
person.sayName();
//用普通的函数使用;
person(1,1,1);  //添加到window中l
window.sayName();

在用普通的函数使用时,挡在全局作用域调用一个函数时,this对象总是指向Global对象;在浏览器中,就是window对象;因此在第二种方法中,调用函数完时,用window对象

调用属性;

2.4构造函数的问题;

使用构造函数的问题,属性如果是函数的话,就会在每个实例中都要实例这个函数,上述的构造函数也可以这样定义:

function person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = new Function("alert(this.name)");// 与声明函数是等价的;


}
View Code

解决不同的实例要实例多个同一个函数的方法;把方法写到构造函数之外,但是这种方法也有一种问题,就是,这些方法都成了全局作用域的方法,无法 ,体现出封装性的特征,

还有一点就是,一般情况下不能够,过多的声明全局变量;由此引出原型模式;

2.4 原型模式;

我们创建一个函数,(函数也是对象)就会有一个prototype这个属性,这个属性是一个指针,这个指针指向一个对象,这个对象是通过调用构造函数而创建的那个对象实例的原型

对象;代码如下:

function Person(){};
Person.prototype.name = "Nical";
Person.prototype.age = 18;
Person.prototype.job = "student";
person.prototype.sayName = function(){
alert(this.name);

}
var person1 = new Pesron();
person1.sayName();//Nical;
var person2 = new Person();
person2.sayName();//Nical;
alert(person1.sayName ==person2.sayName) //true
View Code

接下来我们理解下原型模式的工作原理;

 这张图片是对上述代码的解释;

原型对象最初只有constructor这个属性,并且这个属性指向了该构造函数;

我们可以通过对象的实例来访问对象原型的值;但是我们不能通过对象实例来修改对象原型的值;如果我们在对象实例上添加一个跟原型一样的属性,那么当我们访问这个属性时,返回的值是在对象实例上的值,而不是对象原型上的值,这是因为,JavaScript在搜索时,就已经在对象实例上搜索到这个值了,就没有必要在继续往上,想对象原型搜索了;

可以使用hasownproperty()方法来检测这个属性时在对象实例上还是在原型对象上,只有在对象实例上才会返回true;

 

2.4.2

in和原型;属性是在对象实例上还是在对象原型上只要有这个属性,就会返回true;

alert("name" in person1);

2.4.3 更加简单的创建对象原型的方法;

function Person((){};
Person.prototype ={
 name:"zht",
 age :20;
 job:"student",
 sayName:function(){
   alert(this.name);
 }


};
View Code

这样的创建代码更加简洁,但是跟上述写的对象原型也有所不同,这个写法,相当于重写了一个新的原型对象;这个原型对象constructor属性不指向构造函数,大部分情况下是指向

Object 这个默认的构造函数了。但是用instanceof 检测类型时,还是可以返回true;所以如果constructor这个属性很重要,可以重新特意的将它设置我们的构造函数;从而确保在

访问时能够返回正确的值;但是,以这种方式设置的constructor属性的[[Enumerable]]为true;默认情况下 为false;

2.4.4 原型的动态性;

由于在原型上搜索值是一次性搜索,所以在原型对象做的修改,能够立即在对象实例上反应出来------即使是先创建对象实例 后修改对象原型 也是这样子的;

var friend  = new Person();
Person.prototype .sayHi= function(){
    alert("hi");
}
friend.sayHi();  //hi  
View Code

虽然实例是在原型之前创建的,但是在查找属性时,先在实例查找有没这个属性,然后再在原型对象查找,因为在实例和原型对象之间是一个指针而不是一个副本;因此就可以在

原型中找到sayhi属性并保存;

但是如果原型是向上述的重写的话,情况就会不一样了。因为指针指向发生了变化,

注意点,重写了原型对象,就等于切断了原型与任何之前已经存在的对象实例的联系,它们引用的还是最初的原型;

2.4.5 原生对象的模型;

原型模式的重要性,不仅仅体现在自定义对象类型,还体现在,连原生的对象模型,也是采用这种模式定义的;

所有原生引用类型(Object,Array,String ,Function);都在其构造函数的原型上定义了方法。例如,可以在Array.prototype中找到sort方法;

通过原生对象原型的引用,不仅可以取得默认的方法的使用还可以定义新方法;

2.4.6 原型模式的问题;

posted @ 2015-07-21 08:46  坏婷坏婷  阅读(184)  评论(0编辑  收藏  举报