对象的方法

120 阅读9分钟

js

创建 JavaScript 对象

定义和创建单个对象,使用对象文字

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};

定义和创建单个对象,通过关键词 new

var person = new Object();
person.firstName = "Bill";
person.lastName = "Gates";
person.age = 50;
person.eyeColor = "blue"; 

通过Object.create() es5的

var Obj ={
        name:'mini',
        age:3,
        show:function () {
            console.log(this.name +" is " +this.age);
        }
    }


 var MyObj = Object.create(Obj);
MyObj.name // 'mini'

方法

Object.defineProperty(obj, prop, desc)

就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性

  1. obj 需要定义属性的当前对象
  2. prop 当前需要定义的属性名
  3. desc 属性描述符
// 参数 第三个的 说明 存取描述符
value:  值
writable: 是否能改变属性的值
get: 函数
set: 函数
configrable: 是否配置,以及可否删除
enumerable: 是否会出现在for in 或者 Object.keys()的遍历中

let Person = {}
Object.defineProperty(Person, 'name', {
   value: 'jack',
   writable: true // 是否可以改变
})
Person.name = 'rose' // Person.name = 'rose'
let Person = {}
let temp = null
Object.defineProperty(Person, 'name', {
   get: function(){
       return temp
   },
   set: function(val){
       temp = val
   }
})
Person.name = 'rose' // Person.name = 'rose'

Object.freeze()

在data或vuex里我们可以使用freeze冻结对象,对于纯展示的大数据,都可以使用Object.freeze提升性能

Object.freeze()冻结的是值,你仍然可以将变量的引用替换掉

data: {
    // vue不会对list里的object做getter、setter绑定
    list: Object.freeze([
        { value: 1 },
        { value: 2 }
    ])
},
created () {
  	// 界面不会有响应
 	this.list[0].value = 100;
    // 下面两种做法,界面都会响应
    this.list = [
        { value: 100 },
        { value: 200 }
    ];
    this.list = Object.freeze([
        { value: 100 },
        { value: 200 }
    ]);
}

Object.fromEntries()

将数组转成一个自身可枚举属性的键值对象

const keyValuePair = [
  ['cow', '????'],
  ['pig', '????'],
]
 
Object.fromEntries(keyValuePair);
// { cow: '????', pig: '????' }

Object.entries()

对象自身可枚举属性的键值对数组

const obj = { foo: 'bar', baz: 'abc' }; 
console.log(Object.entries(obj));  // [['foo', 'bar'], ['baz', 'abc']]
const arr = [1, 2, 3]; 
console.log(Object.entries(arr));  // [['0', 1], ['1', '2'], ['2', '3']]
const arr1 = [{ a: 1 }, 2, 3]; 
console.log(Object.entries(arr1));  // [['0', { a: 1 }], ['1', '2'], ['2', '3']]
const arr2 = [{ a: 1 }, { b: 2 }, { c: 3 }]; 
console.log(Object.entries(arr2));  // [['0', { a: 1 }], ['1', { b: 2 }], ['2', { c: 3 }]]
const str = '123'; 
console.log(Object.entries(str));  // [['0', '1'], ['1', '2'], ['2', '3']]

Object.hasOwnProperty()

会返回一个布尔值,指示对象自身属性中(非继承属性)是否具有指定的属性

obj,必需。对象的实例。 prop,必需。一个属性名称的字符串值。

obj.hasOwnProperty(prop)

const obj = new Object();

obj.name = "刘家军";
obj.hobby="knockCode"

const a = obj.hasOwnProperty('name');
console.log(a);// true

delete obj.name
const b = obj.hasOwnProperty('name');
console.log(b); // false

obj.propertyIsEnumerable(prop)

可以确定对象中的指定属性(除了通过原型链继承的属性)是否可以由for...in循环枚举。

const obj = {};
const arr = [];
obj.name= 'weiqinl';
arr[0] = 2018;
console.log(obj.propertyIsEnumerable('name'));  // true
console.log(arr.propertyIsEnumerable(0)); // true
console.log(arr.propertyIsEnumerable('length')); // false
function Person(name,age) {
    this.name = name
    this.age = age
    this.say = function() {
        console.log('say hi')
    }
}
Person.prototype.where = 'beijing' // 在原型链上添加属性
var p = new Person('weiqinl', 18)  // 实例化一个对象
p.time = '2018'    // 在实例上添加属性
let arr = []
for(let i in p) {
    console.log(i, p.propertyIsEnumerable(i))
    p.propertyIsEnumerable(i)? arr.push(i) : ''
}
console.log(arr)
// name true
// age true
// say true
// time true
// where false
// (4) ["name", "age", "say", "time"]
与hasOwnProperty的区别
hasOwnProperty()方法检验是否为自有属性。
propertyIsEnumberable()方法,可以确定对象中的指定属性(除了通过原型链继承的属性)是否可以由for...in循环枚举。

Object.getOwnPropertyNames()

返回一个数组,其中包含作为参数传递的对象自身属性的所有名称

const dog = {}
dog.breed = 'Siberian Husky'
dog.name = 'Roger'
 
Object.getOwnPropertyNames(dog) //[ 'breed', 'name' ]

和**Object.keys()**的区别 www.jb51.net/article/187…

Object valueOf()

在对象实例上调用,返回其原始值

const person = { name: 'Fred' }
person.valueOf() //{ name: 'Fred' }
这通常仅由JavaScript内部使用,而很少在用户代码中实际调用。

Object.defineProperties(obj,props)

直接在一个对象上定义新的属性或者修改现有属性并返回该对象

var obj = {};
    var obj1 = {
        value: true,
        writable: true
    }
    var obj2 = {
        value: 'hello',
        writable: false
    }
    Object.defineProperties(obj, { obj1, obj2 })
    console.log(obj)
    // 输出结果是: {obj1: true, obj2: "hello"}

和Object.defineProperty的区别 www.cnblogs.com/sq652366/p/…

es6

对象的扩展

扩展运算符 ...{}

对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中

let z = { a: 3, b: 4 };
let n = { ...z };
console.log(n)   // { a: 3, b: 4 }

对象属性简写表示法

对象可以用变量和函数作为对象的属性和方法,当属性名和属性值相同时,可以省略一个。方法也可以简写,看例子:

let birth = '2018/03/14';
const Person = {
    name: 'peter', 
    birth,   // 等同于birth: birth
    hello() { console.log('我的名字是', this.name); }    // 等同于hello: function ()...
};

属性名表达式 TODO==========

在声明对象的属性时,可以用标识符声明,es6可以用表达式来声明。

在使用对象字面量声明对象时,可以用中括号[]里写表达式

let name = 'foo';
let obj = {
    [name](){console.log(0)},
    ['a' + 'bc']: 123
};
console.log(obj)    // {foo: ƒ, abc: 123}

ps,属性名表达式与简洁表示法,不能同时使用,会报错

super关键字

super 指向当前对象的原型对象,只用在对象的方法中

var proto = {
    foo: 'hello'
};
var obj = {
    foo: 'world',
    find() {
        return super.foo;
    }
};
Object.setPrototypeOf(obj, proto);
console.log(obj.find())// "hello"

对象方法:

Object.is(a, b)

在严格模式下用来比较两个值是否相等,返回值是布尔值

ps: +0 和 -0 在严格模式下相等, 但用Object.is() 不相等

   NaN 在严格模式不相等, 但用Object.is() 相等

console.log(+0 === -0)   //true
console.log(Object.is(+0, -0)) // false
console.log(NaN === NaN) // false
console.log(Object.is(NaN, NaN)) // true

Object.assign(target,source1,source2...)

对象合并,浅拷贝,将源对象(source)的所有可枚举属性,复制到目标对象(target)

params: target 目标对象,要合并的所存在的容器,只有一个

     source 源对象,被合并的对象,可以多个

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target)     // {a:1, b:2, c:3}

ps: 1 目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性,在嵌套中,该方法也是替换而不是添加

  2 如果只有一个参数,Object.assign会直接返回该参数。

3 只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)

4 属性名为 Symbol 值的属性,也会被Object.assign拷贝。

5 浅拷贝,源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

const target = { a: 1, b: 1,c:{d:1,e:1} };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target)   // {a:1, b:2, c:3}
console.log(Object.assign({a:{b:1,c:1}}))   // {a: {…}}
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
console.log(obj2.a.b) // 2

Object.setPrototypeOf(obj, proto)

用来设置一个对象的prototype对象,返回参数对象本身

params: obj: 代表当前的对象

    proto: 要设置的原型对象名

let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
console.log(obj.x) // 10
console.log(obj.y) // 20
console.log(obj.z) // 40

上段代码将proto对象设为obj对象的原型,所以从obj对象可以读取proto对象的属性。

Object.getPrototypeOf(obj)

用来获取一个对象的prototype对象,返回参数对象本身

let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
console.log(Object.getPrototypeOf(obj))   // {y: 20, z: 40}

Object.keys()

返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名

let obj = {
    name: 'peter',
    age: 25,
    sex: '男'
}
console.log(Object.keys(obj))   // ["name", "age", "sex"]

Object.values()

返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值

let obj = {
    name: 'peter',
    age: 25,
    sex: '男'
}
console.log(Object.values(obj))   // ["peter", 25, "男"]

Object.entries()

返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组

let obj = {
    name: 'peter',
    age: 25,
    sex: '男'
}
console.log(Object.entries(obj))   // [Array(2), Array(2), Array(2)]

ps:当对象里套着一个对象时,以上方法是返回遍历第一次的值

几种循环对象的方法

for......in

TODO ====================

const obj = {
            id:1,
            name:'zhangsan',
            age:18
}

 for(let key  in obj){
        console.log(key + '---' + obj[key])
  }
// id ---1
// name ---zhangsan
// age ---18

Object.keys(obj)和 Object.values(obj)

const obj = {
    id:1,
    name:'zhangsan',
    age:18
}

 console.log(Object.keys(obj))

console.log(Object.values(obj))
// ['id','name','age']
// ['1','zhangsan','18']

Object.getOwnPropertyNames(obj)

返回一个数组,包含对象自身的所有属性(包含不可枚举属性)
遍历可以获取key和value
const obj = {
            id:1,
            name:'zhangsan',
            age:18
    }
    Object.getOwnPropertyNames(obj).forEach(function(key){
        console.log(key+ '---'+obj[key])
    })
// id ---1
// name ---zhangsan
// age ---18

Reflect.ownKeys(obj)遍历

返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举.

var obj = {'0':'a','1':'b','2':'c'};

Reflect.ownKeys(obj).forEach(function(key){
console.log(key,obj[key]);
});
// 0 a
// 1 b
// 2 c

对象拷贝

即将一个对象的值赋值给另一个对象,这种情况在JavaScript中是很常见的。对于对象拷贝分为深拷贝和浅拷贝:

在说拷贝之前我们要先了解堆和栈的概念:

堆(heap):是堆内存的简称,是一块自动分配相对固定大小的存储空间。 栈(stack):是栈内存的简称,是动态分配内存、内存大小不一的存储空间。 一般情况下基本类型是存储在堆中的,直接存储的是值。引用类型是存储在栈中的,存储的是一个指针,这个指针指向内存中的某个位置,这个指针指向的位置是存储变量的实际值。

浅拷贝

一般来说深浅拷贝指的是引用类型。

引用类型是直接复制或者赋值的称为浅拷贝,对于浅拷贝来说两个对象相互之间的关联性太强

var arr = [1, 2, 3];
    var arr1 = arr;
    arr1[3] = 4;
    console.log(arr1, arr)
    // 输出结果是:[1,2,3,4] [1,2,3,4]

深拷贝

引用类型内部的值的复制与地址无关称为深拷贝。对于深拷贝来说我们要实现的是其中一个的属性发生改变另外一个的值不会改变。ES6有一个新增的属性Object.assign(target,...sources)可以帮我们实现我们的需求。

var obj1 = {
    a: 1,
    b: 2
};
var obj2 = {};
Object.assign(obj2, obj1); // 只能进行第一层的深拷贝
obj2.a = 3;
console.log(obj1, obj2);
//输出结果是: {a:1,b:2} {a:3,b:2}

更深层次的拷贝还是传址的

var obj1 = [{ a: 1, b: 2 }, 2, 3];
var obj2 = [];
Object.assign(obj2, obj1);
obj2[0].a = 3;
console.log(obj1, obj2);
// 输出的结果是:[{ a: 3, b: 2 }, 2, 3] 和 [{ a: 3, b: 2 }, 2, 3]

简单的方式实现更深层次的深拷贝

 var obj = { a: [1, 2, 3] };
var obj1 = JSON.parse(JSON.stringify(obj));
obj1.a.push(4);

console.log(obj, obj1)
// 输出结果是: {a: [1, 2, 3]}  {a:[1, 2, 3, 4]}
function deepCopy(obj){
    if (Array.isArray(obj)) {
        var newObj = [];
    } else {
        var newObj = {};
    };

    for (var i in obj) {
        if (typeof obj[i] == "object") {
            newObj[i] = deepCopy(obj[i])
        } else {
            newObj[i] = obj[i];
        }
    };
    return newObj;
};

var arr = [[1], 2, 3];
var arr1 = deepCopy(arr);
arr1[0].push(2);
console.log(arr, arr1)
// 输出结果是:[[1], 2, 3] [[1,2], 2, 3]