对象的声明有俩种:前端
二者惟一的区别就是,字面量形式,能够一次赋值多个,经过new Object就得一个一个赋值es6
数据类型函数
JS种7种数据类型this
简单数据类型spa
复杂基本类型(内置对象,object子类型)双向绑定
补充:null为何是基本类型可是依然会出现,typeof null 会返回 object?这是一个语言的bug,原理以下:原理是这样的,不一样的对象在底层都表示为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判
断为 object 类型,null 的二进制表示是全 0,天然前三位也是 0,因此执行 typeof 时会返回“object”。code
深刻对比基本类型和复杂类型的区别,用string和String对比对象
var str = 'hello world'; var strObj = new String('hello String'); str.length // 11 strObj.length // 12 // typeof判断属于那种简单数据类型 typeof str; // "string" typeof strObj; //"object" // instanceof判断对象实例的鼻祖是哪一个复杂类型 str instanceof String // false strObj instanceof String // true
这段代码能够分析出,str经过字面量形式声明,其数据类型为基本数据类型,并非对象,strObj 为复杂数据类型String的实例。咱们知道str, strObj的数据类型以后,就要抛出一个问题,为何str并非对象,它怎么就能调用length呢?这不是一个简单数据类型该有的呀。js向你丢出一个结论,那就是简单数据类型存在一个隐式转换,它会从简单数据类型转换为复杂数据类型。blog
首先以对象字面量整一个对象ip
let obj = { name: 'hello', age: 12 }
访问对象的属性能够经过 圆点运算符 相似于 obj.name, 还能够经过属性运算符 obj["name"]
访问。
ES6 定义了Object.assign()方法实现浅复制,该方法第一个参数是目标对象,以后还能够跟一个或多个原对象,他会遍历一个或多个原对象全部可枚举的自有键并把他们复制(使用 = 操做符赋值,因此这种僵硬的赋值操做,不会将原对象的属性的特性复制过来)到目标对象,最后返回目标对象。
对象有本身的属性和方法,对于咱们js对象的属性来说,属性还有本身的“属性”,又称为属性描述符。不要小看这个属性描述符,可不得了,经过属性描述符,咱们不只仅能够配置属性是读写权限,甚至经过setter,getter实现咱们的数据双向绑定。该介绍一下这位调用属性描述符的内置方法了:Object.defineProperty()
。这个方法接受三个参数,第一个是指定的对象,第二个是指定的对象参数,第三个固然是要修改的属性描述符了。当对象中不存在指定的属性,Object.defineProperty()
就建立这个属性,当描述符中省略某些字段时,这些字段将使用它们的默认值,拥有布尔值的字段的默认值都是false
因此这也就是说,经过
Object.defineProperty()
建立的属性,描述符是不可配置的,由于configurable:false
// 直接对一个对象使用原点运算符赋值,属性描述符都是true var o = {}; o.a = 1; // 等同于 : Object.defineProperty(o, "a", { value : 1, writable : true, configurable : true, enumerable : true }); // 另外一方面,使用Object.defineProperty()却将属性修饰符关闭了 Object.defineProperty(o, "a", { value : 1 }); // 等同于 : Object.defineProperty(o, "a", { value : 1, writable : false, configurable : false, enumerable : false });
var obj = { name: 'hello', age: 12 } Object.defineProperty(obj, 'name', { value: 2, writable: true, configurable: true, enumerable: true }) obj.name; //2 not hello
接下来,咱们解释一下属性描述符的四大天王:value, writable, configurable, enumerable
为啥先要介绍configurable
呢,不得不说说他的重要性,这个描述符的值是true/false,它表示属性描述符是否可配置,当值为false时,剩下的描述符都是不可配置的,修改也不会生效,不包括value。简单的说,configurable控制的其余描述符的命运!后面咱们讨论的时候,默认configurable为true,否则,讨论也没有意义,根本不会改变嘛
var a = { name: 'tom', age: 22 } Object.defineProperty(a, 'age', { enumerable: false, writable:false, configurable: false, }) a.age = 12; // a.age 为12.即便writable 是false,由于configurable是false,因此writable其实仍是默认的true
我知道你确定是不信的,直接上图。Object.getOwnPropertyDescriptor() 与Object.defineProperty()
互为一对儿,一个定义,一个查看定义
并且,将configurable修改成false,这是一个单向操做,你想再次修改它的值为true以实现从新配置属性描述符是不可能的,一旦设置false,永远都是false了。据说你还不信,那我再上图
var myObject = { a:2 }; myObject.a = 3; myObject.a; // 3 Object.defineProperty( myObject, "a", { value: 4, writable: true, configurable: false, // 不可配置! enumerable: true } ); myObject.a; // 4 myObject.a = 5; myObject.a; // 5 Object.defineProperty( myObject, "a", { value: 6, writable: true, configurable: true, enumerable: true } ); // TypeError
咱们介绍一下控制读写的小伙伴-writable,这个属性描述符控制咱们是否能够对属性进行赋值,值为false时,赋值是无论用的。严格模式下,还会抛出错误。至于writable怎么处理属性是否能被赋值,留一个疑问,稍后立刻揭晓。
// configurable为true var myObject = {}; Object.defineProperty( myObject, "a", { value: 2, writable: false, // 不可写! configurable: true, enumerable: true } ); myObject.a = 3; myObject.a; // 2
这个属性修饰符可能没有那么直观,可是从字面来看,咱们应该是能了解到的,这是控制属性是否能出如今对象可枚举属性中。若是将enumerable设置为false,属性就不会出如今可枚举属性中。enumerable定义了对象的属性是否能够在 for...in 循环和 Object.keys() 中被枚举。
var obj = { name: 'tom', age: 12 } for(prop in obj) { console.log(prop); // name, age } Object.defineProperty(obj, 'name', { enumerable: false, }) for(prop in obj) { console.log(prop); //age }
补充一些可枚举相关的知识,什么叫可枚举属性,就是指那些属性描述符设置为enumerable为true的属性。有不少方法是基于可枚举性的。好比,Object.keys(), in, for in 。对于上面那个例子,就是使用了for in遍历obj对象可枚举属性。
writable:false 和 configurable:false
,就能够建立一个一次赋值,不能修改的常量ES5可使用getter和setter部分改写默认操做,可是只能应用在单个属性上,没法应用在整个对象上,getter,setter都是隐藏函数,前者在获取属性值时自动调用,后者是在设置属性值时自动调用。其实如今,咱们能够总结一下前文所述。属性描述符其实分为两种
而咱们前文一直在讲述数据修饰符,那么什么是访问修饰符呢?
当咱们给一个属性定义getter和setter或者二者都有时,这个属性会被定义为”访问描述符“,对于访问描述符而言,JavaScript会忽略它们的value和writable特性,取而代之的是关心set/get(还有configurable和enumerable)特性
实例演示:
function Archiver() { var temperature = null; var archive = []; Object.defineProperty(this, 'temperature', { get: function() { console.log('get!'); return temperature; }, set: function(value) { temperature = value; archive.push({ val: temperature }); } }); this.getArchive = function() { return archive; }; } var arc = new Archiver(); arc.temperature; // 'get!' arc.temperature = 11; arc.temperature = 13; arc.getArchive(); // [{ val: 11 }, { val: 13 }]
一言以蔽之,setter/getter无非就是咱们在赋值或者读取变量时,预先悄悄调用的一个隐藏方法。
还有一种经过对象文字语法建立的get,set(我也是从《你不知道的js》看到这种用法的,MDN这相关的文档中我并无看到,学到了),这个不是经过Object.defineProperty()建立的,两者都会在对象中建立一个不包含值的属性,对于这个属性的访问会自动调用一个隐藏函数,它的返回值会被看成属性访问的返回值。
其实能够更细致的观察到,经过对象文字语法建立的变量,他的修饰符按照规则确定是没有value的,可是其余配置信息是true,这一点很关键
大致上对象的内容就是这么多,后续在作一个补充,MDN实在是前端宝典,看到这里更推荐读者阅读MDN相关文档:https://developer.mozilla.org...