1、对象有两种形式定义:声明文字形式和构造形式。
2、内置对象:js中有一些对象子类型,称为内置对象
var strprimitive = ‘I am string‘; typeof strprimitive;//‘string‘ strprimitive instanceof String; //false var strobj = new String(‘I am string‘); typeof strobj; strobj instanceof String; Object.prototype.toString.call(strobj); // [object string]
typeof ,instanceof,Object.prototype.toString.call()区分对象类型
js中通过Object.prototype.toString方法----精确判断对象的类型
1、在 javascript 里使用 typeof 来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object” 五种。
对于数组、函数、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串。
2、instanceof判断对象类型,有点麻烦
//对象 (a instanceof Object) && !(a instanceof Array) && !(a instanceof Function) //数组 (a instanceof Object) && (a instanceof Array) //函数 (a instanceof Object) && (a instanceof Function)
3、使用Object.prototype.toString方法
console.log(Object.prototype.toString.call("jerry"));//[object String] console.log(Object.prototype.toString.call(12));//[object Number] console.log(Object.prototype.toString.call(true));//[object Boolean] console.log(Object.prototype.toString.call(undefined));//[object Undefined] console.log(Object.prototype.toString.call(null));//[object Null] console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object] console.log(Object.prototype.toString.call(function(){}));//[object Function] console.log(Object.prototype.toString.call([]));//[object Array] console.log(Object.prototype.toString.call(new Date));//[object Date] console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
所有类型都会得到不同的字符串,几乎完美。
那为什么不直接用obj.toString()呢?
这是因为toString为Object的原型方法,而Array
,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串.....),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。
4、内容
var myObject = { a:2 }; myObject.a;//2 myObject[‘a‘];//2
如果要访问myObject 中a位置上的值,我们需要使用.操作符,或者[]操作符
.a语法通常被称作属性访问,[‘a‘]语法通常被称为键访问
区别在于.操作符要求属性名满足标识符的命名规范,而[..]语法可以接受任意UTF-8/Unicode字符串作为属性名
由于[..]语法使用字符串来访问属性,所以可以在程序中构造字符串
在对象中属性名永远是字符串
5、可计算属性名
ES6增加了可计算属性名,可以在文字形式中使用[]包裹一个表达式当作属性名。
var prefix = "foo"; var myObject = { [prefix+"bar"]:‘hello‘, [prefix+"baz"]:‘world‘ }; myObject[‘foobar‘];//hello myObject[‘foobaz‘];//world
6、数组
数组期望的是数值下标,也就是说值存储的位置是非负整数
数组也是对象,所以虽然每个下标都是整数,仍然可以给数组添加属性
var myArray = [‘foo‘,42,‘bar‘]; myArray.baz = ‘baz‘; myArray.length;//3 myArray.baz;//‘baz‘
可以看到虽然添加了命名属性,数组的length值并没有发生变化
如果你试图向数组中添加一个属性但是属性名看起来很像一个数字,那它会变成一个数值下标
var myArray = [‘foo‘,42,‘bar‘]; myArray[‘3‘] = ‘baz‘; myArray.length;//4 myArray[3];//‘baz‘
7、复制对象
对于JSON安全的对象来说,有一种巧妙的复制方法:
JSON安全:也就是说可以被序列化为一个JSON字符串并且可以根据这个字符串解析出一个结构和值完全一样的对象
var newObj = JSON.parse(JSON.stringfy(someObj));
这种方法需要保证对象是JSON安全的,所以只适用于部分情况
浅复制易懂,问题少一些。
Object.assign(..)第一个参数是目标对象,之后可以跟一个或多个源对象
8、属性描述符
从ES5开始,所有属性都具有了属性描述符
var myObject = { a:2 } Object.getOwnPropertyDescriptor(myObject,‘a‘);
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true
// }
可以使用Object.defineProperty()来添加一个新属性,或者修改一个已有属性
Object.defineProperty(myObject,‘a‘,{ value: 2, writable: true, enumerable: true, configurable: true }); myObject.a;//2
9、对象默认的[[Put]] 和[[Get]]操作分别可以控制属性值的设置和
在ES5中可以使用getter和setter部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter是一个隐藏函数,会在获取属性值时调用,setter也是一个隐藏函数,会在设置属性时调用。
var myObject = { get a() { return 2; } }; myObject.a = 3; myObject.a;//2
由于我们只定义了a的getter,所以对a的值进行设置时,set操作会忽略赋值操作,不会抛出错误。
即使有了合法的setter我们定义的getter只会返回2。所以set操作没有意义。
10、存在性
我们可以在不访问属性值的情况下判断对象中是否存在这个属性
var myObject = { a:2 }; (‘a‘ in myObject);//true (‘b‘ in myObject);//false myObject.hasOwnProperty(‘a‘);// true myObject.hasOwnProperty(‘b‘);//false
in 操作符会检查属性是否在对象及其[[Prototype]]原型链上,相比之下,hasOwnProperty()只会检查属性是否在myObject对象中,不会检查[[Prototype]]链
注意:in实际上检查的是某个属性是否存在。对于数组:4 in [2,4,6] 并不是true ,因为 [2,4,6] 包含的是属性名0,1,2没有4
11、枚举
可枚举就相当于 可以出现在对象属性的遍历中
不影响存在性
for...in...这种枚举不仅会包含所有的数值索引还会包含所有可枚举属性