JS对象

214 阅读6分钟

前言

Javascript的简单数据类型包括数字、字符串、布尔值、null值和undefined值。其他的所有值均为对象。其中数组、函数、正则表达式以及对象都为对象。我们可以把对象看作是一个盒子,盒子里装了许许多多的物品,有玩具、家具、电脑等,而玩具是遥控赛车,家具是电视机,电脑是联想的。这里的玩具(遥控汽车)、家具(电视机)、电脑(联想的笔记本电脑)就相当于对象的属性及属性的名字和值。检测一个数据类型时,我们可以用typeof方法和instanceof来检测一个数据类型是不是对象和是对象中的哪种类型(当用typeof检测null时,结果会显示object,但是null并不是一个对象)。

对象字面量

对象字面量就是一种简单易懂地创建对象的表示法。属性名可以是空字符串在内的任意字符串,如果你的属性名是一个合法的Javascript标识符且不是保留字。则并不强制要求用引号括住属性名。且属性的值中还可以包括另一个对象字面量在内的任意表达式。"first-name" : "Thomas"被称为名/值对,也可以叫做键/值对,对象中每个键/值对都要用','隔开如:

     var empty_object = {};
     var information = {
         "first-name" : "Thomas",
         last_name : "King",
         birthday : {
             year : "1997",
             mounth : "4",
             day : "11"
         }
     };

为什么说对象字面量赋值比new Object()高效?

     var obj = {};              
     var obj = new Object;

在chrome浏览器上我们实验前者比后者得到结果的时间少了好几倍,这说明new Object()相对于对象字面量方法更加的笨重。 所以为什么会这样呢?因为{}是字面量,可以立即求值,而newObject()本质上是方法(只不过这个方法是内置的)调用,既然是方法调用,就涉及到在proto链中遍历该方法,当找到该方法后,又会生产方法调用必须的堆栈信息,方法调用结束后,还要释放该堆栈。

检索

当我们检索一个对象中所包含的值时,我们可以用[]后缀括住我们想要检索的字符串表达式。如果字符串表达式是一个字符串字面量,并且它是一个合法的JavaScript且不是保留字时,我们可以用.来代替。我们可以优先考虑使用.表示法,因为它更紧凑且可读性更好。

     information["first-name"]     //"Thomas"
     information.last_name         //"King"

当你检索一个对象中不存在的成员属性值时,将会返回undefined。

     information["middle-name"]    //undefined
     information.birthday.data     //undefined

|| 运算符可以用来填充默认值:

     var middle = information["middle-name"] || "(none)";
     var sex = information.sex || "unknown";

当我们在一个不存在的对象成员属性中取值时,会返回TypeError异常错误。这时我们可以用&&来避免错误。

     information.sex                         //undefined
     information.sex.man                     //抛出TypeError错误
     information.sex && information.sex.man  //undefined

更新

对象中的值可以通过赋值语句来更新。如果属性名已经存在与对象中,那么之前的值会被替换掉。你创建了一个对象后,你可以用点操作符或中括号操作符来更新对象的属性。

     information['first-name'] = 'Tony';

如果对象之前没有那个属性名,那么该属性就被扩充到对象中。

     information.nickname = 'Dragon';
     information[middle-name] = 'Lester';

引用

对象可以通过引用来传递,但是它们永远不会被复制。比如我可以叫张三也可以叫李四,通过这两个名字都可以找到我,即张三和李四都指向一个对象就是我。当叫张三的我发烧了发生改变时,叫李四的我也会发烧,因为张三和李四指向的都是我这个对象。

     var x = information;
     x.nickname = 'Dragon';
     var nick = information.nickname;
              //因为x和information是指向同一个对象的引用,所以nick为'Dragon'。
     var a = {},b = {},c = {};
              //a、b和c每个都引用一个不同的空对象。
     a = b = c;
              //a、b和c都引用同一个空对象。

在引用时,可能出现的一些问题。在基本类型之间赋值传值的时候,就是一方单纯的把值传给了另一方。而在引用类型之间传递的是地址,所以可能会造成一些问题出现。如下:

     var a = [1,1,2]
     var b = [1,2,3]
     consolo.log(a == b)   //false
     var c = a
     consolo.log(a == c)   //true
     
     c.push(4)
     consolo.log(a)        //[1,2,3,4]

这里就是因为引用类型在赋值的过程中,传递的是内存地址,而a和c指向的都是同一个地址,所以地址内的值发生变化的时候,a和c都会发生改变。

原型

原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承。js中所有的引用类型都有一个_proto_属性,只有构造函数(即你在script标签里声明的那个函数)中才有prototype属性。当你试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的_proto_(即它的构造函数的prototype)中寻找。

     var obj ={}                //等价于var obj = new Object()
     console.log(obj._proto_ === Object.prototype)
     var add = new Function('num1','num2','return num1 + num2;')    //构造函数

反射

反射指的是在程序运行时,能够知道自身的各种信息。例如一个对象在运行时知道自己有哪些属性和方法。

     typeof information["first-name"]       //'syring'
     typeof information["last-name"]         //'undefined'

枚举

在目前JavaScript中并没有枚举的概念,因为js是弱类型语言并没有严格的数据类型限定。但是我们可以通过json来实现它,json可以使用任何类型的值。

     var information = {
         name : "Thomas",
         birthday : {
             year : 1997,
             month : 4 ,
             day : 11
         }
     };
     var myval = information.name ;
     if(information.name == "Thomas"){
         console.log("My name is THomas");
     }else{
         cosole.log("My name is not Thomas");sd
     }

删除

delete运算符可以删除对象的独有属性,而不会删除对象原型链中的任何属性。不过当删除了对象的独有属性后,原型链中的属性可能会显露出来。

     var another_information = Object.create(information);
     another_information.name = 'Cindy' ;
     delete another_information.name;        //"Thomas"

减少全局变量污染

javaScript 可以随意定义保存所有应用资源的全局变量。但全局变量可以削弱程序灵活性,增大了模块之间的耦合性。在多人协作时,如果定义过多的全局变量有可能造成全局变量冲突,也就是全局变量污染问题。以下列出两种减少全局变量污染。

一、定义全局命名空间

     var My_information = {};
     My_information.information = {
         "first-name" : "Thomas",
         last_name : "King",
     }
     My_information.another_information = {
         name : "Cindy"
     }

二、使用自执行函数

     (function() { // ... })()
     (function(){
         var tmp= {};
         var name = 'jack';
         tmp.method = function(){
         return name;
         }
         window.tmp= tmp;
     })()
     console.log(tmp.method());

扩展:自执行函数言简意赅就是不用调用,当被定义出来的时候就能执行。形式如:(function(形参) { // ... })(实参)。并且除了自执行函数自身,其他地方都不能调用它。

     function aaa(a1,b1){
     return sum1 = a1 + b1
     },
     (function bbb(a2,b2){
         return sum2 = a2 + b2
     ;}(),
     console.log(aaa(1,1));            //输出"2"
     console.log(bbb(1,1));            //报错