第八章 面向对象之一:对象的理解

js的面向对象概念跟C++、Java不太一样,更像是一个精简版的设计(可能是因为语言设计者本身讨厌面向对象随便为了应付弄出来一个?还是为了减轻浏览器的负担才这么设计,我觉的是第二者哦,毕竟解释型程序没有编译型程序效率高)。

ECMAScript对对象的定义:”无需属性的集合,其属性可以包含基本值、对象或者函数“。等等,这句话眼熟啊,想起来了吧,Object类型就是这么定义的啊。所以,Object类型就是js里所有对象(类)的父类。

而所有通过new Array、new String的变量都是Array类String类的实例,当然Array、String类的父类也都是Object。

我们知道,做为一个对象,要有属性和方法,js里创建自定义对象的主流方法是字面量方法,如下:

<script>
//这实际是Object的一个实例
var Mouse = {  
    name : "老鼠",
    sayHello : function () {
        alert("吱吱吱");
    }
}
Mouse.sayHello();
</script>

相当于:

var Mouse = new Object();  //创建Object的实例
Mouse.name = "老鼠";
Mouse.sayHello = function () {
    alert("吱吱吱");
}

Mouse.sayHello();

但是这种字面型创建实例的方法,除了做为配置文件外其实我觉的没什么用,因为在创建实例的时候,我们一般需要传入参数进去,建立自己的类,并通过类创建实例更加有用,后续再介绍。Mouse对象有一个name属性和一个sayHello()方法,在js中,制造属性的方法有两种,一种是“赋值”、一种是“定义”。

“制造(或修改)"一个新(或者已经存在)的属性,赋值的方法就是我们上边代码内用的方法,定义的方法是通过Object.defineProperty()函数实现的,用法为Object.defineProperty(对象,属性名,配置文件);,后边我们会举例说明。

通过赋值和定义方法制造出来的属性会有不同,主要表现在:

  • 定义方法:对象如果本身已经存在了这个属性,则修改,如果不存在则新定义。只针对本身对象操作。
  • 赋值方法:如果对象本身存在这个属性,则修改,如果不存在,会根据原型链往上找,如果找不到,则在对象本身上进行属性制造,如果找到了,那就麻烦大了。。。。。(这篇博文看了都不用看我这个,我这个只是为了总结学习用。http://www.cnblogs.com/ziyunfei/archive/2012/10/31/2738728.html)

所以区别就是,定义方法制造属性只针对当前对象本身操作,而赋值会进行原型链查找。

在js里,属性的分类有三种:数据属性访问器属性、内部属性,他们的区别如下:

  • 数据属性:拥有确定值的属性。
  • 访问器属性:配置了getter和setter的数据属性。
  • 内部属性:javaScript引擎内部使用的属性,比如原型属性等。

也就是说,实际上name属性是还有属性的,它的属性是定义了它属性本身的一些特点。也就是说,数据属性和访问器属性是可以配置的,具体来说,他们两个各自有四个属性(其中有两个是共同的),也就是数据属性和访问器属性都各自有两个特性属性,还有两个公用属性

共用属性:

  • [[Configurable]]:能否通过delete删除从而重新定义属性。
  • [[Enumerable]]:能否通过for-in循环返回属性。

数据属性特有属性:

  • [[Writeable]]:能否修改属性的值。
  • [[Value]]:包含这个属性的数据值。读取属性值的时候从这里读取,写入的时候写入到这里,默认为undefined。

访问器属性特有属性:

  • [[Get]]: 存储着getter方法。
  • [[Set]]: 存储着setter方法。

下面举例通过Object.defineProperty()方法设置属性如下(其他属性设置也是如此,但是可以一次性设置多个属性):

<script>
//这实际是Object的一个实例
var Mouse = {  
    name : "老鼠",
    sayHello : function () {
        alert("吱吱吱");
    },
    sayName : function () {
        alert(this.name);
    }
};
Object.defineProperty(Mouse,"name",{
    writable:false,  //设置Mouse实例的name属性不能修改值
    value:"耗子"  //但是此处还是可以的,需要{}里的运行完才起作用?这里不清楚
});
Mouse.name = "耗子1";  //并没有什么用
Mouse.sayName();  //耗子
</script>

 这是数据属性定义的方法,我们定义了一个已经存在的属性,所以JS就直接重写了name属性,如果我们定义一个age属性,则会新增加一个age属性,大家理解一下。下面写一段访问器属性的get、set方法:

<script>
//这实际是Object的一个实例
var Mouse = {  
    name : "老鼠",
    sayHello : function () {
        alert("吱吱吱");
    },
    sayName : function () {
        alert(this.name);
    }
};

Object.defineProperty(Mouse,"age",{  //通过定义方法增加了一个新的访问器属性,名字为age,age的getter是get函数,setter是set函数
    get : function () {  //
        alert("getter接口");
        return this.name;
    },
    set : function (ages) {  //赋值操作会通过set函数执行。
        alert("setter接口");
        if (ages>10)    {
            this.name = "大耗子";
        }
        else {
            this.name = "小耗子";
        }
    }
});
Mouse.age = 123;  //通过set函数对age进行赋值
alert(Mouse.age);  //通过get函数进行读取  显示123
</script>

所以我认为,如果你给属性设置了get或者set函数,那么他就是访问器属性,如果不设置,就是数据属性。当然,定义访问器属性的时候是无法使用数据属性的value值的,这也是区别吧,主要在方式方法上的区别。

那么,如何取得一个属性的特性呢,在ECMAScript5里,有一个Object.getOwnPropertyDescriptor()方法,它有两个参数,属性所在的对象和属性名。

接上边继续编码:

var a = Object.getOwnPropertyDescriptor(Mouse,"age");
console.dir(a);
a = Object.getOwnPropertyDescriptor(Mouse,"name");
console.dir(a);

结果如下:

当然,还可以一次性设置多个属性,用Object.definePropertys(),具体用法google吧。顺便说一下,貌似对象(实例)的方法应该也是可以通过定义和赋值进行制造的!

原文地址:https://www.cnblogs.com/jingubang/p/4633326.html