zoukankan      html  css  js  c++  java
  • 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 原型模式的问题;

  • 相关阅读:
    【万丈高楼平地起 第一季 链表是怎样链成的】
    【笔记——ASP.NET基础知识(一)】
    【万丈高楼平地起 第二季 队列和栈】
    【没有银弹No Silver Bullet】
    【简单示例:数据库表转XML】
    【软件工程小知识】
    【总结——SQL Server中的数据类型】
    【总结—.Net Framework集合类】
    【笔记——ASP.NET基础知识(二)】
    【总结——ASP.NET对象】
  • 原文地址:https://www.cnblogs.com/zht0915/p/4663338.html
Copyright © 2011-2022 走看看