##对象
这是系列关于js语言核心思想的一些理解,包括对象、继承、原型链、构造函数、执行上下文堆栈、执行上下文、变量对象、活动对象、作用域链、闭包以及this。
本文参考自《JavaScript权威指南》、《JavaScript语言精粹》以及前端早读君的文章《javaScript核心》。
在JavaScript中,对象是指可变的键控集合。属性名为字符串,值可以为任何类型的javascript值,每个属性都是一个名/值对。除了可以拥有属性外,对象还可以从一个称为原型的对象中继承属性。这就是JavaScript中的 “原型式继承”。
在ES5中,属性还包括了一些标识可写、可枚举和可配置的特性。可以通过这些API给原型对象添加方法,并设置成不可枚举,让它们更像内置方法,也可以给对象定义不能修改或删除的属性,“锁定”该对象。 获取和定义可使用 **getOwnPropertyDescriptor 和 defineProperty ** 方法:
var o = {};
Object.defineProperty(o,"x",{
value:2,
writable:true, // 可写性;
enumerable:false, // 可枚举性;
configurable:true // 可配置性;
});
console.log(Object.getOwnPropertyDescriptor(o,"x"));
console.log(o.x);
- 可写,表明是否可以设置改属性的值;
- 可枚举,表明是否可以通过for/in循环返回;
- 可配置,表明是否可以删除或修改该属性;
- 对象的原型属性(prototype)通过隐含的
__proto__
属性指向另一个对象,可以继承原型对象的属性;
Object.getPrototypeOf( ) // 可查询对象的原型;
p.isPrototypeOf(o) // 来检测p是否是o的原型;
- 对象的类(class)是一个表示对象类型的字符串,用以表示对象的类型信息,一般用toString( )来获取:[Object class]。 下面是封装好的 classof函数,用来检测对象类型;
function classof(o){
if(o === null){return "Null"};
if(o === undefined){return "Undefined"};
return Object.ptototype.toString.call(o).slice(8,-1);
}
- 对象的扩展标记(extensible flag)指明了是否可以向该对象添加新属性;ES5中,所有的内置对象和自定义对象都是显式可扩展的,宿主对象的可扩展性是依据引擎所定义的;
Object.esExtensible( ); // 判断对象是否可扩展;
Object.preventExtensions( ); // 将对象设置为不可拓展并且无法再转换回可拓展;但同样可以继承属性;
Object.seal( ); // 封闭对象;将对象设置为不可拓展,而且将所有自有属性设置为不可配置;
Object.isSealed( ); // 检测对象是否被封闭;
Object.freeze( ); // 更严格的冻结对象,不可拓展,配置,且只读;
Object.isFrozen( ); // 检测对象是否被冻结;
- 内置对象:JS内部定义的对象或类,如数组(Array)、函数(Function)、日期(Date)和正则表达式(RegExp)等;
- 宿主对象:由js解释器所嵌入的宿主环境中定义的对象,如浏览器客户端;
- 自定义对象:在JS代码中创建的对象;
- 自有属性:在对象内部定义的属性;
- 继承属性:从原型对象中继承得到的属性;
- 对象字面量法: 一个对象字面量就是包围在一对花括号中的若干个名/值对组成的映射表,名与值之间用
:
分隔,名值对间用,
分隔。该方法的__proto__
指向Object.prototype.
// 注意,最后一个名/值对后不再添加逗号;
var student = {
"name":"Tayde",
"age":26
}
- new操作符+构造函数: 通过new操作符后跟一个函数,初始化创建出一个新的对象,该方法的
__proto__
指向构造函数.prototype。
var o = new Object(); // 与 var o = { }效果一样;
- ES5中的Object.create( ): 该方法可填两个参数,第一个填对象原型,第二选填自定义的属性;
__proto__
指向函数中填入的对象。
var o1 = Object.create({x:1,y:2}); // 则o1对象已经继承了x,y属性;
.
运算符,当属性名为一个简单的标识符时,一个静态值时使用;优先考虑,因为它有更好的可读性;[ ]
运算符,该方法更全面,当属性名为变量或动态值时使用;
var name = student.name;
var age = student["age"];
Tips: 1、当属性不存在时,会返回 undefined,并不会报错; 2、但当查询属性的对象不存在时,则会报错;解决方法:
var len = book && book.subtitle && book.subtitle.length;
3、可以用
||
运算符来填充默认值;
var sex = student.sex || "unknown";
对象通过引用来传递,他们永远不会被复制。 对象并没有被复制,而是仅仅将x,y指向同一个对象的引用而已。
var x = {a:1};
var y = x;
y.a = 2;
console.log(x.a); // 2;
delete student.name;
delete student["age"];
Tips: delete操作符只能删除自身属性,无法删除原型上的继承属性; delete操作符值是断开属性和宿主对象的联系,并不是删除属性,因此外部的引用仍会存在;
var a = {x:{y:1}};
var b = a.x;
delete a.x;
console.log(b); // {y:1};
console.log(a.x); // undefined;
1、in运算符:
var o ={x:1};
console.log("y" in o); // false;
2、hasOwnProperty( ):检测是否为自有属性,如果是继承属性,则返回false;
var o = {x:1};
console.log(o.hasOwnProperty("x")); // true;
console.log(o.hasOwnProperty("toString")); // false;
3、propertyIsEnumerable( ): 属于hasOwnProperty的增强版,只有当属性为自有属性且可枚举性时,才返回true;
var o = {x:1};
console.log(o.propertyIsEnumerable("x")); // true;
console.log(o.hasOwnProperty("y")); // false;
console.log(o.hasOwnProperty("toString")); // false;
4、直接与undefined比较;
var o = {x:1};
o.x !== undefined; // true;
o.y !== undefined; // false;
在ES5中,对象的属性值可以用一个或两个方法替代,他们就是getter和setter。由这两个方法定义的属性称作“存取器属性”。
var serialnum = {
"$n":0,
get next(){
return this.$n++;
},
set next(){
if(n>=this.$n){this.$n = n;}else{throw "新值必须大于当前值。"}
}
}
对象序列化是指将对象的状态转换成字符串,也可以将字符串转换为对象。使用ES5中的 JSON.stringify( ) 和 JSON.parse( )。
1、NaN、Infinity和-Infinity序列化后的结果是Null; 2、函数、RegExp、Error对象和undefined值不能序列化和还原; 3、JSON.stringify( ) 只能序列化对象可枚举的自有属性;
1、toString( ):无需参数,返回一个该对象的字符串。 2、toLocaleString( ):返回一个表示这个对象的本地化字符串。 3、toJSON( ): 4、valueOf( ):