JS 对象(Object)的深入解析—私有属性

2019-03-16  本文已影响0人  vinterx

当你走的很远的时候,回过头来看看自己走过的道路,可能会发现曾错过的风景。

JS中万物都是对象,今天就深度讲一下Object的里面到底有什么。文章主要讲对象的自有属性和原型中的属性,至于原型链就不在这篇文章多讲了。

一、Object简述

创建对象的方法有如下几种

  1. new + Object
  2. 字面式 {name: 'vinter'}
  3. 工厂模式(可以创建多个对象)
let person = (name, age) => {
  let o = new Object()
  o.name = name
  o.age = age
  Object.prototype.say = () => {
    console.log('你好')
  }
  return o
}
let p1 = person('vinter', 18)
let p2 = person('xzwen', 20)
//  无法识别对象类型 都是Object
  1. 构造函数
function Person(name){
    this.name = name
        this.say = () => {}
}

let p = new Person('vinter')

console.log(p instanceof Person)  // true
console.log(p instanceof Object)  //  true
//  能够识别对象的类型
  1. 原型模式
function Person(name){
}
Person.prototype = {
  name: 'viter',
  age: 18,
  say: () => {}
}
let p = new Person()

//  所有属性写进原型,对象都能访问,没有对象的私有属性
  1. 混合模式
    \color{red}{最优方法} 实例拥有自己的私有属性,又拥有共同的原型方法
function Person(name, age){
    this.name = name
    this.age = age
}
Person.prototype = {
  constructor: Person,  //  将constructor 指向Person
  say: () => {console.log('你好')}
}
let p = new Person('vinter', 18)
console.log(p.name)
p.say()

二、Object私有属性解析

object.png

1. Object.assign

Object.assign() 方法用于将其他对象的可枚举属性复制到目标对象(即第一个参数对象)

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const sources = { d: 2, b: 6 }
Object.assign(target, source, sources)
//  { a: 1, b: 6, c: 5, d: 2}

console.log(target.c)
//  5

常用于将某个对象合并到新对象{}。

Object.assign({}, source)

2. Object.create

Object.create =  function (obj) {
    var F = function () {};
    F.prototype = obj;
    return new F();
};

常用于继承某个构造函数的原型属性,但是不能继承该构造函数的实例属性,例如上面例子

let P = () => {}
p.prototype = obj
let p1 = Object.create(obj)

3. Object.defineProperty

Object.defineProperty(obj, prop, descriptor)

该属性是实现vue双向数据绑定的核心,这里主要讲它的使用方法。
讲它的相关用法时,就得先理解\color{red}{数据属性和访问器属性}的概念。
1.数据属性
数据属性的四个特性
configurable:表示是否能被delete删除属性且能重新定义该属性。
enumerable:表示能否通过for-in遍历的属性。
writable:表示是否能修改属性。
value:属性的值。

let person = {
    name: 'vinter'
}
console.log(Object.getOwnPropertyDescriptor(person, 'name'))
person.png

2.访问器属性
数据属性不包含数据值,包含一对get和set的核心方法,在读取访问器属性时,就是通过这两个方法进行操作处理的。
访问器属性的四个特性
configurable:表示是否能被delete删除属性且能重新定义该属性。
enumerable:表示能否通过for-in遍历的属性。
get:读取属性时调用的方法,默认值是undefined。
set:写入属性时调用的方法,默认值是undefined。
\color{red}{访问器属性不能直接定义,需要通过Object.defineProperty()来定义。}

let person = {
    name: 'vinter',
    _age: 18, //    下划线是常用标记,表示是内部属性,只能通过对象的方法进行读写
    weight: 120
}
Object.defineProperty(person, 'age', {  // 'age'代替'_age'
    get(){
        return this._age
    },
    set(newValue){
        this._age = newValue
        this.weight += 2
    }
})
person.age = 10
console.log(person.weight, person.age) //   122 10
console.log(Object.getOwnPropertyDescriptor(person, 'age'))
访问器属性.png

从图中可以看到访问器属性的configurable和enumerable两个属性的默认值都是false,如果后面要对该访问器属性进行delete删除时,将configurable转化成true即可。

console.log(Object.getOwnPropertyDescriptors(person))
person对象.png

从图可以看出该对象具有四个属性,\color{red}{ \_age是数据属性,通过它生成了一个age访问器属性。因为访问器属性不能直接定义,所以通过\_age数据属性生成了。}

4. Object的四个相关属性

(defineProperty、defineProperties、getOwnPropertyDescriptor、getOwnPropertyDescriptors)
这四个属性是分为两对:defineProperty vs getOwnPropertyDescriptor、defineProperties vs getOwnPropertyDescriptors。
意思为属性设置和属性的获取解析,第一对上面讲过了,这里就大概说一下第二对的意思,也就是支持设置对个属性,获取多个属性的意思。
Object.defineProperties()

Object.defineProperties(obj, props)
var obj = new Object();
Object.defineProperties(obj, {
    name: {
        value: '张三',
        configurable: false,
        writable: true,
        enumerable: true
    },
    age: {
        value: 18,
        configurable: true
    }
})

console.log(obj.name, obj.age) // 张三, 18

Object.getOwnPropertyDescriptors()
打印出对象的所有属性

Object.getOwnPropertyDescriptors(obj)

5. Object.entries

Object.entries() 方法返回一个给定对象\color{red}{自身可枚举属性的键值对的二维数组。}

let obj = {
   name: 'vinter',
   age: 18
}

let arr = [2, 3, 4]

let string = 'abc'

console.log(Object.entries(obj))  //    [['name', 'vinter'], ['age', 18]]

console.log(Object.entries(arr))    //  [['0', 2], ['1', 3], ['2', 4]]

console.log(Object.entries(string)) //  [['0', 'a'], ['1', 'b'], ['2', 'c']]

Object转Map
new Map()构造函数接受一个二维数组,而Object.entries()方法生成一个二维数组,所以对象、数组、字数串转化为Map结构变得简单。

obj = {name: 'vinter', age: 18}
new Map(Object.entries(obj))
// Map {'name' => 'vinter', 'age' => 18}

6. Object.freeze,Object.preventExtension,Object.seal

正常对象的数据属性都可以被\color{red}{增、删、改、查。}但是通过以下方法,改变了数据属性的四大特性。

相对应的检测方法,返回Boolean。

举例
Object.freeze()方法可冻结对象,冻结后,对象属性不能删除,修改以及添加,只能for...in读取。

obj = {
  name: 'vinter',
  age: 18
}

Object.freeze(obj)

console.log(Object.getOwnPropertyDescriptors(obj))
freeze.png

7. Object.is

该对象方法和==与===运算符相似,但是有明显区别。
Object.is与==比较
== 会将两边的操作数进行隐式转化,之后再进行比较,但是Object.is就不会进行转化。

'' == false  // true
'1' == 1  //  true

Object.is与===比较
=== NaN和NaN不等,-0与+0相等,但是Object.is就认为NaN和NaN是相等,而-0和+0是不相等的。
所以总的来说这两个的相似程度比== 运算符更相近。

8.Object.keys,Object.values

Object.keys()返回一个\color{red}{所有可枚举属性}名称(键)的数组

let arr = [2, 3, 4]
let str = 'abc'

console(Object.keys(arr)) //  ['0', '1', '2']
console.log(Object.str(str)) // ['0', '1', '2']
//  因为JSON对象的特性,所以返回都会是字符串的数组

Object.values()返回可枚举属性值得数组

var obj = { foo: 'bar', baz: 42 }
let str = 'abc'
console.log(Object.values(obj)) //  ['bar', 42]
console.log(Object.values(str)) //  ['a', 'b', 'c']

9.Object.setPrototypeOf

Object.setPrototypeOf(obj, prototype)
为对象obj设置新的原型对象。

注意
如果对象的[[Prototype]]被修改成不可扩展(通过 Object.isExtensible()查看),就会抛出 TypeError异常。如果prototype参数不是一个对象或者null(例如,数字,字符串,boolean,或者 undefined),则什么都不做。否则,该方法将obj[[Prototype]]修改为新的值。

var obj = { foo: 'bar', baz: 42 }
let prototypeC = {name: 'vinter'}

Object.setPrototypeOf(obj, prototypeC)

console.log(obj)
setProtopertyOf.png

下篇文章JS 对象(Object)的深入解析—原型属性

上一篇 下一篇

猜你喜欢

热点阅读