资讯专栏INFORMATION COLUMN

Object 属性与方法全接触

YJNldm / 1710人阅读

摘要:一切对象都是的实例,一切函数都是的实例,是构造函数,函数是的实例,是对象,对象是的实例,可以说与是一对密不可分的兄弟,让我们一起解开与的神秘面纱,本章主要了解相关知识,下章再来看构造函数可以创建一个对象包装器中所有对象都来自所有对象从继承方

一切对象都是 Object 的实例,一切函数都是 Function 的实例,Object 是构造函数,函数是 Function 的实例,Function.prototype 是对象,对象是 Object 的实例,可以说 Object 与 Function 是一对密不可分的兄弟,让我们一起解开 Object 与 Function 的神秘面纱,本章主要了解 Object 相关知识,下章再来看 Function

Function instanceof Object // true
Object instanceof Function // true

Object 构造函数可以创建一个对象包装器

JS 中所有对象都来自 Object, 所有对象从 Object.prototype 继承方法和属性

传入的值为 null 或 undefined 将返回一个 {} 空对象

Object(null) // {}
Object(undefined) // {}

Object() 等同于 new Object()

对象字面量

由 {} 包含零个或多个键值对组成以逗号分隔的列表构成

对象字面量是属性名及其关联值的集合
必须由 逗号 分隔
下面是 ES6(ECMAScript 2015) 中对象的定义方式

const a = 1;
var obj = {
    a,
    get a(){},
    set a(){},
    ["a" + "b"]: "hello",
    say(){},
    baz: { b: 2 }
}
重复属性

重复的属性,后面的属性会覆盖前面的属性,在ES5中,重复的属性会抛出语法错误 SyntaxError

对象合并

Object.assign() 可以合并两个对象,也可以使用展开符 ... 合并两个对象,Object.assign() 会触发 setter,而展开操作符则不会

var a = { a: 1 };
var b = { b: 2 };

var mergedObj = Object.assign({}, a, b)

var mergedObj = { ...a, ...b }
变更对象原型

如果给对象的 _proto_ 赋值为 null, 则会更改对象原型,赋值为其它任何值则不会改变对象原型

Object.getPrototypeOf({__proto__:null}) === null
// true

Object.getPrototypeOf({__proto__:{}}) === null
// false

在对象字面值中,只有一次改变原型的机会,多次变更会报语法错误

不使用 : 定义 _proto__ 不会变更原型,而是会变成对象的普通属性

var __proto__ = "variable";
var obj1 = { __proto__ };
Object.getPrototypeOf(obj1) === Object.prototype
// true

var obj2 = { __proto__() { return "hello"; } };
obj2.__proto__() === "
与JSON区别

对象字面量 与 JSON(JavaScript Object Notation) 的区别

JSON 只允许 以 "property": value 的形式定义属性,且属性名必须以 " 号括起来,属性定义不允许简写
JSON 中的属性值只允许 字符串、数字、数组、true、false、null或其它JSON对象
JSON 中属性值不允许是函数
JSON.parse() 不会处理计算属性名,会抛语法错误
Object.length

返回 Object() 构造函数形参数量,值为 1

Object.prototype Object.prototype.hasOwnProperty()

检查对象自身中是否有某属性(忽略原型链中的属性)

Object.prototype.isPrototypeOf()

检查当前原型是否在指定对象的原型中 (作用等同于 instanceof)

Object.prototype.propertyIsEnumerable()

判断属性是否可枚举

Object.prototype.toLocaleString()

返回对象的字符串表示(用于派生对象重载)

Array.prototype.toLocaleString([locales[,options]])
Number.prototype.toLocaleString([locales[,options]])
Date.prototype.toLocaleString([locales[,options]])

新的 locales 和 options 参数让应用程序可以指定要进行格式转换的语言,并且定制函数的行为

在旧的实现中,会忽略 locales 和 options 参数,使用的语言环境和返回的字符串的形式完全取决于实现方式。

locales 和 options 不同的浏览器及版本有兼容性问题,所以这个api并没有得到广泛的应用

var prices = ["¥7", 500, 8123, 12];
prices.toLocaleString("ja-JP", { style: "currency", currency: "JPY" });

// "¥7,¥500,¥8,123,¥12"

const num = 2333333;
num.toLocaleString("zh", { style: "decimal" });   //2,333,333
num.toLocaleString("zh", { style: "percent" });   //233,333,300%

const num = 2333333;
num.toLocaleString("zh", { style: "currency", currency: "CNY" });    //¥2,333,333.00
num.toLocaleString("zh", { style: "currency", currency: "cny", currencyDisplay: "code" });      //CNY2,333,333.00

let num = 2333.3;
num.toLocaleString("zh", { minimumIntegerDigits: 5 });        //02,333.3
//如果不想有分隔符,可以指定useGrouping为false
num.toLocaleString("zh", { minimumIntegerDigits: 5, useGrouping: false });        //02333.3
num.toLocaleString("zh", { minimumFractionDigits: 2, useGrouping: false });     //2333.30

num = 666.666
num.toLocaleString("zh", { maximumFractionDigits: 2, useGrouping: false });     //666.67
Object.prototype.toString()

返回对象的字符串表示

使用 toString 来检查对象类型

function isNull(){
Object.prototype.toString.call(obj) === "[object Null]"
}

Object.prototype.valueOf()

返回一个表示该对象的字符串

Object.assign()

将可枚举的属性从一个或多个源拷贝到目标对象

但是只能深拷贝非嵌套的对象,嵌套属性为浅拷贝

简单的深拷贝

JSON.parse(JSON.stringify(Obj)), 缺点是会破坏对象的原型链,并且会丢失对象的方法

Object.create(proto, [propsObj])

使用指定的原型创建对象

// ES5实现 (不支持 propsObj)
function extend(proto){
  function F(){};
  F.prototype = proto;
  return new F();
}

// 创建一个原型为null的空对象
var o = Object.create(null)

var o = {}
// 相当于
var o = Object.create(Object.prototype)

// 为所创建的对象添加属性 (如果缺省配置,默认为false)
var o = Object.create(Object.prototype, {
  foo: {
    writeable: true,
    configurable: true,
    enumerable: true,
    value: "hello"
  }
})

function MyClass (){}
var o = new MyClass()
// 相当于
var o = Object.create(Myclass.prototype)

Object.assign 只会拷贝源对象自身且可枚举的属性,会调用 源对象的 get 和 目标对象的 set 方法,
如果源对象的属性 get 方法是自定义的,合并后,将会丢失
合并时,不会跳过那些值为 null 或 undefined 的源对象
Ojbect.assign 的ES5中的 polyfill

Object.defineProperty(Object, "assign", {
  value: function assign(target, varArgs) {
    "use strict";
    if (target == null) {
      throw new TypeError("Connot convert undefined or null to object");
    }

    var to = Object(target);

    for (var index = 1; index < arguments.length; index++) {
      var nextSource = arguments[index]
      for (var nextKey in nextSource) {
        if(Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
          to[nextKey] = nextSource[nextKey];
        }
      }
    }

    return to;
  },
  writeable: true,
  configurable: true,
})
Object.defineProperty(obj, prop, descriptor)

定义或修改属性对象

obj: 要定义属性的对象
prop: 属性名称
descriptor: 属性描述

属性描述 descriptor 分为两种:数据描述符 和 存取描述符

数据描述符:一个有值的属性,可配置 是否可枚举、是否可配置、是否可赋值 及 value值

存取描述符:有 getter、setter 函数的属性,也可配置 是否可配置及是否可枚举
属性描述只能是 数据描述 或 存取描述 中的一种

数据描述符 描述的属性只可能有 configurable、enumerable、writeable、value

存取描述符 描述的属性只可能有 get、set、configurable、enumerable 四个配置
如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符

// 数据描述符 描述的属性
Object.defineProperty({}, "a", {
  // 是否可枚举 决定了是否可被 for...in 和 Object.keys() 获取属性名
  enumerabel: true,
  // 属性描述是否可改变,该属性是否可删除,当前配置为false时,不能在数据和访问器属性类型之间切换,不可删除,除 writable 之外的描述不可修改
  configurable: true,
  // 是否可赋值
  writeable: true,
  // 属性值,默认为 undefined
  value: 1
})

// 存取描述符 描述的属性
var bValue;
Object.defineProperty({}, "b", {
  get: function(){
    return value;
  },
  set: function(newValue){
    bValue = newValue
  },
  enumerable: true,
  configurable: true,
})
function Archiver () {
  var temp = null;
  var history = []

  Object.defineProperty(this, "temp", {
    get: function () {
      console.log("get")
      return temp;
    },
    set: function (newV) {
      temp = newV
      history.push({val: temp})
    }
  })

  this.getHistory = function(){ return history; };
}

var arc = new Archiver()

arc.temp
arc.temp = 11
arc.temp = 13
arc.getHistory() // [{ val: 11 }, { val: 13 }]
Object.defineProperties(obj, props)

定义或修改多个属性对象 与 Object.defineProperty 一样

var obj = {};
Object.defineProperties(obj, {
  "property1": {
    value: true,
    writable: true
  },
  "property2": {
    value: "Hello",
    writable: false
  }
});
Object.entries()

返回可枚举属性的键值对数组

// 获取
const obj = { foo: "bar", baz: 42 };
console.log(Object.entries(obj)); // [ ["foo", "bar"], ["baz", 42] ]

// 遍历 for...of
const obj = { a: 5, b: 7, c: 9};
for(const [key, value] of Object.entries(obj)) {
  console.log(`${key} ${value}`);
}

// 遍历 forEach
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

// Object 转 Map
new Map(Object.entries(obj))
Object.freeze()

冻结一个对象,被冻结的对象,不可添加、删除、修改其属性,也不可修改属性的描述配置,返回被冻结的对象

只能冻结对象中的第一层的常量对象,不可冻结复杂对象

obj1 = {
  internal: {}
};

Object.freeze(obj1);
obj1.internal.a = "aValue";

obj1.internal.a // "aValue"
自定义一个深冻结函数

function deepFreeze(obj){
  const propNames = Object.getOwnPropertyNames(obj);

  propNames.forEach(name => {
    const prop = obj[name];

    if(typeof prop === "object" && prop !== null) {
      deepFreeze(prop)
    }
  })

  return Object.freeze(obj)
}
Object.isFrozen()

返回指定对象是否是冻结对象

Object.seal()

封闭一个对象,对象属性不可删除,不可增加新属性,不可修改属性描述配置,但 可以修改属性值

const object1 = {
  property1: 42
};

Object.seal(object1);
object1.property1 = 33;
console.log(object1.property1);
// expected output: 33

delete object1.property1; // cannot delete when sealed
console.log(object1.property1);
// expected output: 33
Object.isSealed()

返回指定对象是否是封闭对象

获取对象自身可枚举的属性

Object.keys()

与 for...in 不同的是:for...in 还会遍历对象原型链中的属性

使用 for...in 获取对象自身可枚举的属性

for(key in obj) {
obj.hasOwnProperty(key){
console.log(key)
}
}
Object.values()

返回可枚举的属性数组

const obj = { foo: "bar", baz: 42 };
console.log(Object.entries(obj)); // [ ["foo", "bar"], ["baz", 42] ]
Object.getOwnPropertyNames()

获取对象自身的属性 (枚举&不能枚举)

获取对象自身不可枚举的属性?

var allProps = Object.getOwnPropertyNames(obj)
var enumProps = Object.keys(obj)
var noenumProps = allProps.filter(v => enumProps.indexOf(v) === -1)
Object.getOwnPropertySymbols()

返回对象自身所有 Symbol 属性数组

对象自身属性 包含了两种类型,一种是 字符串属性,一种是 Symbol 数据属性,
字符串属性名可由 Object.getOwnPropertyNames() 来获取
Symbol 属性名可由 Ojbect.getOwnPropertySymbols() 来获取
默认对象是不含有 Symbol 属性的,除非手动添加了 Symbol 属性

Object.getOwnPropertyDescriptor()

返回 对象自身属性的 描述配置信息

Object.getOwnPropertyDescriptors()

返回 对象自身所有属性的 描述配置信息

属性描述分为两种:存取描述 与 数据描述

var o = { get foo() { return 17; } };
var d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
//   configurable: true,
//   enumerable: true,
//   get: /*the getter function*/,
//   set: undefined
// }

var o = { bar: 42 };
var d = Object.getOwnPropertyDescriptor(o, "bar");
// d {
//   configurable: true,
//   enumerable: true,
//   value: 42,
//   writable: true
// }

Object.assign() 无法拷贝源对象属性的特性,且属性描述会被转为数据描述,也无法拷贝源对象的原型

使用 Object.create() 可以完整的浅拷贝一个对象

Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj))

Object.getPrototypeOf()
返回指定对象的原型

var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
Object.setPrototypeOf()

设置指定对象的原型

这个方法是ES6中的方法,用于替换ES5中 Object.prototype.__proto__ = newProto 的方式修改原型

修改原型对于浏览器是一个耗性能的方法,应避免去修改原型,使用 Object.create() 去创建新的对象

Object.is()

同值相等比较 比较两个值是否相等

与抽象相等 == 区别:
同值相等不会去隐式转换数据类型

与严格相等 === 区别:
同值相告对于 -0与+0 返回 false, 而严格相等返回 true
对于 NaN 与 NaN,同值相等返回 true, 严格相等返回 false

Object.is(0, -0);            // false
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

0 === -0 //true
+0 === -0 //true
NaN === NaN //false
Object.isExtensible()

判断指定对象是否可以扩展 (是否可以添加属性及原型)返回 Boolean

var empty = {};
Object.isExtensible(empty); // === true
Object.preventExtensions()

禁止对象扩展 已有的属性可以修改、删除,但不能再添加新的属性

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96649.html

相关文章

  • JavaScript学习之Object(下)相关方法

    摘要:它不区分该属性是对象自身的属性,还是继承的属性。那么我们要遍历对象所有属性,包括继承以及不可遍历的属性,用加原型遍历实现类似的用递归 Object静态方法 Object自身方法,必须由Object调用,实例对象并不能调用 Object.getPrototypeOf() 作用是获取目标对象的原型 function F() {}; var obj = new F(); console.lo...

    amuqiao 评论0 收藏0
  • 深入理解 js 之继承原型链

    摘要:原型链与继承当谈到继承时,只有一种结构对象。如果对该图不怎么理解,不要着急,继续往下看基于原型链的继承对象是动态的属性包指其自己的属性。当使用操作符来作用这个函数时,它就可以被称为构造方法构造函数。 原型链与继承 当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object )都有一个私有属性(称之为proto)指向它的原型对象(prototype)。该原型对象也...

    xingqiba 评论0 收藏0
  • vue.js响应式原理解析实现

    摘要:今天,就我们就来一步步解析响应式的原理,并且来实现一个简单的。当然,这个也只是一个简单的,来说明响应式的原理,真实的源码会更加复杂,因为加了很多其他逻辑。接下来我可能会将其与联系起来,实现和语法。 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染。之后,再接触了vue.js,当时也一度很好奇vue.js是如何监...

    Shihira 评论0 收藏0
  • 关于JavaScript对象,你所不知道的事(一)- 先谈对象

    摘要:对象与属性让我们保持耐心,再梳理一下对象与属性的关系对象是属性的集合,当对象的属性是函数时,我们将其称之为方法。 这篇博文的主要目的是为了填坑,很久之前我发表了一篇名为关于JavaScript对象中的一切(一) — 对象属性的文章,想要谈一谈JavaScript对象,可那时只是贴了一张关于这个主题的思维导图,今天我会针对这一主题进行展开,将JavaScript对象一些平常不太常用的知识...

    mykurisu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<