前言
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)); //报错