资讯专栏INFORMATION COLUMN

JavaScript面向对象的程序设计——“对象的基本概念”的注意要点

HmyBmny / 1065人阅读

摘要:描述符对象就是上面提到的个描述其行为的特性和。真是奇怪读取属性的特征使用的方法,可以取得给定属性的描述符。接收两个参数所在的对象和要读取其描述符的属性名称。

对象的基本概念

面向对象(Object-Oriented,OO),的语言最大的特征就是它们都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。

创建自定义对象最简单的方式就是创建一个Object 的实例,然后再给他添加属性和方法。如:

var math = new Object();
math.π = function pi(){
    return Math.PI;
};

document.write(math.π());

这里借用了Math.PI,最后的结果是无论调用的是math.π还是Math.PI都会返回圆周率的值。其中,前者就是我们自己自定义的对象。又如:

var person = new Object();
person.name = "Oliver";
person.age = 18;
person.job = "Software Engineer";
person.sayName = function(){
    alert(this.name);
};

上面这个对象可以用下面的结构化图像解释清楚:

Object => person
                |-name                    
                |-age
                |-job
                |-sayName()
                            |-this.name

这里面person 是对象,又是Object 的实例,其中他有三个属性和一个方法,这个方法用于显示this.name,会被解析为person.name。

上面的例子又可以用字面量的语法写成这样:

var person = {
    name: "Oliver",
    age: 18,
    job: "Software Engineer",
    sayName: function(){
        alert(this.name);
    }
};
属性类型

根据ECMA-262 第五版,ECMAScript 中有两种属性(内部值):数据属性和访问器属性。为了表示特性的内部值,该规范把它们放在了两对方括号中,如[[Enumerable]]。

数据属性

数据属性有4 个描述其行为的特性:

[[Configurable]]:表示能否通过delete 删除属性;

[[Enumerable]]:表示能否通过for-in 循环返回属性;

[[Writable]]:表示能否修改属性的值;

[[Valu]]:包含这个属性的数据值;

其中,前三个默认都是true,最后一个默认为undefined。

如何修改数据属性默认的特性呢?这就要用到ECMAScript 5 的Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象,属性的名字和一个描述符对象。描述符对象就是上面提到的4 个描述其行为的特性:configurable、enumerable、writable 和value。

修改方式如下:

var person = {};
Object.defineProperty(person, "name", {
    writable: false,
    value: "Oliver"
});

console.log(person.name); //Oliver
person.name = "Niko";
console.log(person.name); //Niko

又如:

var person = {
    name: "Troy",
    age: 18
};
Object.defineProperty(person, "name", {
    writable: false,
    value: "Oliver",
    enumerable: false
});

for (x in person){
    console.log(x); //age
}

如:

var person = {
    name: "Troy",
    age: 18
};
Object.defineProperty(person, "name", {
    value: "Oliver",
    configurable: false
});

delete person.name;
console.log(person.name) //Oliver

要注意的是,一旦把属性定义为不可配置的,就不能再把它变回可配置的了。

不要在IE8 中使用Object.defineProperty()方法。

访问器属性

该属性不包含数据值,只有一对getter 和setter 函数(两者为可选);4个 特性如下:

[[Configurable]]

[[Enumerable]]

[[Get]]:在读取属性时调用的函数;默认undefined;

[[Set]]:在写入属性时调用的函数;默认undefined;

同样,必须使用Object.defindProperty()来定义。如:

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 = 2006;
console.log(book.edition);

两个默认的属性:_year 和edition。year 前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。

对于上面的下划线不太明白的,可以参考下面一种写法:

var book = {
    year: 2004,
    edition: 1
};

Object.defineProperty(book, "setYear", {
    get: function(){
        return this.year;
    },
    set: function(newValue){
        if(newValue > 2004){
            this.year = newValue;
            this.edition += newValue - 2004;
        }
    }
});

book.setYear = 2007;
console.log(book.edition);
console.log(book.year)

两者功能相同,实际上该方法是给book 对象又设置了另一个属性即第一段代码中的_year 和第二段代码中的setYear。

另外,一般在这个方法之前,要创建访问器属性,一般都是使用两个非标准的方法:__defineGetter__()__defineSetter__()。如:

var book = {
    name: "hello"
};
book.__defineGetter__("name",function(){
    return "world";
});

document.write(book.name);
定义多个属性

ECMAScript 5 又定义了一个Object.defineProperties()方法。利用这个方法可以通过描述符一次定义多个属性。如:

var book = {};
Object.defineProperties(book, {
    _year:{
        value: 2004,
        writable: true
    },
    edition:{
        value: 1,
        writable: true
    },
    year:{
        get: function(){
            return this._year;
        },
        set: function(newValue){
            if(newValue > 2004){
                this._year = newValue;    
                this.edition += newValue - 2004;
            }
        }
    }
});
book.year = 2006;
console.log(book.year + " " + book.edition);

还真是奇葩,不知是否浏览器的问题,数据属性还是要加上为true 的writable 访问器属性才能起作用。不是默认为true 么。真是奇怪

读取属性的特征

使用ECMAScript 5 的Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。接收两个参数:所在的对象和要读取其描述符的属性名称。如:

var cars = {};
Object.defineProperties(cars, {
    name: {
        value: "Benz",
        writable: false
    },
    _color: {
        value: "White",
        writable: true
    },
    price: {
        value: 300000,
        writable: true
    },
    color: {
        get: function(){
            return this._color;
        },
        set: function(newValue){
            if(newValue == "Black"){
                this._color = "Black";
                this.price = 280000
            }else if(newValue == "White"){
                this._color = "White";
                this.price = 300000
            }
        }
    }
});
function selectColors(colorValue){
    cars.color = colorValue;
    document.write(cars.name + ": " + cars.color + "款 " + "(" + cars.price + "元人民币" + ")");
}
selectColors("Black"); //Benz: Black款 (280000元人民币)
selectColors("White"); //Benz: White款 (300000元人民币)

var descriptor = Object.getOwnPropertyDescriptor(cars, "name");
document.write(descriptor.value + descriptor.writable + descriptor.configurable + descriptor.enumerable); //Benzfalsefalsefalse

var descriptor2 = Object.getOwnPropertyDescriptor(cars, "color");
document.write(descriptor2.get + descriptor2.set + descriptor2.configurable + descriptor2.enumerable + descriptor2.value); //function () { return this._color; }function (newValue) { if(newValue == "Black"){ this._color = "Black"; this.price = 280000 }else if(newValue == "White"){ this._color = "White"; this.price = 300000 } }falsefalseundefined

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86238.html

相关文章

  • JavaScript面向对象程序设计——“对象继承”注意要点

    摘要:如继承了这里就不必写该方法的主要优势就是可以在子类型构造函数中向超类型构造函数传递参数。以上原型式继承通常只是想让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以胜任的。 继承 继承分为接口继承和实现继承;接口继承只继承方法签名,实现继承则继承实际的方法;由于函数没有签名,所以ECMAScript 中没有接口继承,只能依靠原型链来实现实现继承。 原型链 基本思想是利用原型链让...

    zhongmeizhi 评论0 收藏0
  • 浅谈JavaScript面向对象

    摘要:不必在构造函数中定义对象实例的信息。其次,按照一切事物皆对象的这饿极本的面向对象的法则来说,类本身并不是一个对象,然而原型方式的构造函数和原型本身也是个对象。第二个问题就是在创建子类型的实例时,不能向超类型的构造函数中传递参数。 前言 对象(Object)应该算是js中最为重要的部分,也是js中非常难懂晦涩的一部分。更是面试以及框架设计中各出没。写这篇文章,主要参考与JavaScrip...

    cyixlq 评论0 收藏0
  • 【连载】前端个人文章整理-从基础到入门

    摘要:个人前端文章整理从最开始萌生写文章的想法,到着手开始写,再到现在已经一年的时间了,由于工作比较忙,更新缓慢,后面还是会继更新,现将已经写好的文章整理一个目录,方便更多的小伙伴去学习。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 个人前端文章整理 从最开始萌生写文章的想法,到着手...

    madthumb 评论0 收藏0
  • JavaScript面向对象程序设计——“创建对象注意要点

    摘要:所以,可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。如对于构造函数原型属性以及实例之间的关系,参见高级程序设计一书中第章节。稳妥构造函数模式稳妥对象,指的是没有公共属性,且其方法也不引用的对象如 创建对象 Object 构造函数或对象字面量都可以用来创建单个对象。但这个方法的缺点非常明显:同一个接口创建很可耐多对象会产生大量的重复代码。为了解决这个问题,人们开始使用工厂...

    tracymac7 评论0 收藏0

发表评论

0条评论

HmyBmny

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<