对象是一种复合型的值,也可以说是属性的无序集合。javascript对象还可以从一个称为原型(prototype)的对象继承属性。对象的方法通常是继承的属性。
js的对象是动态的,对象的常见方法有创建(create),设置(set),查找(query),删除(delete),检测(test),枚举(enumerate)。
在ECMAscript5中可以对属性的可枚举(for/in遍历),可配置(删除属性等),可写(设置属性值)加以配置。
对象除了属性,还有三个对象特性:
对象的原型 指向另一个对象,本对象的属性继承自他的原型对象
对象的类 是一个标识对象类型的字符串
对象的扩展标记 指明了是否能向该对象添加属性
1.创建对象
1.1对象直接量
var empty={};
var point ={x:1,y:2};
var book ={
author:{
name:“李磊”
}
"main title":“lilei”
}
1.2 通过new创建对象
var o =new object()
1.3 原型
每一个javascript对象都和另外一个对象关联(除了null)。“另一个”对象就是我们熟知的原型,每一个对象都从原型继承属性。
原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))。看下面的例子:
function f1(){};
console.log(f1.prototype) //f1{}
console.log(typeof f1. prototype) //Object
console.log(typeof Function.prototype) // Function,这个特殊
console.log(typeof Object.prototype) // Object
console.log(typeof Function.prototype.prototype) //undefined
从这句console.log(f1.prototype) //f1 {} 的输出就结果可以看出,f1.prototype就是f1的一个实例对象。就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype,基本过程如下:
var temp = new f1(); f1. prototype = temp;
所以,Function.prototype为什么是函数对象就迎刃而解了,上文提到凡是new Function ()产生的对象都是函数对象,所以temp1是函数对象。
var temp1 = new Function ();
Function.prototype = temp1;
看了这么多,原型函数到底有啥用,其实很简单,给person.prototype设置了属性或者方法,比如person.prototype.name=lilei,那么在之后的使用过程中,person继承person.prototype的属性,person自带name=lilei的属性。
1.4 Object.create()
创建新对象,第一个参数是这个对象的原型,第二个参数是可选项,用以对象属性进一步描述
Object.create( x:1);
也可以传入null来创建一个没有原型的对象,但不继承任何东西。
Object.create(null)
创建一个普通的空对象
Object.create(Object.prototype)
2 属性的查询和设置
var author = book.author;//查询book的author属性
var author =book["main title'];//查询book的main title属性
book.author=lilei;//设置book的author是lilei
book["main title']=lilei;//设置book的main title是lilei
2.1作为关联数组的对象
book["main title']=lilei;
main title是字符串,所以可以在程序运行时对属性进行删除或者修改
function addstock(portfolio ,stockname, share){
portfolio[stockname]=share;
}
用户在程序运行时输入stockname,因此在这之前不知道stockname是什么。由于写程序时不知道属性是什么所以不能采取“.”的方式访问portfolio属性,但可以使用[],因为使用的字符串,字符串是动态的,可以删除修改操作。
2.2继承
原型继承
我觉得要正真理解原型链就需要先理解原型继承的原理,理解了如何继承,基本上你就对原型链掌握很深了。我们来实现一个简单的原型继承,我通过阮老师的文章中写的直接继承prototype来实现继承,修改上面的代码:
var Cat = function(){
this.Color = "black";
this.Eat = function(){
alert("吃老鼠");
};
}
Cat.prototype.A = function(){
alert("Cat A");
};
Cat.prototype.B = function(){
alert("Cat B");
};
var Dog = function(){
this.Weight = "30";
}
Dog.prototype = Cat.prototype;
console.log(Dog.prototype.constructor == Cat); // true
var dog1 = new Dog();
dog1.A(); // Cat A
dog1.B(); // Cat B
上面的代码,我设置了一个Dog来继承Cat,我们使用prototype来实现继承,实际继承成功了,Dog的实例dog1调用了Cat里面的prototype的A和B方法。但是这里出了一个小问题,通过prototype继承导致了Dog的构造函数发生了改变,导致它指向了Cat,这就是我们代码中console输出的原因。我们上面说过每个原型都有一个自己的独立的构造函数,我们却改变了它,这样会导致原型混乱,所以我们必须把Dog的构造函数指回Dog本身。所以修改下代码:
var Cat = function(){
this.Color = "black";
this.Eat = function(){
alert("吃老鼠");
};
}
Cat.prototype.A = function(){
alert("Cat A");
};
Cat.prototype.B = function(){
alert("Cat B");
};
var Dog = function(){
this.Weight = "30";
}
Dog.prototype = Cat.prototype;
Dog.prototype.constructor = Dog;
console.log(Dog.prototype.constructor == Cat); // false
console.log(Cat.prototype.constructor == Dog); // true
var dog1 = new Dog();
dog1.A(); // Cat A
dog1.B(); // Cat B
上面我通过Dog.prototype.constructor = Dog;这句话把Dog构造函数指回自己了,但是坑爹的是这样做之后,原先的Cat的构造函数也被改变成了Dog,唉,这是要闹哪样,完全坑爹,所以这种继承方式也是失败的,但是我们已经接近成功了,阮老师后面提出了利用空对象作为中介来继承。好的的直接上代码:
var Cat = function(){
this.Color = "black";
this.Eat = function(){
alert("吃老鼠");
};
}
Cat.prototype.A = function(){
alert("Cat A");
};
Cat.prototype.B = function(){
alert("Cat B");
};
var Dog = function(){
this.Weight = "30";
}
var Fn = function(){};
Fn.prototype = Cat.prototype;
Dog.prototype = new Fn();
Dog.prototype.constructor = Dog;
console.log(Dog.prototype.constructor == Dog); // true
console.log(Cat.prototype.constructor == Cat); // true
var dog1 = new Dog();
dog1.A(); // Cat A
dog1.B(); // Cat B
这下实现完美的继承了,上面是我根据阮老师的提供的方式实现的一个继承,Dog不止继承了Cat里面的prototype的方法,而且构造函数还是指回自己,Cat的构造函数也没被篡改。貌似非常完美的继承。
3.删除属性
delete可以删除对象的属性
delete book.author //book不再有属性author
4.检测属性
in运算符,可以区分不存在的属性和存在但值为undefined的属性
var o={x:1}
"x" in o ;// true
''y'' in o;//false
对象的hasOwnProperty()方法用来检测给定的名字是否是对象的自有属性,对于继承性属性,他将返回false
var o={x:1};
o.hasOwnProperty("x");//true
hasOwnProperty(''y''); //false
hasOwnProperty(''toString''); //false:to string是继承的属性
propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性的可枚举性为true时才返回true.
var o =inherit({ y:2});
o.x=1;
o.propertyIsEnumerable("x");//true:o 有一个可枚举的自有属性x
o.propertyIsEnumerable("y");//false :y是继承而来的
Object.prototype.propertyIsEnumerable("toString"); //false 不可枚举
“!==”来判断属性是否是undefined
var o={x:1}
"x" !==undefined ;// true o 中有x属性
''y''!== undefined//false o 中没有y属性
5.枚举属性
for/in可以枚举对象的属性,但是Object.prototype的属性有时候并不想被遍历,而在ECMAScript5中是会被枚举的,所以可以用下面的方法
for (p in o){
if (!o.hasOwnProperty(p)) continue; //跳过属性
}
for (p in o){
if (type of o[p]=== "function") continue; //跳过方法
}
6.属性getter和setter
属性由名字 值和一组特性(attribute)构成,属性也可以由一个或两个方法代替。(getter 和setter),由这两个方法定义的属性称作“存取器属性”。
var obj = {
val:100,
get getval(){
return this.val;
},
set setval(x){
this.val = x;
}
}
console.log(obj.getval); //100
obj.setval = 101;
console.log(obj.getval); //101
//demo2
var obj2 = {
val:200
}
obj2.__defineGetter__('name',function(){return this.val});
obj2.__defineSetter__('name',function(name){this.val = name;})
console.log(obj2.name) //200
obj2.name = 201;
console.log(obj2.name); //201
7.属性的特性
数据属性的特性:值(value),可写性(writable),可枚举性(enumerable),可配置性(configurable)
存取器属性的特性:读取(get),写入(set),可枚举,可配置
8.对象的三个属性:
原型的属性:用以继承属性。详细上文有讲解
类属性:对象的类型信息
可扩展性:是否可以增加属性
9.序列化对象
对象序列化是指将对象的状态转换为字符串,也可以将字符串还原为对象
o ={x:1,y:{z:[false,null,""]}}
s =JSON.stringify(o);//s是'{“x”:1,"y” :{"z":[false,null,""]}}'
p=JSONparse(s); //p是o的深拷贝
10.对象方法
Object.toString()
toString()
toLocaleString()
toJSON()
valueOf()