`

JavaScript学习之二 — JavaScript创建对象的8种方式

阅读更多
本文列举了《JavaScript高级程序设计:第二版》书中讲到的8种创建JavaScript对象的模式,这里有英文版下载

代码里边用到的一些公用方法本文后边有附
1、最简单的方式
/******************************************************************************************
 * 1、最简单的方式
 * 缺点:如果创建类似的对象,会出现大量的重复代码
 */
var person1 = new Object();
person1.nickname = 'maitian';
person1.age = 27;
person1.address = 'bj';
person1.getNickName = function() {
	return this.nickname
};
printPerson('1、最简单的方式', person1);

输出:
1、最简单的方式	 nickname: maitian, age: 27, address: bj

2、工厂模式
/*****************************************************************************************
 * 2、工厂模式
 * 优点:针对1存在的问题,解决代码重复
 * 缺点:
 * 	a、未解决对象识别问题,即该对象是什么类型
 *  b、每次创建对象,getNickName函数都会运行一次
 * @param {String} nickname
 * @param {number} age
 * @param {String} address
 * @return {Object}
 */
function createObject(nickname, age, address) {
	var person = new Object();
	person.nickname = nickname;
	person.age = age;
	person.address = address;
	person.getNickName = function() {
		return this.nickname
	};
	return person;
}
var person2 = createObject('maitian', 27, 'sz');
printPerson('2、工厂模式', person2);

输出:
2、工厂模式	 nickname: maitian, age: 27, address: sz

3、构造函数模式
/******************************************************************************************
 * 3、构造函数模式
 * 优点:解决第2中的缺点b提到的对象识别问题
 * 缺点:
 * 	 a、如同2中的缺点b,每次创建对象,getNickName函数都会运行一次
 * 	 b、如果创建对象的时候忘记了new,直接写成了var person = Person3('nickname',24,'address'),
 * 		person则为undefined
 * @param {String} nickname
 * @param {number} age
 * @param {String} address
 */
function Person3(nickname, age, address) {
	this.nickname = nickname;
	this.age = age;
	this.address = address;
	this.getNickName = function() {
		return this.nickname;
	}
};
var person3 = new Person3('maitian', 27, 'zz');
printPerson('3、构造函数模式', person3);
printMessage("  person3 instanceof Person3: " + (person3 instanceof Person3));
// 这里person3为undefined
person3 = Person3('maitian',24,'zz');

/**
 * 3.1、对构造函数模式的改进之一
 * 优点:解决了3中缺点a存在的每次创建对象都创建一个getNickName函数问题
 * 缺点:
 *  a、创建一个全局函数,别的地方几乎不会用到的
 *  b、依然存在3中缺点b
 * @param {String} nickname
 * @param {number} age
 * @param {String} address
 */
function Person31(nickname, age, address) {
	this.nickname = nickname;
	this.age = age;
	this.address = address;
	this.getNickName = getNickName;
};
var getNickName = function(){
	return this.nickname;
};
var person31 = new Person31('maitian', 27, 'zz');
printPerson('\t3.1、对构造函数模式的改进之一', person31);
printMessage("\t  person31 instanceof Person31: " + (person31 instanceof Person31));

//《JavaScript高级程序设计》第二版第18.1.1节中给出的解决方法
/**
 * 3.2、对构造函数模式的改进之二
 * 优点:解决了3中缺点b
 * 缺点:如3中缺点a
 * @param {} nickname
 * @param {} age
 * @param {} address
 * @return {}
 */
function Person32(nickname, age, address) {
	if (this instanceof Person32) {
		this.nickname = nickname;
		this.age = age;
		this.address = address;
		this.getNickName = function() {
			return this.nickname;
		}
	} else {
		return new Person32(nickname, age, address);
	}

};
var person32 = new Person32('maitian', 27, 'zz');
printPerson('\t3.2、对构造函数模式的改进之二', person32);
printMessage("\t  person32 instanceof Person32: " + (person32 instanceof Person32));

输出:
3、构造函数模式	 nickname: maitian, age: 27, address: zz
  person3 instanceof Person3: true
	3.1、对构造函数模式的改进之一	 nickname: maitian, age: 27, address: zz
	  person31 instanceof Person31: true
	3.2、对构造函数模式的改进之二	 nickname: maitian, age: 27, address: zz
	  person32 instanceof Person32: true

4、原型模式
/*****************************************************************************************
 * 4、原型模式
 * 优点:解决3.1中缺点里提到的全局函数问题
 * 缺点:
 *   a、如果用字面量重设原型,则在重设原型之前创建的对象所指向的原型不会被改为这个字面量对象,如4.1所示
 *   b、通过这种方式创建的对象的默认字段值都相同
 *   c、如果原型的字段是引用类型,那么所有实例都指向同一引用,一个实例的修改别的实例也能看到
 */
var Person4 = function() {
};
Person4.prototype = {
	constructor : Person4,
	nickname : 'maitian',
	age : 27,
	address : 'gw',
	jobs : ['designer','farmer'],
	getNickName : function() {
		return this.nickname;
	}
};
var person41 = new Person4();
var person42 = new Person4();
printPerson('4、原型模式 - before person41.jobs.push', person41);
printPerson('4、原型模式 - before person41.jobs.push', person42);
printMessage("  person41 instanceof Person4: " + (person41 instanceof Person4));
person41.jobs.push('programmer');
printPerson('4、原型模式 - after person41.jobs.push', person41);
printPerson('4、原型模式 - after person41.jobs.push', person42);
/**
 * 4.1、原型模式存在的问题之一
 * 	如果用字面量重设原型,则在重设原型之前创建的对象所指向的原型不会被改为这个字面量对象,如4.1所示
 */
var Person41 = function() {
};
var person41 = new Person41();
Person41.prototype = {
	constructor : Person41,
	nickname : 'maitian',
	age : 27,
	address : 'gw',
	getNickName : function() {
		return this.nickname;
	}
};
printPerson('\t4.1、原型模式存在的问题之一', person41);
//注意连这里的instanceof都返回为false
printMessage("\t  person41 instanceof Person41: " + (person41 instanceof Person41));

/**
 * 4.2、原型模式存在的问题之一的解决办法
 * 	不用字面量设置原型
 */
var Person42 = function() {
};
var person42 = new Person42();
Person42.prototype.nickname = 'maitian';
Person42.prototype.age = 27;
Person42.prototype.address = 'gw';
Person42.prototype.getNickName = function() {
	return this.nickname;
};
printPerson('\t4.2、型模式存在的问题之一的解决办法', person42);
printMessage("\t  person42 instanceof Person42: " + (person42 instanceof Person42));

/**
 * 4.3、原型模式存在的问题之二
 *  通过这种方式创建的对象的默认字段值都相同,并且这些属性都是原型的属性而非实例的属性
 */
var Person43 = function() {
};
Person43.prototype.nickname = 'maitian';
Person43.prototype.age = 27;
Person43.prototype.address = 'gw';
Person43.prototype.getNickName = function() {
	return this.nickname;
};
var person431 = new Person43();
var person432 = new Person43();
printPerson('\t4.3、型模式存在的问题之二', person431);
printPerson('\t4.3、型模式存在的问题之二', person432);
printMessage("\t  person431 instanceof Person42: " + (person431 instanceof Person43));
printMessage("\t  'nickname' in Person43: - before (person431.nickname = 'yueye') " + ('nickname' in Person43));
printMessage("\t  person431.hasOwnProperty('nickname'): - before (person431.nickname = 'yueye') " + person431.hasOwnProperty('nickname'));
person431.nickname = 'yueye';
printMessage("\t  'nickname' in Person43: - after (person431.nickname = 'yueye') " + ('nickname' in Person43));
printMessage("\t  person431.hasOwnProperty('nickname'): - after (person431.nickname = 'yueye') " + person431.hasOwnProperty('nickname'));

输出:
4、原型模式 - before person41.jobs.push	 nickname: maitian, age: 27, address: gw,jobs: designer,farmer
4、原型模式 - before person41.jobs.push	 nickname: maitian, age: 27, address: gw,jobs: designer,farmer
  person41 instanceof Person4: true
4、原型模式 - after person41.jobs.push	 nickname: maitian, age: 27, address: gw,jobs: designer,farmer,programmer
4、原型模式 - after person41.jobs.push	 nickname: maitian, age: 27, address: gw,jobs: designer,farmer,programmer
	4.1、原型模式存在的问题之一	 nickname: undefined, age: undefined, address: undefined
	  person41 instanceof Person41: false
	4.2、型模式存在的问题之一的解决办法	 nickname: maitian, age: 27, address: gw
	  person42 instanceof Person42: true
	4.3、型模式存在的问题之二	 nickname: maitian, age: 27, address: gw
	4.3、型模式存在的问题之二	 nickname: maitian, age: 27, address: gw
	  person431 instanceof Person42: true
	  'nickname' in Person43: - before (person431.nickname = 'yueye') false
	  person431.hasOwnProperty('nickname'): - before (person431.nickname = 'yueye') false
	  'nickname' in Person43: - after (person431.nickname = 'yueye') false
	  person431.hasOwnProperty('nickname'): - after (person431.nickname = 'yueye') true

5、构造函数模式和原型模式的组合
/*****************************************************************************************
 * 5、构造函数模式和原型模式的组合
 * 优点:
 * 	a、解决4中缺点b
 * 	b、解决4中缺点c
 * 缺点:
 * 	a、如果原型对象通过字面量创建依然存在4中缺点a的问题
 *  b、构造函数和原型需要分开写,比起Java语言,不够简洁
 */
function Person5(nickname, age, address) {
	this.nickname = nickname;
	this.age = age;
	this.address = address;
	this.jobs = ['designer','farmer'];
};
Person5.prototype.getNickName = function() {
	return this.nickname;
};
var person5 = new Person5('maitian', 27, 'zz');
var person52 = new Person5('maitian2', 27, 'zz2');
printPerson('5、构造函数模式和原型模式的组合 - before person5.jobs.push', person5);
printPerson('5、构造函数模式和原型模式的组合 - before person5.jobs.push', person52);
printMessage("\t  person5 instanceof Person5: " + (person5 instanceof Person5));
printMessage("\t  'nickname' in Person5: - before (person5.nickname = 'yueye') " + ('nickname' in Person5));
printMessage("\t  person5.hasOwnProperty('nickname'): - before (person5.nickname = 'yueye') " + person5.hasOwnProperty('nickname'));
person5.jobs.push("programmer");
printPerson('5、构造函数模式和原型模式的组合 - after person5.jobs.push', person5);
printPerson('5、构造函数模式和原型模式的组合 - after person5.jobs.push', person52);

输出:
5、构造函数模式和原型模式的组合 - before person5.jobs.push	 nickname: maitian, age: 27, address: zz,jobs: designer,farmer
5、构造函数模式和原型模式的组合 - before person5.jobs.push	 nickname: maitian2, age: 27, address: zz2,jobs: designer,farmer
	  person5 instanceof Person5: true
	  'nickname' in Person5: - before (person5.nickname = 'yueye') false
	  person5.hasOwnProperty('nickname'): - before (person5.nickname = 'yueye') true
5、构造函数模式和原型模式的组合 - after person5.jobs.push	 nickname: maitian, age: 27, address: zz,jobs: designer,farmer,programmer
5、构造函数模式和原型模式的组合 - after person5.jobs.push	 nickname: maitian2, age: 27, address: zz2,jobs: designer,farmer

6、动态原型模式
/*****************************************************************************************
 * 6、动态原型模式
 * 优点:适当缓解了5中的缺点b
 * 缺点:依然存在5中的缺点a,不能用字面量重置原型对象
 */
function Person6(nickname, age, address) {
	this.nickname = nickname;
	this.age = age;
	this.address = address;
	if (!this.getNickName) {
		Person6.prototype.getNickName = function() {
			return this.nickname;
		}
	}
};
var person6 = new Person6('maitian', 27, 'gz');
printPerson('6、动态原型模式', person6);
printMessage("\t  person6 instanceof Person6: " + (person6 instanceof Person6));
printMessage("\t  'nickname' in Person6:" + ('nickname' in Person6));
printMessage("\t  person6.hasOwnProperty('nickname'): " + person6.hasOwnProperty('nickname'));

输出:
6、动态原型模式	 nickname: maitian, age: 27, address: gz
	  person6 instanceof Person6: true
	  'nickname' in Person6:false
	  person6.hasOwnProperty('nickname'): true

7、寄生构造函数模式
/*****************************************************************************************
 * 7、寄生构造函数模式
 *	优点:可以快速创建对象
 *  缺点:
 *   a、如同2的缺点a,未能解决对象的识别问题
 *   b、如同2的缺点b,每创建一个对象都会运行一次function
 *   c、如果适用new去创建对象,实际上是创建了两个对象
 */
function Person7(nickname,age,address){
	var person = new Object();
	person.nickname = nickname;
	person.age = age;
	person.address = address;
	person.getNickName = function() {
		return this.nickname
	};
	return person;
};
var person7 = new Person7('maitian', 27, 'tj');
printPerson('7、寄生构造函数模式', person7);
printMessage("\t  person7 instanceof Person7: " + (person7 instanceof Person7));
printMessage("\t  'nickname' in Person7: " + ('nickname' in Person7));
printMessage("\t  person7.hasOwnProperty('nickname'): " + person7.hasOwnProperty('nickname'));
//这里不用new跟用new是一样的
person7 = Person7('maitian', 27, 'tj');
printPerson('7、寄生构造函数模式存在问题之一的验证', person7);


输出:
7、寄生构造函数模式	 nickname: maitian, age: 27, address: tj
	  person7 instanceof Person7: false
	  'nickname' in Person7: false
	  person7.hasOwnProperty('nickname'): true
7、寄生构造函数模式存在问题之一的验证	 nickname: maitian, age: 27, address: tj

8、稳妥构造函数模式
/*****************************************************************************************
 * 8、稳妥构造函数模式
 * 优点:适合用在安全环境,即不能适用this和new的环境
 * 缺点:
 *  a、如同2的缺点a,未能解决对象的识别问题
 *  b、如同2的缺点b,每创建一个对象都会运行一次function
 *  c、可以不使用new创建,如果用new则存在7中缺点c
 */
function Person8(nickname,age,address){
	var person = new Object();
	person.getNickName = function() {
		return nickname
	};
	person.getAge = function(){
		return age;
	};
	person.getAddress = function(){
		return address;
	};
	return person;
};
var person8 = new Person8('maitian', 27, 'km');
printPerson('8、稳妥构造函数模式', person8);
printMessage("\t  person8 instanceof Person8: " + (person8 instanceof Person8));
printMessage("\t  'nickname' in Person8: " + ('nickname' in Person8));
printMessage("\t  person8.hasOwnProperty('nickname'): " + person8.hasOwnProperty('nickname'));

输出:
8、稳妥构造函数模式	 nickname: maitian, age: 27, address: km
	  person8 instanceof Person8: false
	  'nickname' in Person8: false
	  person8.hasOwnProperty('nickname'): false



附:用到的公用方法
/*--------------------------一些工具方法-----------------------*/
/**
 * Chrome浏览器不支持doPrintPerson函数,会抛出Uncaught TypeError: Illegal invocation异常,不知道为何
 */
var isChrome = function() {
	return /\bchrome\b/.test(navigator.userAgent.toLowerCase());
}();
function printPerson(type, person) {
	var nickname = person.getNickName ? person.getNickName() : person.nickname,
		age = person.getAge ? person.getAge() : person.age,
		address = person.getAddress ? person.getAddress() : person.address,
		jobs = person.getJobs ? person.getJobs() : person.jobs ;
	var message = type + "\t nickname: " + nickname + ", age: " + age + ", address: " + address;
	if(jobs){
		message += ",jobs: " + jobs.join(',');
	}
	printMessage(message);

};
/**
 * 延迟载入函数
 * 
 * @param {}  message
 */
var printMessage = function(message) {
	if (isChrome) {
		//chrome不支持延迟载入函数
		console.info(message);
	} else {
		if (typeof console == 'object') {
			// ie8, chrome, firefox, safari
			printMessage = console.info;
		} else if (typeof opera == 'object') {
			// opera
			printMessage = opera.postError;
		} else if (typeof java == 'object' && typeof java.lang == 'object') {
			// LiveConect java控制台,firefox,safari,opera支持此方式
			printMessage = java.lang.System.println;
		} else {
			printMessage = function() {
				alert('printPerson无法将信息输出到控制台');
			}
		}
		printMessage(message);
	}
};
分享到:
评论

相关推荐

    javascript创建对象的方式(二)

    这篇博客“javascript创建对象的方式(二)”可能详细介绍了在JavaScript中除了最基础的字面量语法之外的其他创建对象的方法。这里我们将深入探讨几种常见的创建对象的方式。 1. **构造函数**: JavaScript中的...

    javascript创建对象的方式(三)

    在JavaScript这门动态类型的编程语言中,创建对象是其核心特性之一。本文将详细探讨三种主要的创建JavaScript对象的方法,并结合“源码”与“工具”的概念,来深入理解这些方式在实际开发中的应用。 一、字面量...

    JavaScript学习笔记之创建对象_.docx

    在JavaScript中,对象是核心概念之一,它们是无序属性的集合,允许我们存储和操作数据。对象的属性可以是基本值(如字符串、数字、布尔值)或更复杂的对象和函数,使得JavaScript具备强大的数据结构和面向对象编程...

    面向对象JavaScript精要(英文原版pdf)

    - **第三章:JavaScript中的类和对象**:详细介绍如何使用JavaScript创建类和对象。 - **第四章:继承**:探讨JavaScript中实现继承的不同方式。 - **第五章:封装和私有性**:讲解如何在JavaScript中实现封装以及...

    javascript如何创建对象

    JavaScript创建对象的方法主要有以下几种: 一、直接创建 直接创建是通过new Object()来创建一个新的空对象,然后逐步给这个对象添加属性和方法。例如,创建一个名为person1的对象,并添加name、gender属性,以及一...

    javascript创建对象的方式(一)

    这篇博文主要探讨了JavaScript创建对象的几种常见方式,这对于理解和掌握JavaScript面向对象编程至关重要。在实际开发中,了解并灵活运用这些方法能够提高代码的可读性和可维护性。下面,我们将详细讲解标题中提到的...

    JavaScript创建对象的七种方式(推荐)

    JavaScript创建对象的方式有很多,通过Object构造函数或对象字面量的方式也可以创建单个对象,显然这两种方式会产生大量的重复代码,并不适合量产。接下来介绍七种非常经典的创建对象的方式,他们也各有优缺点。 ...

    【JavaScript源代码】详解js创建对象的几种方式和对象方法.docx

    本文将深入探讨JavaScript中创建对象的几种常见方式以及对象方法。 首先,我们来看“工厂模式”。工厂模式是一种创建对象的抽象方式,通过一个函数来返回一个新的对象。例如: ```javascript function getObj(name...

    javascript对象创建

    首先,让我们从最基础的创建对象的方式开始。在JavaScript中,可以使用字面量语法来创建一个简单的对象: ```javascript var obj = { name: 'John', age: 30, sayHello: function() { console.log('Hello, ' + ...

    javascript面向对象创建对象的方式小结.docx

    本文将详细介绍JavaScript中创建对象的七种常见方式,并给出具体的示例代码。 #### 二、通过内置`Object`对象的方式创建 这是最简单直接的方式之一,通过`new Object()`创建一个空对象,之后通过点语法为其添加属性...

    Javascript面向对象编程.

    在JavaScript中,面向对象主要通过以下三种方式实现: 1. **构造函数(Constructor)**:构造函数是一种特殊的函数,用于创建和初始化对象。我们可以通过`new`关键字来调用构造函数,创建一个新的对象实例。例如: ...

    在javascript中创建对象的各种模式解析

    工厂模式是最早期的对象创建方式之一,它通过一个函数来创建对象,并返回新创建的对象。这种方法的核心是利用函数封装创建对象的细节,然后通过返回值来创建对象实例。工厂模式的优点是解决了创建多个具有相同属性和...

    JavaScript学习笔记,javascript基础知识,基础语法整理.pdf

    JavaScript是一种高级的、动态的、基于对象的客户端脚本语言。它是在网页上执行的脚本语言,能实现网页的交互功能。下面是该资源中的重要知识点总结: 一、 JavaScript 基本概念 * JavaScript是一种基于对象的脚本...

    JavaScript对象创建总结

    javascript对象创建方法总结,通过这些方法的总结,可以对对象有了更深一步的了解,也加深了对对象的巩固认识。

    javascript中数组、对象

    创建对象的方式有以下几种: 1. 对象字面量: ```javascript var obj = {}; // 创建空对象 var obj = {name: 'Alice', age: 30}; // 创建包含属性的对象 ``` 2. 构造函数: ```javascript var obj = new ...

    javascript创建对象的方式(四)

    以上就是JavaScript创建对象的六种常见方式,每种都有其适用场景和优缺点。理解并熟练掌握这些方法,能够帮助你编写出更加灵活、可维护的代码。在实际项目中,根据需求选择合适的方法,可以提升代码质量和效率。

    JavaScript学习指南 源代码

    JavaScript,一种广泛应用于Web开发的脚本语言,是前端开发的核心技术之一。它以其灵活性、动态性和丰富的交互性,使得网页不再仅仅是静态的HTML,而是能够动态响应用户操作,提供丰富的用户体验。本“JavaScript...

Global site tag (gtag.js) - Google Analytics