《JavaScript高级程序设计(第三版)》读书笔记03 面向对象的程序设计

版权声明:哼!坏人!这是我辛辛苦苦码的! https://blog.csdn.net/DurianPudding/article/details/85274163

对象简介

定义: 无需属性的集合,属性可以包含基本值、对象或者函数。
通俗理解: 对象是一组没有特定顺序的值,好比一组名值对,值可以是数据或者函数。

6.1 理解对象

1、 创建对象
  1. 最简单方式(不实用):创建Object实例,再添加属性和方法
var person = vew Object();
person.name = "Jay Chou";
person.age = 29;
person.job = "Singer";

person.sayName = function(){
	alert(this.name);
}
  1. 对象字面量方式(实用)
var person = {
	name: "Jay Chou",
	age: 29,
	job: "Singer",

	sayName: function(){
		alert(this.name);
	}
}; // 此处有分号
2、属性类型

只有内部才用的特性描述了属性的各种特征。特性是内部值,放在两对方括号中,例如[[Enumerable]]
ECMAScript有两种属性:数据属性和访问器属性

1. 数据属性

数据属性包含一个数据值的位置,这个位置可以读取和写入。

1.1 数据属性有4个描述其行为的特性:

  • [[Configurable]]:是否可配置:能否通过delete删除属性,能否修改属性的特性,或能否修改为访问器属性。
  • [[Enumerable]]:能否通过for-in循环返回属性。
  • [[writable]]:能否修改属性的值。
  • [[value]]:包含这个属性的数据值。读取和写入在这个位置,默认为undefined
// 举例,直接在对象上定义的属性
var person = {
	name: "Jay Chou"
}; 

例子中,只有[[value]]被设置成Jay Chou,其他特性都默认为true

1.2 修改属性默认的特性
使用Object.defineProperty()方法,接收三个参数:属性所在的对象,属性的名字,一个描述符对象。

1)修改属性值

var person = {};
Object.defineProperty(person,"name",{ // 创建一个名为name的属性
	writable: false, // 不可修改属性的值
	value: "Nicholas" // 设置值
});

alert(person.name); // "Nicholas"
person.name = "Greg";
alert(person.name); // "Nicholas"

2)不可配置的属性

var person = {};
Object.defineProperty(person,"name",{
	configurable: false, // 不能从对象中删除属性
	value: "Nicholas"
});

alert(person.name); // "Nicholas"
delete person.name;
alert(person.name); // "Nicholas"

3)不可配置不能再变为可配置
可以多次调用Object.defineProperty()修改同一个属性,但是把configurable特性设置为false之后就有限制了。

var person = {};
Object.defineProperty(person, "name", {
	configurable: false,
	value: "Nicholas"
});

// 抛出错误
Object.defineProperty(person, "name", {
	configurable: true, // 不可配置--X--可配置
	value: "Nicholas"
})
2. 访问器属性

访问器属性不包含数据值,包含一对getter setter函数。读取访问器属性时,调用getter,返回有效的值。写入时调用setter传入新值,处理数据。

2.1 访问器属性有4个特性

  • [[configurable]]
  • [[Enumerable]]
  • [[Get]]:默认为undefined
  • [[Set]]:默认为undefined

2.2 定义访问器属性
不能直接定义,要使用Object.defineProperty()定义
不一定要同时指定getter setter,只指定一个意味着另一个不能读/写

var book = { // 创建了一个book对象,定义了两个默认的属性
	_year: 2004, // _year的下划线是一种常用的几号,用于表示只能通过对象方法访问的属性
	edition: 1
};

Object.defineproperty(book, "year", { // 访问器属性year
	get: funtion(){
		return this._year;
	},
	set: funtion(newValue){
		
		if(newValue > 2004) {
			this._year = newValue;
			this.edition += newValue - 2004;
		}
	}
});

book.year = 2005; 
alert(book.edition); // 2
3、定义多个属性

Object.defineProperties(),接收两个对象参数:1. 要添加和修改其属性的对象 2. 第二个对象的属性与第一个对象中要添加或修改的属性一一对应

var book = {};
Object.definePropertyies(book, {
	_year: { // 数据属性
		writable: true,
		value:2004
	},
	edition: { // 数据属性
		writable: true,
		value: 1
	},
	year: { // 访问器属性
		get: function(){
			return this._year;
		},
		set: function(newValue){
			if(newValue > 2004) {
				this._year = newValue;
				this.edition += newValue - 2004;
			}
		}
	}
});
4、读取属性的特性

使用Object.getOwnPropertyDescriptor()方法,取得给定属性的描述符。接收两个参数:1. 属性所在的对象 2. 要读取其描述符的属性名称。返回值是一个对象。

var book = {};
Object.defineProperties(book, {
	_year: {
		value: 2004
	},
	edition: {
		value: 1
	},
	year: {
		get: function(){
			return this._year;
		},
		set: function(newValue){
			if(newValue > 2004) {
				this._year = newValue;
				this.edition += newValue - 2004;
			}
		}
	}
});

var descriptor = Object.getOwnPropertyDescriptor(book,"_year");
alert(descriptor.value); // 2004
alert(descriptor.configurable); // false
alert(typeof descriptor.get); // "undefined"

var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value); // undefined
alert(descriptor.enumerable); //false
alert(typeof descriptor.get);  // "function"

6.2 创建对象

创建单个对象可以用6.1中 Object构造函数或对象字面量方法,但是创建多个对象时重复使用一个接口会产生大量的重复代码。为了解决这个问题,使用工厂模式的一种变体。

1、 工厂模式

因为在ECMAScript中无法创建类,开发人员发明一种函数来封装以特定接口创建对象的细节。

function createPerson(name, age, job){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function(){
    console.log(this.name);
  };
  return o;
}

var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
console.log(person1.name);
console.log(person2);

输出:

Nicholas
{ name: 'Greg', age: 27, job: 'Doctor', sayName: [Function] }

工厂模式解决了创建多个相似对象的问题,没有解决对象识别的问题(即怎样知道一个对象的类型)。

2、 构造函数模式

创建自定义的构造函数

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

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

console.log(person1.age);
console.log(person2);

输出:

29
Person { name: 'Greg', age: 27, job: 'Doctor', sayName: [Function] }

构造函数模式和工厂模式的不同之处:

  • 没有显示的创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句

构造函数特点:

  • 开头大写字母
  • 创建新实例要用new操作符

调用构造函数经历的步骤:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(this指向了新对象)
  • 执行构造函数中的代码
  • 返回新对象

检测类型

  1. 构造函数属性:constructor
    person1和person2分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性,该属性指向Person。
console.log(person1.constructor === Person);
console.log(person2.constructor === Person);

输出:

true
true
  1. instanceof可以更准确的检测对象类型
    这个例子中,创建的所有对象,既是Object的实例,又是Person的实例。因为所有对象均继承自Object
console.log(person1 instanceof Object); // true
console.log(person1 instanceof Person); // true
console.log(person2 instanceof Object); // true
console.log(person2 instanceof Person); // true

构造函数模式 vs 工厂模式
构造函数模式可以将实例标识为一种特定的类型。



猜你喜欢

转载自blog.csdn.net/DurianPudding/article/details/85274163