JS语言精粹--对象

这篇文章算是我职业生涯中的第一篇技术博文吧,有些地方可能表达得不是很好,还望你们多多包涵哈^_^!javascript

正文

JavaScript的简单类型有数字、字符串、布尔值(true、false)、null值和underfind值,其余全部的值都是对象。java

数字、字符串和布尔值“貌似”是对象,由于它们都拥有方法,可是它们是不可变的。而JavaScript中的对象是可控的键控集合正则表达式

在JavaScript中,数组是对象,函数是对象,正则表达式是对象,固然,对象天然也是对象。数组

对象是属性的容器,其中每一个属性都拥有名字和值(name-value)。属性名能够是包括字符串在内的任意字符串,属性值能够是除undefined值以外的任意值。闭包

JavaScript中的对象是无类别(class-free)的,它对新属性的名字和值没有约束。对象适合用于收集和管理数据。对象能够包含其余对象,因此它们能够容易的表示成树形或图形结构。函数

JavaScript包括一个原型链特性(这是JS对象中很重要的一个特性,具体用法之后我会发一篇针对原型链及其用法的文章进行专门说明),容许对象继承另外一个对象的属性,正确地使用它能减小对象初始化的时间和内存耗损。ui

1. 对象字面量

对象字面量,提供了一种很是方便的建立新对象值得表示法,即包围在一对花括号中的零个或多个“名/值”对(也称为键值对),它能够出如今任何容许表达式出现的地方。prototype

javascriptvar empty_object = {};
var batman = {
    'first-name': 'Bruce',
    'last-name': 'Wayne'
};

属性名能够是包括空字符串在内的任何字符串,不过,一个合法的变量标识符,不能是保留字,虽然不强调用引号括住,可是,像“first-name”、“first name”这类含有“-”或是空格的属性名,是必须加上引号括住的。逗号用来分隔多个“名/值”对。code

属性值能够从包括另外一个对象字面量在内的任意表达式中得到,而对象是可嵌套的。对象

javascriptvar flight = {
    airline: 'Domestic',
    number: 1024,
    departure: {
        IATA: 'SZ',
        time: '2015-08-03 15:00:00',
        city: 'shenzhen'
    },
    arrival: {
        IATA: 'BJ',
        time: '2015-08-04 00:00:00',
        city: 'beijing'
    }
};

2. 检索

要检索对象中包含的值(或属性值或方法或其它),能够采用在 [] 后缀中括住一个字符串表达式的方式,若是字符串表达式是一个合法js标识符且不为保留字的常数,那么优先考虑用 . 表示法,由于它更紧凑且可读性更好。

javascriptbatman['first-name']    // "Bruce"
flight.departure.city   // "shenzhen"

若是你尝试检索一个并不存在的成员元素的值(这里的属性表达式是严格区分大小写的),将返回一个undefined值。

javascriptbatman['middle-name']   // undefined
flight.status           // undefined
batman['FIRST-NAME']    // undefined

|| 运算符能够用来填充默认值:

javascriptvar middle = batman['middle-name'] || '(none)';
var status = flight.status || 'unknown';

尝试检索一个undefined值将会致使TypeError异常,这能够经过 && 运算符来避免错误。

javascriptflight.equipment                             // undefined
flight.equipment.model                       // throw "TypeError"
flight.equipment && flight.equipment.model   // undefined

3. 更新

对象中的值能够经过赋值语句来更新。

若是属性名已经存在于对象中,那么这个属性值将被替换。

javascriptbatman['first-name'] = 'Damian';

若是对象以前并无这个属性名,那么该属性将会被扩充到该对象中。

javascriptbatman['middle-name'] = 'AI';
batman['nickname'] = 'Robin';
flight.equipment = {
    model: 'Boeing 777'
};
flight.status = 'overdue';

4. 引用

对象经过引用来传递,它们永远不会被拷贝。

javascriptvar x = batman;
x.nickname = 'Joker';
var nick = batman.nickname;  // 由于x和batman是指向同一个对象的引用,因此nick为"Joker"
var a = {},b = {},c = {};    // a、b、c 每一个都分别引用一个不一样的空对象
a = b = c = {};              // a、b、c 都引用一个相同的空对象

5. 原型

每一个对象都会链接到一个原型对象,而且它能够从中继承属性。全部经过字面量建立的对象,都链接到 Object.prototype 这个JS中的标准的对象。

当建立一个新对象时,能够选择某个对象做为它的原型,给Object增长一个beget方法,这个beget方法建立一个使用原对象做为其原型的新对象,这个咱们之后会在专门的博文作详细了解。

javascriptif(typeof Object.beget !== 'function'){
    Object.beget = function(o){
        var F = function(){};
        F.prototype = o;
        return new F();
    };
};

var next_batman = Object.beget(batman);

原型链接在更新时是不起做用的,当咱们对某个对象作出改变时,不会触及到该对象的原型:

javascriptnext_batman['first-name'] = 'Damian55';
next_batman['middle-name'] = 'Ai22';
next_batman.nickname = 'Robin5';

原型链接只有在检索值的时候才会被用到。若是咱们尝试去获取对象的某个属性值,且该对象没有该属性名,那么,JS会试着从原型对象中获取属性值,若是那个原型对象也没有该属性,则再从它的原型中寻找,以此类推,直到最后到达终点Object.prototype,若想要的属性彻底不存在于原型链中,则返回undefined值,这个过程称为委托

原型关系是一种动态的关系,若是咱们在原型中添加一个新的属性,该属性会当即对全部基于该原型建立的对象可见。

javascriptbatman.profession = 'JSL';
next_batman.profession;      // 'JSL'

6. 反射

检查对象并确认对象有什么属性,能够去检索该属性并验证取得的值。而肯定属性的类型,可使用typeof操做符。

javascripttypeof flight.number        // 'number'
typeof flight.status        // 'string'
typeof flight.arrival       // 'object'
typeof flight.manifast      // 'undefined'

请务必注意原型链中的任何属性也会产生一个值:

javascripttypeof flight.toString      // 'function'
typeof flight.constructor   // 'function'

有两种方法去处理这些不须要的属性:

  • 让你的程序检查并剔除函数值,通常来讲,作反射的目标是数据,所以其中一些值可能会是函数。
  • 使用hasOwnProperty方法,若是对象拥有独立属性,它将返回true。

另外,hasOwnProperty方法不会检查原型链。

javascriptflight.hasOwnProperty('number');        // true
flight.hasOwnProperty('constructor');   // false

7. 枚举

for in 语句可用来遍历一个对象中的全部属性名,固然,也包括函数和咱们可能不关心的原型中的属性,因此咱们有必要过滤掉没必要要的值。
最经常使用的过滤器(即过滤原型中的属性)是hasOwnProperty方法,以及使用typeof来排除函数:

javascriptvar name;
for(name in next_batman){
    if(typeof next_batman[name] !== 'function'){
        document.writeln(name + ': ' + next_batman[name]);
    }
}

以上,属性名出现的顺序是不肯定的,所以要想确保属性以特定的顺序出现,最好是彻底避免使用 for in 语句,而是建立一个数组,在其中以正确的顺序包含属性名:

javascriptvar i;
var properties = ['first-name','middle-name','last-name','profession'];
for(i = 0;i < properties.length;i ++){
    document.writeln(properties[i] + ': ' + next_batman[properties[i]]);
}

经过使用普通for而不是for in ,能够获得咱们想要的属性,而不用担忧可能发掘出原型链中的属性,并按正确的顺序取得它们的值。

8. 删除

delete运算符能够用来删除对象的属性,它将会移除该对象的肯定包含的属性,它不会触及原型链中的任何对象。

删除对象的属性可能会让来自原型链中的属性浮现出来。

javascriptnext_batman.nickname        // 'Robin5'
// 删除next_batman的nickname属性,从而暴露出原型的nickname的属性值
delete next_batman.nickname; 
next_batman.nickname;       // 'Robin'

9. 减小全局变量污染

JS能够随意定义可保存全部应用资源的全局变量,不幸的是,全局变量会削弱程序的灵活性,因此应该避免。

最小化使用全局变量的一个方法是在你的应用中只建立惟一一个全局变量:

javascriptvar MyApp = {};

该变量此时变成了你的应用容器:

javascriptMyApp.batman = {
    'first-name': 'Bruce',
    'last-name': 'Wayne'
};

MyApp.flight = {
    airline: 'Domestic',
    number: 1024,
    departure: {
        IATA: 'SZ',
        time: '2015-08-03 15:00:00',
        city: 'shenzhen'
    },
    arrival: {
        IATA: 'BJ',
        time: '2015-08-04 00:00:00',
        city: 'beijing'
    }
};

只要把多个全局变量都整理在同一个命名空间下,你将显著下降与其余应用程序、组件或类库之间产生糟糕的相互影响(即耦合度高)的可能性,也使其变得更容易阅读,由于MyApp.batman指向的时顶层结构。固然,也可使用闭包来进行信息隐藏,它是另外一种有效减小全局污染的方法。

相关文章
相关标签/搜索