Javascript高级程序设计_6_面向对象

Posted on 2018-01-28 17:00  Jonathan_C  阅读(141)  评论(0)    收藏  举报
  •   面向对象的数据属性包括configurable(能否重新配置/删除), enumerable(能否枚举), writable(能否修改), value(属性的数据值)。\
1         var obj={
2             name:"Jonathan"
3         };
4         console.log(obj.name);
    1.  对象Obj的name属性的值(value)为Jonathan.
    2. 可以通过defineProperty来修改configurable, enumerable和writable三个属性。在修改前,这三个属性均为true。
1         var obj={
2             name:"Jonathan"
3         };
4         console.log(obj.name);//Jonathan
5         Object.defineProperty(obj,"name",{
6             writable:false
7         })
8         obj.name="Else";
9         console.log(obj.name);//Jonathan

      3. 需要注意的是,一旦对象的configurable被改成false之后,就不能再改回true了,若改成了true,则会报错。比如:

 1         var person={
 2             weight:120
 3         }
 4         Object.defineProperty(person,"weight",{
 5             configurable:false
 6         })
 7         Object.defineProperty(person,"weight",{
 8             configurable:true,
 9             value:100,
10         })//TypeError: Cannot redefine property: weight
  • 访问器属性除了数据值value不包括,还包括一对setter和getter函数。setter函数可以通过设置一个属性的值,来修改其他属性的值。比如:

    这里要注意的是,当用户修改book的属性year时,会调用getter和setter函数,修改_year和edition的值。这个方法可以有效防止私有变量_year被修改。

 1         var book={
 2             _year:2004,
 3             edition:1
 4         }
 5         Object.defineProperty(book,"year",{
 6             get:function(){
 7                 return this._year;
 8             },
 9             set:function(val){//这里val是year的形参,当修改该值的时候,会调用setter getter 函数
10                 if(val>2004){
11                     this._year=val;
12                     this.edition+=val-2004;
13                 }
14             }
15         });
16         book.year=2005;//when revise the value of year, this action calls the setter and getter function, which then revise the private variable _year
17         console.log(book.edition);//2

     通过defineProperties(这里要注意后缀)可以定义多个属性,比如book初始化为 var book={}的时候,通过defineProperty定义它的属性。例如:

        var paper={};
        Object.defineProperties(paper,{
            _year:{
                value:2003,
            },
            _author:{
                name:"Jonathan",
            }
        })
        console.log(paper._year);//2003
  • 创建对象  
  1. 工厂模式:通过函数接口来批量创建对象,例如
     1         function createObj(age, name, weight, grade){
     2             var obj=new Object();
     3             obj.age=age;
     4             obj.name=name;
     5             obj.weight=weight;
     6             obj.grade=grade;
     7 
     8             return obj;//这里有return 语句!!
     9         }
    10         var p1=createObj(10,"Jonathan", 120, "Year 2");
    11         console.log(p1.grade);
    12         console.log(typeof p1);//object
    13 
    14         var a=new String("a");
    15         console.log(typeof a);//object, you cannot tell the type difference between p1 and a.

    但是你无法知道这个对象的类型,比如上例中的a 和 p1。

  2. 所以有一种新的构造函数模式来构造对象。
1         function Person(age, name, weight){
2             this.age=age;
3             this.name=name;
4             this.weight=weight;
5         }
6         var p2=new Person(10,"Tom",70);
7         console.log(p2.age);//age

    这里没有显示的创建对象,只是通过this关键词将属性赋值给了对象属性,并且没有return语句。

    如果想知道p2的构造函数,通过p2.constructor即可得知。

    • 构造函数作为一种特殊的函数体,它的调用方法区别于其它的函数。任何函数通过new操作符来调用,那么该函数就可以作为构造函数。
    • 比较下面三种调用方法:
 1         var p2=new Person(10,"Tom",70);//当作构造函数调用
 2         console.log(p2.age);//10
 3         console.log(p2.constructor);
 4 
 5         Person(12,"Will",100);//当作普通函数调用
 6         console.log(window.age);//12
 7 
 8         var p3=new Object();//另一个对象的作用域调用
 9         Person.call(p3,14,"Jessy",80);
10         console.log(p3.age);//14
  •  原型模式
  1. 每个函数都具有原型,在创建新的函数时,JS会隐式的给这个函数创建一个prototype属性,这个属性类似指针,指向函数的原型对象。函数的原型对象具有constructor属性,指向构造这个对象的构造函数。
1         console.log(Person.prototype);//构造函数Person通过prototype指向它的原型。
2         console.log(p2.constructor);//对象p2通过constructor指向它的构造函数Person
3         console.log(Person.prototype.constructor);//又指回了Person.

  2. 通过isPrototypeOf和getPrototypeOf来判断对象之间的从属关系。

1         console.log(Person.prototype.isPrototypeOf(p2));//true
2         console.log(Object.getPrototypeOf(p2)==Person.prototype);//true;

  3. hasOwnProperty可判断对象是否具有自身的属性,无关原型。delete可删除对象自身的属性,但是无法删除原型的属性。

  4. in操作符则可以顺着原型链向上查找,返回布尔值。for-in循环可以返回能够访问的且可枚举的属性,无论实在原型还是实例本身。要想获得对象上所有可枚举的实例属性,使用Object.keys()方法。

1         console.log(Object.keys(p2));//["age", "name", "weight"]
  • 定义原型,可以通过更简单的方法。但是要注意重新定义的时候construtor的修改。
 1         function Video(){
 2             Video.prototype{
 3                 _year:2010,
 4                 _name:"Forever Love",
 5                 _Singer:"Jonathan",
 6                 _Price:120,
 7                 constructor:Video;//防止用instanceOf的时候无法判断是谁创建的实例
 8             }
 9             
10         }
11         Object.defineProperty(Video.prototype,"constructor"{
12             enumerable:false,
13             value:Person,
14         })//因为修改了原型中constructor属性,所以重新将enumerable属性设置回false
  • 所有原生的引用类型(object, Array, String 等等),都具有原型。并且其方法都已经在原型中定义好了。可以在浏览器控制台看Array.prototype
  • 构造函数和原型模式的混合使用:
  1. 原型模式定义共享的属性,构造函数用于定义实例对象。例如:
 1 console.log('Construtor Mode+Prototype Mode:')
 2         function Animal(name, age, weight,food){
 3             this.name=name,
 4             this.age=age,
 5             this.weight=weight,
 6             this.food=food
 7         }
 8         Animal.prototype={
 9             constructor:"Animal",
10             sayName:function(){
11                 alert(this.name);
12             }
13         }
14         var cat=new Animal("mimi",5,20,["fish"]);
15         var dog=new Animal("wawa",6,15,["bone"]);
16         cat.food.push("rat");
17         console.log(cat.food);//["fish", "rat"]
18         console.log(dog.food);//["bone"]
19         console.log(dog.sayName==cat.sayName);//true
  •  寄生构造函数模式
 1         //寄生构造模式parasite constrution mode
 2         function someone(name, age,job){
 3             var o=new Object();
 4             o.name=name;
 5             o.age=age;
 6             o.job=job;
 7             o.sayName=function(){
 8                 console.log(this.name)
 9             }
10             return o;
11         }
12         var friend=new someone("JS",12,"hardwork");
13         friend.sayName();//JS

寄生构造函数模式,除了在函数内部用new新建了一个构造函数以外,其它都和工厂模式一样。

这个模式很有意思,看以下代码:

 1         //寄生模式的应用
 2         function specialArray(){
 3             var values=new Array();//values相当于构造函数
 4             values.push.apply(values,arguments);//给构造函数添加值
 5             values.toPipedString=function(){//定义toPipedString方法
 6                 return values.join("|");
 7             }
 8             return values;//返回构造函数
 9         }
10         var colors=new specialArray("BLUE","YELLOW","RED");//新建colors对象
11         console.log(colors.toPipedString());//BLUE|YELLOW|RED  调用toPipedString方法

有时候,把function看成JAVA中的class能帮助于理解,呵呵

  • 稳妥构造函数的方法
 1         //稳妥构造函数模式
 2         function People(age,name,job){
 3             var o=new Object();
 4             o.name=name;
 5             o.age=age;
 6             o.job=job;
 7             o.sayName=function(){
 8                 return o.name;
 9             }
10             return o;
11         }
12         var aMan=new People(20,"Jonathan","Coding");
13         console.log(aMan.sayName());//Jonathan

这里所谓的稳妥,是指在安全模式下,不用this来构建,并且外部只能通过sayName来访问name这个字段,其他字段初始化之后便不能修改。