Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javascript零碎之基础二 #49

Open
kekobin opened this issue Oct 9, 2019 · 0 comments
Open

Javascript零碎之基础二 #49

kekobin opened this issue Oct 9, 2019 · 0 comments

Comments

@kekobin
Copy link
Owner

kekobin commented Oct 9, 2019

Object

Object常见静态方法总览:
(1)对象属性模型的相关方法

  • Object.getOwnPropertyDescriptor():获取某个属性的描述对象。
  • Object.defineProperty():通过描述对象,定义某个属性。
  • Object.defineProperties():通过描述对象,定义多个属性。

(2)控制对象状态的方法

  • Object.preventExtensions():防止对象扩展。
  • Object.isExtensible():判断对象是否可扩展。
  • Object.seal():禁止对象配置。
  • Object.isSealed():判断一个对象是否可配置。
  • Object.freeze():冻结一个对象。
  • Object.isFrozen():判断一个对象是否被冻结。

(3)原型链相关方法

  • Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
  • Object.getPrototypeOf():获取对象的Prototype对象。

Object.create(proto,[propertiesObject])

  • proto:新创建对象的原型对象
  • propertiesObject:可选。要添加到新对象的可枚举(新添加的属性是其自身的属性,而不是其原型链上的属性)的属性。

image

由上图可见,proto 为null、Object、Object.prototype时,使用Object.create创建新对象的结构都是不一样的。不同点在于"是否继承与Object"、"还是继承于Object.prototype"。

为什么vue中普遍使用 Object.create(null) 初始化新对象,而不是{}呢?

  • 使用create(null)创建的对象,没有任何属性,即可以把它当作一个非常纯净的map来使用,可以自己定义hasOwnProperty、toString方法,而不必担心会将原型链上的同名方法覆盖掉。
  • 可以节省hasOwnProperty带来的一丢丢性能损失并且可以偷懒少些一点代码。因为在我们使用for..in循环的时候会遍历对象原型链上的属性,使用create(null)就不必再对属性进行检查了,当然,我们也可以直接使用Object.keys[]。

Object.keys(),Object.getOwnPropertyNames()

对于一般的对象来说,Object.keys()和Object.getOwnPropertyNames()返回的结果是一样的。只有涉及不可枚举属性时,才会有不一样的结果。Object.keys方法只返回可枚举的属性,Object.getOwnPropertyNames方法还返回不可枚举的属性名。

var a = ['Hello', 'World'];

Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]

属性描述对象

JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。

下面是属性描述对象的一个例子。

{
  value: 123, // 默认为undefined
  writable: false, // 默认为true
  enumerable: true,
  configurable: false,
  get: undefined,
  set: undefined
}
  • enumerable: 表示该属性是否可遍历,默认为true。如果设为false,会使得某些操作(比如for...in循环、Object.keys())跳过该属性。
  • configurable: 表示可配置性,默认为true。如果设为false,将阻止某些操作改写该属性,比如无法删除该属性,也不得改变该属性的属性描述对象(value属性除外)。也就是说,configurable属性控制了属性描述对象的可写性。
  • get: 表示该属性的取值函数(getter),默认为undefined。
  • set: 表示该属性的存值函数(setter),默认为undefined。

Object.getOwnPropertyDescriptor(obj, propertyName)

获取属性描述对象。它的第一个参数是一个对象,第二个参数是一个字符串,对应该对象的某个属性名。

而 Object.getOwnPropertyDescriptors(obj) 功能一样,只不过获取obj所有属性的描述。

image

注意,Object.getOwnPropertyDescriptor方法只能用于对象自身的属性,不能用于继承的属性。

Object.getOwnPropertyNames() 和 Object.keys()

前者返回参数对象自身的全部属性的属性名,不管该属性是否可遍历;后者只返回可遍历的属性。

image

Object.defineProperty(),Object.defineProperties()

  • Object.defineProperty方法允许通过属性描述对象,定义或修改一个属性,然后返回修改后的对象,它的用法如下。
Object.defineProperty(object, propertyName, attributesObject)
var obj = Object.defineProperty({}, 'p', {
  value: 123,
  writable: false,
  enumerable: true,
  configurable: false
});

obj.p // 123

obj.p = 246;
obj.p // 123
  • Object.defineProperties 定义或修改多个属性,然后返回修改后的对象
var obj = Object.defineProperties({}, {
  p1: { value: 123, enumerable: true },
  p2: { value: 'abc', enumerable: true },
  p3: { get: function () { return this.p1 + this.p2 },
    enumerable:true,
    configurable:true
  }
});

obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"

注意,一旦定义了取值函数get(或存值函数set),就不能将writable属性设为true,或者同时定义value属性,否则会报错。

enumerable

如果一个属性的enumerable为false,下面三个操作不会取到该属性。

  • for..in循环
  • Object.keys方法
  • JSON.stringify方法

因此,enumerable可以用来设置“秘密”属性。

var obj = {};

Object.defineProperty(obj, 'x', {
  value: 123,
  enumerable: false
});

obj.x // 123

for (var key in obj) {
  console.log(key);
}
// undefined

Object.keys(obj)  // []
JSON.stringify(obj) // "{}"

configurable

configurable(可配置性)返回一个布尔值,决定了是否可以修改属性描述对象。也就是说,configurable为false时,value、writable、enumerable和configurable都不能被修改了。也决定了目标属性是否可以被删除(delete)。

存取器

除了直接定义以外,属性还可以用存取器(accessor)定义。其中,存值函数称为setter,使用属性描述对象的set属性;取值函数称为getter,使用属性描述对象的get属性。

var obj = Object.defineProperty({}, 'p', {
  get: function () {
    return 'getter';
  },
  set: function (value) {
    console.log('setter: ' + value);
  }
});

obj.p // "getter"
obj.p = 123 // "setter: 123"

JavaScript 还提供了存取器的另一种写法:

var obj = {
  get p() {
    return 'getter';
  },
  set p(value) {
    console.log('setter: ' + value);
  }
};

存取器往往用于,属性的值依赖对象内部数据的场合。

对象的拷贝

var extend = function (to, from) {
  for (var property in from) {
    if (!from.hasOwnProperty(property)) continue;
    Object.defineProperty(
      to,
      property,
      Object.getOwnPropertyDescriptor(from, property)
    );
  }

  return to;
}

extend({}, { get a(){ return 1 } })
// { get a(){ return 1 } })

控制对象状态

有时需要冻结对象的读写状态,防止对象被改变。JavaScript 提供了三种冻结方法,最弱的一种是Object.preventExtensions,其次是Object.seal,最强的是Object.freeze。

  • Object.preventExtensions(): 可以使得一个对象无法再添加新的属性。

image

  • Object.seal(): 使得一个对象既无法添加新属性,也无法删除旧属性。

image

Object.seal实质是把属性描述对象的configurable属性设为false,因此属性描述对象不再能改变了。
Object.seal只是禁止新增或删除属性,并不影响修改某个属性的值。

  • Object.freeze():可以使得一个对象无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量。

image

  • Object.isFrozen(): 用于检查一个对象是否使用了Object.freeze方法。
    用途是,确认某个对象没有被冻结后,再对它的属性赋值。
if (!Object.isFrozen(obj)) {
  obj.p = 'world';
}

Object.prototype.toString()

作用是返回一个对象的字符串形式,默认情况下返回类型字符串。常用语判断数据类型。

Object.prototype.toString.call(value)

例如:
image

封装方法:

var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};

['Null',
 'Undefined',
 'Object',
 'Array',
 'String',
 'Number',
 'Boolean',
 'Function',
 'RegExp'
].forEach(function (t) {
  type['is' + t] = function (o) {
    return type(o) === t.toLowerCase();
  };
});

type.isObject({}) // true
type.isNumber(NaN) // true
type.isRegExp(/abc/) // true

Array

reduce(),reduceRight()

reduce方法和reduceRight方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员),其他完全一样。

image

a默认是数组的第一个元素,此时b为数组第二个元素。也可以像下面这样指定初始的a,则b初始是数组第一个元素:

image

JSON

JSON.stringify(obj, null, params)

第三个参数,用于增加返回的 JSON 字符串的可读性。如果是数字,表示每个属性前面添加的空格(最多不超过10个);如果是字符串(不超过10个字符),则该字符串会添加在每行前面。
image

参考

属性描述对象

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant