JavaScript高级程序设计第八章阅读

94 阅读5分钟

《JS高程第八章 第一部分》

面向对象编程Object

8.1 理解对象

创建对象的通常方式是创建object的一个新实例,然后再给它添加属性和方法

	let person=new Object();
	person.name="JackMa";
	person.age=59;
	person.job="福报厂创始人";
	person.sayHi=function(){
		console.log("对于你们年轻人来说996是福报");
		console.log("我从没得过钱,我对钱不感兴趣。")
	}

8.1.1属性

属性分为 对象属性以及访问器属性

1、数据属性

数据属性包含一个保存数据值的位置,值会从这个位置读取,也会写入到这个位置。数据属性有四个特性描述它们的行为。 **1、[[Configurable]]:**表示属性是否可以通过delete删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。默认情况下,所有直接定义在对象上的属性的这个特性都是true

**2、[[Enumerable]]:**表示属性是否可以通过for-in进行循环,默认情况下,所有直接定义在对象上的属性的这个特性都是true

**3、[[Writable]]:**表示属性的值是否可以被修改。默认情况下,所有定义在对象上的属性的这个特性都是true

**4、[[Value]]:**包含属性实际的值。这就是前面提到的那个读取和写入属性值的位置,这个特性默认为undefined

要修改属性的默认特性,就必须使用Object.defineProperty()方法

类方法defineProperty()

**defineProperty()**会直接在对象上定义一个新属性,或者修改一个对象现有的属性,并返回此对象。

语法:defineProperty(对象,属性,描述);

	let person=new Object();
	Object.defineProperty(person,"tel",{
		Configurable:true,	//表示是否可以通过delete删除并重新定义
		Enumerbable:true,	//表示是否可以通过for-in进行循环
		Writable:true,		//表示属性的值是否可以被修改
		Value:13888888888	//
	})

2、访问器属性

访问器属性不包含数据值,相反,它们包含一个获取(getter)函数和一个设置(setter)函数,不过这两个属性都不是必需的

	Configurable:表示属性是否可以通过delete删除
	Enumerable:表示属性是否可以通过for-in循环返回。
	Get:获取函数,在读取属性时调用,默认为undefined
	Set:设置函数,在写入属性时调用。默认值为undefined

Sample:

	let book={
		name:"JS高程",
		year_:2017,
		edition:1
	}
	Object.defineProperty(book,"year",{
		get(){
			return this.year_;
		},
		set(newValue){
			if(newValue>2017){
				this.year_=newValue;
				this.edition+=newValue-2017;
			}
		}
	});
	book.year=2019;
	console.log(book.edition);

8.1.2类方法defineProperties()定义多个属性

	let book={};
	Object.defineProperties(book,{
		year_:{
			value:2017
		},
		edition:{
			value:1
		},
		year:{
			get(){
				return this.year_;
			},
			set(newValue){
				if(newValue>2017){
					this.year_=newValue;
					this.edition+=newValue-2017;
				}
			}
		}
	});

上面这段代码在book对象上定义了两个数据属性year_和edition,还有一个访问器属性year

类方法getOwnPropertyDescriptor()

方法返回制定对象上的一个自有属性对应的属性描述符,自有属性指的是直接赋予该对象的属性不需要从原型链上查找的属性

语法Object.getOwnPropertyDescriptor(obj,prop)

	let obj={
		name:"这是一个Object",
		number:110
	}
	const str=Object.getOwnPropertyDecscriptor(obj,"name");
	console.log(str.value);		//这里返回"这是一个Object"
	console.log(str.number);	//这里返回undefined

8.1.4合并对象merge

类方法Object.assign()方法 ES6新增方法

	let target={
		a:123,
		b:456
	}
	let source={
		b:345,
		c:567
	}
	obj=Object.assign(target,source);
	console.log(target);
	//返回对象{
		a:123,b:345,c:567
	}

assign实际上是浅复制,拷贝指针地址,不拷贝数据

类方法Object.is() ES6新增

判断两个对象是否为同一个值

	let num=1;
	console.log(Object.is(num,1));	//返回true
	let tr=true;
	console.log(Object.is(tr,num));	//返回false
	let nu=+0;
	console.log(Object.is(nu,0));	//返回true

**TIPS :**在JS中,数组是伪数组,本质上是一个对象。

	let a=[1,2,3];
	//用对象的写法是
	let a={
		"0":1,
		"1":2,
		"2",3,
		length:3
	}
	//a[0]a["0"]都可以调用,a[0]这里进行了隐式转换了
	console.log(a[0]);		//返回 1
	console.log(a["0"]);	//返回 1
	console.log(a.length)	//返回 3
	
	for(let i=0;i<a.lenght;i++){
		console.log(a[i]);	//返回 1 2 3 
	}

8.1.6 增强对象语法(语法糖)

1、属性值简写

	let person={
		name:"JackMa"
	}
	//
	let name="JackMa"
	let person1={
		name
	}

2、可计算属性

/这里本质上就是数组赋值对象属性/

	const nameKey="name";
	const ageKey="age";
	const jobKey="job";
	let person={};
	person[nameKey]="JackMa";
	person[ageKey]=58;
	person[jobKey]="福报厂创始人";
	
	console.log(person);
	/*	这里返回的是 {
		name:"JackMa",
		age:58,
		job:"福报厂创始人"
	}
	*/
	

记住:在JS中数组本质上是对象 C语言中,指针本质上是数组

3、简写方法名

Tip1

	let person={
		sayHello:function(name){
			console.log(`Hello,${name}`);
		}
	};
	person.sayHello('JackMa');		//返回 Hello,JackMa

Tip2

	let person={
		sayHello(name){
			console.log(`Hello,${name}`);
		}
	}
	person.sayHello('JackMa');		//返回 Hello,JackMa

Tip1和Tip2两个都一样的

8.1.7 对象解构 ES6新增

对象解构语法,可以在一条语句中使用嵌套数据实现一个或多个赋值操作。 简单地说,对象解构就是使用与对象匹配的结构来实现对象属性赋值

Sample 不使用对象解构

	let person={
		name:"JackMa",
		age:58
	};
	let personName=person.name,
		personAge=person.age;
	console.log(personName);
	console.log(personAge);

Sample 使用对象解构

	let person={
		name:'JackMa',
		age:58
	};
	let {name:personName,age:personAge}=person;
	console.log(personName);	//JackMa
	console.log(personAge);		//58

1、嵌套解构

解构对于引用嵌套的属性或赋值目标没有限制。为此,可以通过解构复制对象属性

	let person={
		name:"JackMa",
		age:58,
		job:{
			title:"福报厂创始人"
		}
	};
	let personCopy={};
	({name:personCopy.name,age:personCopy.age,job:personCopy.job}=person)
	
	console.log(person);
	//返回{name:'JackMa',age:58,job:{title:'福报厂创始人'}}
	console.log(personCopy);
	//返回{name:'JackMa',age:58,job:{title:'福报厂创始人'}}

	//下面利用嵌套解构来匹配嵌套属性
	let {job:{title}}=person;
	console.log(title);	//返回	‘福报厂创始人’

2、部分解构

如果解构存在错误,则只返回一部分

	let person={
		name:'JackMa',
		age:27
	};
	let personName,personBar,personAge;
	try{
		//person.foo是undefined所以会抛出错误
		({name:personName,foo:{bar:personBar},age:personAge}=person);
	}catch(e){
		console.log('error');
	}
	console.log(personName,personBar,personAge);
	//返回 JackMa,undefined,undefined

因为前面的personBar解构失败,所以后面的personAge也是undefined

3、函数参数上下文匹配

说成白话就是解构函数的参数arguments

	let person={
		name:'JackMa',
		age:27
	};
	function printPerson(foo,{name,age},bar){
		console.log(arguments);
		console.log(name,age);
	}

	function printPerson2(foo,{name:personName,age:personAge},bar){
		console.log(arguments);
		console.log(personName,personAge);
	}
	printPerson('fst',person,'snd');
	//返回 ‘JackMa’ 27
	printPerson2('fst',person,'snd');
	//返回 ‘JackMa’ 27