Cuuube / blog

blog on Mirror
1 stars 0 forks source link

[es5]重新读书之——Object #52

Open Cuuube opened 6 years ago

Cuuube commented 6 years ago

:标题中的安全,较新等均指浏览器。

安全:较旧版本的浏览器都支持,甚至ie

较安全:ie9以上,火狐、chrome浏览器不能是太早期版本

较新:仅仅新版本火狐、chrome等支持,ie不支持,甚至edged都很危险

仅供参考


1. valueOf 自定义对象的表示 (安全)

原型链方法

很有趣的一个方法。当将对象看做简单数据对象,进行运算时,会取valueOf的值。例:

class Person {
    constructor (name) {
        this.name = name;
    }
    valueOf () {
        return this.name;
    }
}
let tom = new Person('Tom');
console.log('I am ' + tom);
// I am Tom

valueOf方法默认会返回this,但当我们手动设置之后,就可以返回任何东西(返回对象也可以,但最好你返回的对象也设置了valueOf,不然很可能会变得奇葩)。

2. assign 合并和复制 (较新)

assign会将第二个参数的所有属性,都覆盖到第一个上。

let baseObj = { a: 'a', d: 'd' };
let extendObj = {
    a: 1,
    b: 2,
    c: 3
};
let newObj = Object.assign(baseObj, extendObj);
console.log(newObj);
// {a: 1, b: 2, c: 3, d: 'd'}

额外用法:经常用作obj的复制

let oldObj = { a: 1 , b: 2 };
let newObj = Object.assign({}, oldObj);
console.log(oldObj === newObj);
// false

jquery中也有类似的用法$.extend(),对浏览器的兼容更好。

3. create 继承 (安全)

用最简单的一行说明继承:

let parentObj = { a: 'a', b: 'b' };
let obj = Object.create(parentObj);
console.log(obj);
// {}

咦,你说怎么创建出来是空的呢,说好的继承呢?

如果你在chrome控制台中log出来看,点开这个obj的__proto__属性来,你就明白了。

console.log(obj.__proto__);
// {a: "a", b: "b"}

我们的parentObj已经跑到prototype中啦!

但,如果你很满意,并学会了assign方法,开始举一反三,那你就悲剧了

let parentObj = { a: 'a', b: 'b' };
let obj = Object.create(parentObj, { a: 1 });
// Uncaught TypeError: Property description must be an object: 1... balabala...

因为Object.create的第二个参数并不能直接是一个一般的obj,必须是一个对象的属性名称和属性描述符的键值对,关于这个东西是什么,具体可以参考下面defineProperties的讲解,总之是一个很厉害但很麻烦的主。

4. defineProperties和defineProperty 创建新属性值(安全)

给对象添加新属性值。

单数,复数,调用方式不同。例:

let a = { a:1, b:2 };
// defineProperty
Object.defineProperty(a, 'c', {
    writeable: true,// 可重复赋值
    value: 3,       // 值
    enumerable: true,// 会出现在枚举中
    configurable: true// 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除
})

// defineProperties
Object.defineProperty(a, {
    'c': {
        writeable: true,// 可重复赋值
    value: 3        // 值
    },
    'd': {
        value: 4        // 没有writeable,默认为false,即不可更改
    }
})

5. preventExtensions 使object不可拓展 (较安全 )

不可拓展即是:

可使用isExtensible()检验是否被密封

用法同下面

6. seal 密封对象 (较安全)

密封即是:

let obj = {a: 1, b: 2};
Object.seal(obj);
obj.a = 5; // ok
obj.c = 30; // no error
console.log(a); // {a: 5, b: 2};

可使用Object.isSeal(obj)检验是否被密封

7. freeze 冻结对象 (较安全)

冻结对象即是:

let obj = {a: 1, b: 2};
Object.freeze(obj);
obj.a = 5; // Type Error

可使用Object.isFrozen(obj)检验是否被冻结

8. keys, values, entries(较新)

这些都是ES6的语法,keysentries在较新版FF和chrome支持,values几乎支持的版本更新更少

example:

let a = { a: 1, b: 2 };
console.log(Object.keys(a));
// ["a", "b"]
console.log(Object.values(a));
// [1, 2]
console.log(Object.entries(a));
// chrome控制台打印:
// (2) [Array(2), Array(2)]
// 0:(2) ["a", 1]
// 1:(2) ["b", 2]
// length:2
// __proto__:Array(0)

一目了然:

9. is 比较

用于比较两个object是否相同。规则和===略有区别

具体规则可以点击这里

此处摘出不一样的地方:

这种相等性判断逻辑和传统的 == 运算符所用的不同,== 运算符会对它两边的操作数做隐式类型转换(如果它们类型不同),然后才进行相等性比较,(所以才会有类似 "" == falsetrue 的现象),但 Object.is 不会做这种类型转换。

这与===运算符也不一样。===运算符(和==运算符)将数字值-0+0视为相等,并认为Number.NaN不等于NaN

10. hasOwnProperty 是否自己的属性存在

这个方法是原型链上的方法,因此可以直接在任意obj上调用

此方法最爽的是可以判断出自己的属性,也是旧版本中的明星用法:可以做for-in的清道夫

exmple:

let obj = { a: 'a', b: 'b' };
let parentObj = { a: 1, b: 2, c: 3 };
obj.__proto__ = parentObj; // 相当于obj的原型指向了parentObj,obj继承了parentObj的属性[代码中不要这样写]

console.log(obj);
// { a: 'a', b: 'b' }
console.log(obj.c);
// 3

for (let i in obj) {
    console.log(i, obj[i]);
}
// a a
// b b
// c 3

如果我只想遍历子类obj的属性,不想要继承的属性,但父类的c强行抢镜。

于是。。你知道怎么办了

for (let i in obj) {
    if (obj.hasOwnProperty(i)) { //< 补丁
        console.log(i, obj[i]);
    }
}
// a a
// b b