你不知道1
-
typeof null === ‘object’ 原理
原理是这样的,不同的对象在底层都表示为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判 断为 object 类型,null 的二进制表示是全0, 自然前三位也是0,所以执行typeof 时会返回 “object”
-
原始值 “I am a string” 并不是一个对象,它只是一个字面量,并且是一个不可变的值。
-
我们都可以直接在字符串字面量上访问属性或者方法,之所以可以这 样做,是因为引擎自动把字面量转换成 String 对象,所以可以访问属性和方法
-
在对象中,属性名永远都是字符串。如果你使用 string(字面量)以外的其他值作为属性 名,那它首先会被转换为一个字符串。即使是数字也不例外,虽然在数组下标中使用的的 确是数字,但是在对象属性名中数字会被转换成字符串,所以当心不要搞混对象和数组中 数字的用法
-
对于 JSON 安全(也就是说可以被序列化为一个 JSON 字符串并且可以根据这个字符串解 析出一个结构和值完全一样的对象)的对象来说,有一种巧妙的复制方法
var newObj = JSON.parse( JSON.stringify( someObj ) );
当然,这种方法需要保证对象是 JSON 安全的,所以只适用于部分情况 -
属性描述符
Object.getOwnPropertyDescriptor(obj, attrName)
返回四个值 ,分别是value writable enumerable configuerable
-
writable 决定是否可以修改属性的值
-
configuerable 只要属性是可配置的,就可以使使用 defineProperty(…) 方法来修改属性描述符
Object.defineProperty(myObject, 'a', { value: 4, writable: true, enumerable: true, configuerable: true, })
-
enumerable 控制属性是否会出现在 for in 循环中
-
1) 对象常量 结合 writable:false 和 configurable:false 就可以创建一个真正的常量属性(不可修改、 重定义或者删除
var myObject = {};
Object.defineProperty( myObject, "FAVORITE_NUMBER", {
value: 42,
writable: false,
configurable: false
} );
2) 禁止扩展
如果你想禁止一个对象添加新属性并且保留已有属性,可以使用 Object.preventExtensions(..)
3) 密封
Object.seal(..) 会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用 Object.preventExtensions(..) 并把所有现有属性标记为 configurable:false。
所以,密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以 修改属性的值)
4) 冻结
Object.freeze(..) 会创建一个冻结对象,这个方法实际上会在一个现有对象上调用 Object.seal(..) 并把所有“数据访问”属性标记为 writable:false,这样就无法修改它们 的值。
- 在对象中,属性名永远都是字符
> 如果你使用 string(字面量)以外的其他值作为属性 名,那它首先会被转换为一个字符串。即使是数字也不例外,虽然在数组下标中使用的的 确是数字,但是在对象属性名中数字会被转换成字符串,.
-
可计算属性名最常用的场景可能是 ES6 的符号(Symbol) , 不过 简单来说,它们是一种新的基础数据类型,包含一个不透明且无法预测的值(从技术角度来说就是字符串)
-
深拷贝
var newObj = JSON.parse( JSON.stringify( someObj ) );
,这种方法需要保证对象是 JSON 安全的,所以只适用于部分情况。 -
用户定义的所有的普通属性默认都是 enumerable,这通常就是你想要的。但是如果你不希 望某些特殊属性出现在枚举中,那就把它设置成 enumerable:false。对于一些自定义特别标识的属性 可以这样操作。
-
in 操作符会检查属性是否在对象及其 [[Prototype]] 原型链中。相比之下, hasOwnProperty(..) 只会检查属性是否在 myObject 对象中,不会检查 [[Prototype]] 链。
-
和数组不同,普通的对象没有内置的 @@iterator,所以无法自动完成 for..of 遍历。之所 以要这样做,有许多非常复杂的原因,不过简单来说,这样做是为了避免影响未来的对象 类型。
-
你可以给任何想遍历的对象定义 @@iterator
var myObject = { a:2, b:3 }; Object.defineProperty(myObject, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function(){ var o = this; var idx = 0; var ks = Object.keys(o); return { next: function(){ return { value: o[ks[idx++]], done:(idx > ks.length) } } } }, }) // 也可以直接在定义对象时进行声明,比如 var myObject = { a: 2, b: 3, [Symbol.iterator]: function() { return { next: function(){ return { value, done } } } } }
-
你甚至可以定义一个“无限”迭代器,它永远不会“结束”并且总会返回一个新 值(比如随机数、递增值、唯一标识符,等等)。你可能永远不会在 for..of 循环中使用这 样的迭代器,因为它永远不会结束,你的程序会被挂起:
var randoms = { [Symbol.iteraror]:function(){ return { next: function(){ return { value: Math.random } } } } } var randoms_pool = []; for(var n of randoms) { randoms_pool.push(n); // 防止无限运行 if(randoms_pool.length === 100) break; }
-
Object.create()的polyfill代码
if(!Object.create){ Object.create = function(o){ function F (){} F.prototype = o; return new F(); } }
-
“修复”丢失的 .constructor 属性
function Foo() { /* .. */ }
Foo.prototype = { /* .. */ }; // 创建一个新原型对象
// 需要在 Foo.prototype 上“修复”丢失的 .constructor 属性
// 新对象属性起到 Foo.prototype 的作用
Object.defineProperty(Foo.prototype, 'construtor', { enumerable: false, writable: true, configuable: true, value: Foo, // 让.construtor 指向Foo })
.constructor 并不是一个不可变属性。它是不可枚举(参见上面的代码)的,但是它的值 是可写的(可以被修改)。此外,你可以给任意 [[Prototype]] 链中的任意对象添加一个名 为 constructor 的属性或者对其进行修改,你可以任意对其赋值。
- 创建一个合适的关联对象,我们必须使用 Object.create(..) 而不是使用具有副 作用的 Foo(..)。这样做唯一的缺点就是需要创建一个新对象然后把旧对象抛弃掉,不能 直接修改已有的默认对象。
我们来对比一下两种把 Bar.prototype 关联到 Foo.prototype 的方法:
// ES6 之前需要抛弃默认的Bar.prototype Bar.prototype = Object.create(Foo.prototype); // ES6 开始可以直接修改现有的Bar.prototype Object.setPrototypeof(Bar.prototype, Foo.prototype)
-
获取一个对象的原型链
Object.getPrototypeof(a)
, 也就是Object.getPrototypeof(a) === Foo.prototype
,
也有一种非标准的方法来访问内部原型链的属性 `a._proto_ === Foo.prototype`
__proto__
的实现原理
```javascript
Object.definePrototy(Object.prototype, '__proto__',{
get: function(){
return Object.getPrototypeof(this)
},
set: function(o){
// es6 的setProtoOf(..)
Object.setPrototypeOf(this, o);
return o;
}
})
```
-
理解
Object.create(..)
这个大英雄var foo = { something: function(){ console.log('Tell me somgthing good...') } }; var bar = Object.create(foo); bar.somgthing(); // Tell me somgthing good... // Object.create(..) 会创建一个新对象(bar)并把它关联到我们指定的对象(foo),这样 我们就可以充分发挥 [[Prototype]] 机制的威力(委托)并且避免不必要的麻烦(比如使 用 new 的构造函数调用会生成 .prototype 和 .constructor 引用)。
-
Object.create(null)
会创建一个拥有空(null)的原型链对象Object.create(null) 会 创 建 一 个 拥 有 空( 或 者 说 null)[[Prototype]] 链接的对象,这个对象无法进行委托。由于这个对象没有原型链,所以 instanceof 操作符(之前解释过)无法进行判断,因此总是会返回 false。 这些特殊的空 [[Prototype]] 对象通常被称作“字典”,它们完全不会受到原 型链的干扰,因此非常适合用来存储数据。
-
:[[Prototype]] 机制就是指对象中的一个内部链接引用 另一个对象。
如果在第一个对象上没有找到需要的属性或者方法引用,引擎就会继续在 [[Prototype]] 关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的 [[Prototype]],以此类推。这一系列对象的链接被称为“原型链”。
JavaScript 中这个机制的本质就是对象之间的关联关系。