JavaScript
有数组,但是没有字典这种结构,对象从形式上看就是一种字典结构。并且对象的key统一为String
类型,(用其他类型也不会出错,只是内部会调用toString
接口自动转),value
可以是简单的值,对象,函数,数组等。
可以简单理解为对象就是字典的键值对,跟JSON
互转非常方便。个人非常认同这种简单的处理方式。
当然,有map
这种类似字典的结构,至少名字不叫字典,并且目前更愿意用数组的map()
方法。
一切都是对象,比如数组、函数本身都是对象。数字,布尔量等等也都是对象。
对象创建
JavaScript
没有类的概念,而是采用原型链的方式来定义类。平时使用的时候直接调用构造函数创建类。并且也没有析构函数的概念。delete
也只是删除对象的属性,而不是回收对象。对象的回收由GC
统一负责,不需要操心
使用对象
Javascript 创建对象方法的总结
JavaScript prototype
JavaScript 对象
直接{}
初始化
大多数时候,对象就是一些键值对的组合,比如MVC
设计模式中的M
,只有属性,没有方法,并且字段名都确定。那么最简单的方式就是直接定义变量,给初始化值。对象定义和初始化一并完成了。对象{}
可以嵌套,跟JSON
很相似:
var myCar = {
color: "red",
wheels: 4,
engine: {
cylinders: 4,
size: 2.2
}
};
console.dir(myCar);
构造函数
如果Model在好几个地方用,那么直接初始化的方法就不大合适,一不小心属性名字就写的不一样了。可以定义一个构造函数,然后用的地方调用这个构造函数创建对象,可以保证大家的属性名字是一样的,只是对象的名字和属性值不一样。
这里包括定义构造函数和定义变量并初始化两个步骤
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
var myCar = new Car("Eagle", "Talon TSi", 1993);
console.dir(myCar);
动态添加属性
一开始只知道要用一个对象,但是字段一个都不知道。等到用的时候才知道字段的名字和值。这种场景,可以通过直接添加属性的方式创建对象。这种形式使用起来最方便。
person = {}; // person = new Object();
person.firstname="John";
person.lastname="Doe";
person.age=50;
person.eyecolor="blue";
console.dir(person);
添加方法
- 属性的
key
是String
,值是对象(数字也是对象);函数的key
也是String
,值是函数,也是对象;所以函数成员和普通的数据成员没有本质区别。 - 不过从面向对象设计的概念来说,数据是私有的,每个对象一份
copy
,大家互不影响,是合理的。而函数只是定义了做事的方法,并没有实际工作,不需要每个对象持有一份copy
,只要大家共享一份就可以了。这样省内存啊。 - 除了函数以外,有些数据成员也希望多个对象共享一份数据。行为相当于静态变量。
希望共享的成员,(函数或者数据都一样),就添加到对象的prototype
function Person(name,age,job) {
this.name=name;
this.age=age;
this.job=job;
}
Person.prototype = {
friends:["Jams","Martin"],
sayFriends:function() {
alert(this.friends);
}
};
var person1 = new Person("kevin",31,"SE");
var person2 = new Person("Tom",30,"SE");
person1.friends.push("Joe");
person1.sayFriends(); // Jams,Martin,Joe
person2.sayFriends(); // 也是Jams,Martin,Joe;因为属性friends在prototype定义,所有Person对象共享
console.dir(person1);
console.dir(person2);
如果要把
prototype
部分的定义放到构造函数中,要注意保护只做一次。因为构造函数会被多次调用,但是定义prototype
只要1次就可以了。推荐还是这种将prototype
拿到构造函数外面定义的方式。
访问对象
- 访问属性一般用点语法:
objectName.propertyName
- 访问方法一般用点语法:
objectName.methodName()
- 访问属性也可以用
[]
。一个属性的名称如果不是一个有效的JavaScript
标识符(例如,一个由空格或连字符,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。例如:
// 同时创建四个变量,用逗号分隔
var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object();
myObj.type = "Dot syntax";
myObj["date created"] = "String with space";
myObj[str] = "String value";
myObj[rand] = "Random Number";
myObj[obj] = "Object";
myObj[""] = "Even an empty string";
console.dir(myObj);
原型对象(prototypical object)
-
JavaScript
是基于原型的语言:只有对象,没有类。 - 原型对象可以作为一个模板,新对象可以从中获得原始的属性。只是简单的
copy
,没有继承的功能。通过“原型链”,可以实现类似继承的效果。 - 通过原型继承来的属性是所有对象共享的,这点要注意。对象特有的变量要用
this
关键字写在构造函数中 - 特殊的
__proto__
属性是在构建对象时设置的;设置为构造器的prototype
属性的值。
所以表达式var a = new Foo()
将创建一个对象a
,其中a.__proto__ == Foo.prototype
。 - 对象先找本地自己的构造函数中用
this
表示的变量,找到了就返回了,不去管原型链中是否有相同名字的属性。效果相当于子类覆盖父类的属性 - 当查找一个对象的属性时,
JavaScript
会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部 – 也就是Object.prototype
– 但是仍然没有找到指定的属性,就会返回undefined
-
hasOwnProperty
是Object.prototype
的一个方法,它可是个好东西,他能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnProperty
是JavaScript
中唯一一个处理属性但是不查找原型链的函数。
// 修改 Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // 输出两个属性:bar 和 moo
}
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i); // 只输出 moo
}
}
参考文章
javaScript原型链理解
这个文章讲得比较清楚,特别是那张图要好好理解。