JS对象的初步整理

72 阅读2分钟

对象:一些属性和方法和无序集合。

无序意味着内部没有Symbol.iterator。不可以使用for of 迭代。

对象定义

传统:

let obj = {
	name:'gjq',
	sayName:function(){
		console.log(this.name);
	}
}

ES6:

let ageKey = "age"
let jobKey = "job"
function setKey(key){
return `${key}+1`;
}
let obj = {
	name:'gjq',
	sayName(){
		console.log(this.name);   //这里值为函数的属性可以简写,但仍然属于此对象的作用域
	},
	[age]:27,                新增的可计算属性,[]里面首先进行js表达式求值,然后返回值作为key
	[setKey(jobKey)]:15       因为[]会进行js求值,所以可以嵌入函数表达式,但是这样性能会降低
}

DFKfbt.png

访问对象属性

传统:

obj.name

ES6

var prototy=name;
obj[prototy];       	1.可以通过变量访问对象
obj["na"+"me"]		2.可以通过字符串拼接访问

描述对象的属性特征:访问器属性和数据属性(这是属性具有的属性)

数据属性:

  • [[configurable]]:是否可删除属性,是否可以修改特性,是否可以改为访问器属性
  • [[enumerable]]:是否可枚举,即for-in。
  • [[writable]]:是否可修改
  • [[value]]:值

默认都为true

访问器属性:

  • [[configurable]]
  • [[enumerable]]
  • [[get]]:获取属性值,默认undefined,可以重写getter函数
  • [[set]]:设置属性值,默认undefined,重写getter函数

定义属性的方法:Object.defineProperty(obj,"属性",{writable:...})

​ 批量操作:Object.defineProperties(obj,{"属性",{writable:...}},{})

获取属性描述的方法:Object.getOwnPropertyDescriptor(obj,"属性")

​ 批量操作:Object.getOwnPropertyDescriptors(obj)

DFKWDI.png

对象的合并(Object.assign())

Object.assgin()接受一个目标对象和多个源对象作为参数,将源对象中的可枚举属性和自有属性(Object.hasOwnProperty())浅复制到目标对象。

过程:调用源对象可复制属性的get方法,然后在目标对象中调用set方法。多个目标对象相同属性会被覆盖。

问题:因为是浅复制,所以引用类型地址相同

对象相等的判定

  1. 俩个对象的判断:ES6的Object.is(obj1,obj2)

    多个对象:

    function equal(x,...arg){
    	return Object.is(x,arg[0])&&(arg.length<2||equal(...arg))
    }
    
  2. 递归比较俩个对象的key,value是否一致

  3. JSON.stringfy()转化为字符串比较。问题:对于key顺序不同的对象结果为false

    编程思路:比较是不是都是对象。比较长度是否一致,比较key是否相同,递归比较嵌套的key值

对象的解构

ES6新增对象解构语法,就是使用与对象匹配的结构来实现对象属性的赋值

let person = {
	name:'gjq',
	sex:"man"
}
let {name,sex="wonmen"} = person;
console.log(name);  //'gjq'
console.log(sex);   //"man"

解构赋值:在一个类似于对象字面量的方式中声明多个变量,实现同时执行多个赋值的操作

注意:

  • 与数组的解构赋值不同,对象因为是无序的集合,赋值时会去匹配key值相同的变量进行赋值,而数组则是按顺序赋值。

  • 赋值的过程实际是:先找到同名属性,然后将值赋给对应的变量,真正被赋值的是后者

    let {name:baz,sex:bar}={name:'gjq',sex:"man"}
    name:name is not defined;  baz:'gjq'
    sex:sex is not defined; bar:"man"
    真正被赋值的变量是baz和bar,而不是key
    
  • 对于匹配不到的属性,值为默认值||undefined(设置默认值时应该用sex="man",而不是sex:"man")

创建对象的方式

new Object

	let obj = new Object();
	obj.name = 'gjq';
	obj.age = 15;
	obj.sayName = function(){
		console.log(this.name)
	}

对象字面量

 let obj1 = {
 	name:'gjq',
 	age:15,
 	sayName:function(){
 		console.log(this.name);
 	}
 }

工厂函数

	function person(name,age){
		let o = new Object();
		o.name = name;
		o.age = age;
		o.sayName = function(){    
			console.log(this.name)
		}
		return o;
	}

构造函数模式

	function Person(name,age){
		this.name = name;
		this.age= age;
		this.sayName = function(){
			console.log(this.name);
		}
	}

问题 : 个对象创建时都要创建一个新的sayName,浪费内存

初步解决 : 将sayName、放在全局环境中,这样所有的对象共享全局环境的那个sayName。

问题 : 污染了全局环境,没有体现封装性。

原型模式

	function Person(){}
	Person.prototype = {
		constructor:Person,
		name:'gjq',			//属性值是死的
		age:15,
		sayName:function(){
			console.log(this.name)
		},
		friends:['rcw,wzh']   		//问题所在,所有实例共享引用类型的内存地址
	}

组合使用原型和构造函数

	function Person(name,age){
		this.name = name;
		this.age= age;
		this.friends = ['rcw,wzh'];     //引用类型放在构造函数体内
	}
	Person.prototype = {
		constructor:Person,
		sayName:function(){     	//公有的属性和方法放在原型中
			console.log(this.name);
		}
	}

原型使用注意点:当改变了构造函数的prototype属性时,以前创建的对象仍然使用以前的prototype,新创建的对象使用新的prototype