`

javascript创建对象的几种方法

 
阅读更多

 

面向对象的语言大都有一个类的概念,通过类可以创建多个具有相同方法和属性的对象。虽然从技术上讲,javascript是一门面向对象的语言,但是javascript没有类的概念,一切都是对象。任意一个对象都是某种引用类型的实例,都是通过已有的引用类型创建;引用类型可以是原生的,也可以是自定义的。原生的引用类型有:Object、Array、Data、RegExp、Function。

 

!引用类型就是一种数据结构,将数据和功能组织在一起,通常被称为类。

 

缺乏类概念的javascript中,需要解决的问题就是如何高效的创建对象。

 

1.1.0.创建对象的一般方法

 

var person = {}; //对象字面量表示,等同于var person = new Objcect();

 

person.name = 'evansdiy';

person.age = '22';

person.friends = ['ajiao','tiantian','pangzi'];

person.logName = function() {

    console.log(this.name);

}

基于Object引用类型,创建了一个对象,该对象包含四个属性,其中一个为方法。如果需要很多类似person的实例,那就会有许多重复的代码。

 

1.1.1.工厂模式 [top]

 

通过一个可以包含了对象细节的函数来创建对象,然后返回这个对象。

 

function person(name,age,friends) {

 

    var o = {

        name: name,

        age: age,

        friends: friends,

        logName: function() {

            console.log(this.name);

        }

    };

 

    return o;

 

}

 

var person1 = person('Evansdiy','22',['ajiao','tiantian','pangzi']);

每次调用person函数,都会通过该函数内部的对象o创建新的对象,然后返回,除此之外,这个为了创建新对象而存在的内部对象o没有其他的用途。另外,无法判断工厂模式创建的对象的类型。

 

1.1.2.构造函数模式 [top]

 

function Person(name,age,job) {

 

    this.name = name;

    this.age = age;

    this.job = job;

    this.logName = function() {

        console.log(this.name);

    }

 

}

 

 

//通过new操作符创建Person的实例

var person1 = new Person('boy-a','22','worker');

 

var person2 = new Person('girl-b','23','teacher');

 

person1.logName(); //boy-a

 

person2.logName(); //girl-a

对比工厂模式,可以发现,这里并不需要创建中间对象,没有return。另外,可以将构造函数的实例标识为一种特定的类型,这就解决了对象识别的问题(通过检查实例的constructor属性,或利用instanceof操作符检查该实例是否通过某个构造函数创建)。

 

console.log(person1.constructor == Person);//constructor位于构造函数原型中,并指向构造函数,结果为true

 

console.log(person1 instanceof Person);//通过instanceof操作符,判断person1是否为构造函数Person的实例

但构造函数模式也有自己的问题,实际上,logName方法在每个实例上都会被重新创建一次,需要注意的是,通过实例化创建的方法且并不相等,以下代码将会得到false:

 

console.log(person1.logName == person2.logName);//false

我们可以将方法移到构造器外部(变为全局函数)来解决这个问题:

 

function logName() {

    console.log(this.name);

}

 

function logAge() {

    console.log(this.age);

}

但是,在全局下创建的全局函数实际上只能被经由Person创建的实例调用,这就有点名不副实了;如果方法很多,还需要逐一定义,缺少封装性。

 

1.1.3.原型模式 [top]

 

javascript中的每一个函数都包含一个指向prototype属性的指针(大部分浏览器可以通过内部属性__proto__访问),prototype属性是一个对象,其中包含了由某种引用类型创建的所有实例共享的属性和方法。

 

function Person() {}

 

Person.name = 'evansdiy';

 

Person.prototype.friends = ['ajiao','jianjian','pangzi'];

 

Person.prototype.logName = function() {

    console.log(this.name);

}

 

var person1 = new Person();

 

person1.logName();//'evansdiy'

以上代码做了这几件事情:

 

1.定义了一个构造函数Person,Person函数自动获得一个prototype属性,该属性默认只包含一个指向Person的constructor属性;

 

2.通过Person.prototype添加三个属性,其中一个作为方法;

 

3.创建一个Person的实例,随后在实例上调用了logName()方法。

 

!这里需要注意的是logName()方法的调用过程:

 

1.在person1实例上查找logName()方法,发现没有这个方法,于是追溯到person1的原型

 

2.在person1的原型上查找logame()方法,有这个方法,于是调用该方法

 

基于这样一个查找过程,我们可以通过在实例上定义原型中的同名属性,来阻止该实例访问原型上的同名属性,需要注意的是,这样做并不会删除原型上的同名属性,仅仅是阻止实例访问。

 

var person2 = new Person();

 

person2.name = 'laocai';

如果我们不再需要实例上的属性时,可以通过delete操作符删除。

 

delete person2.name;

利用for-in循环枚举出实例可以访问到的所有属性(不论该属性存在于实例或是原型中):

 

for(i in person1) {

    console.log(i);

}

同时,也可以利用hasOwnProperty()方法判断某个属性到底存在于实例上,还是存在于原型中,只有当属性存在于实例中,才会返回true:

 

console.log(person1.hasOwnProperty('name'));//true

!hasOwnProperty来自Object的原型,是javascript中唯一一个在处理属性时不查找原型链的方法。

 

另外,也可以通过同时使用in操作符和hasOwnProperty()方法来判断某个属性存在于实例中还是存在于原型中:

 

console.log(('friends' in person1) && !person1.hasOwnProperty('friends'));

先判断person1是否可以访问到friends属性,如果可以,再判断这个属性是否存在于实例当中(注意前面的!),如果不存在于实例中,就说明这个属性存在于原型中。

 

前面提到,原型也是对象,所以我们可以用对象字面量表示法书写原型,之前为原型添加代码的写法可以修改为:

 

Person.prototype = {

 

    name: 'evansdiy',

    friends: ['ajiao','jianjian','pangzi'],

    logName: function() {

        console.log(this.name);  

    }

 

}

由于对象字面量语法重写了整个prototype原型,原先创建构造函数时默认取得的constructor属性会指向Object构造函数:

 

//对象字面量重写原型之后

console.log(person1.constructor);//Object

不过,instanceof操作符仍会返回希望的结果:

 

//对象字面量重写原型之后

console.log(person1 instanceof Person);//true

当然,可以在原型中手动设置constructor的值来解决这个问题。

 

Person.prototype = {

 

    constructor: Person,

    ......

 

}

如果在创建对象实例之后修改原型对象,那么对原型的修改会立即在所有对象实例中反映出来:

 

function Person() {};

 

var person1 = new Person();

 

Person.prototype.name = 'evansdiy';

 

console.log(person1.name);//'evansdiy'

实例和原型之间的连接仅仅是一个指针,而不是一个原型的拷贝,在原型实际上是一次搜索过程,对原型对象的所做的任何修改都会在所有对象实例中反映出来,就算在创建实例之后修改原型,也是如此。

 

如果在创建对象实例之后重写原型对象,情况又会如何?

 

function Person() {};

 

var person1 = new Person1();//创建的实例引用的是最初的原型

 

//重写了原型

Person.prototype = {

    friends: ['ajiao','jianjian','pangzi']

}

 

var person2 = new Person();//这个实例引用新的原型

 

console.log(person2.friends);

 

console.log(person1.friends);

以上代码在执行到最后一行时会出现未定义错误,如果我们用for-in循环枚举person1中的可访问属性时,会发现,里头空无一物,但是person2却可以访问到原型上的friends属性。

 

!重写原型切断了现有原型与之前创建的所有对象实例的联系,之前创建的对象实例的原型还在,只不过是旧的。

 

//创建person1时,原型对象还未被重写,因此,原型对象中的constructor还是默认的Person()

console.log(person1.constructor);//Person()

 

//但是person2的constructor指向Object()

console.log(person2.constructor);//Object()

需要注意的是,原型模式忽略了为构造函数传递参数的过程,所有的实例都取得相同的属性值。同时,原型模式还存在着一个很大的问题,就是原型对象中的引用类型值会被所有实例共享,对引用类型值的修改,也会反映到所有对象实例当中。

 

function Person() {};

 

Person.prototype = {

    friends: ['ajiao','tiantian','pangzi']

}

 

var person1 = new Person();

 

var person2 = new Person();

 

person1.friends.push('laocai');

 

console.log(person2.friends);//['ajiao','tiantian','pangzi','laocai']

修改person1的引用类型值friends,意味着person2中的friends也会发生变化,实际上,原型中保存的friends实际上只是一个指向堆中friends值的指针(这个指针的长度是固定的,保存在栈中),实例通过原型访问引用类型值时,也是按指针访问,而不是访问各自实例上的副本(这样的副本并不存在)。

 

1.1.4.结合构造函数和原型模式创建对象 [top]

 

结合构造函数和原型模式的优点,弥补各自的不足,利用构造函数传递初始化参数,在其中定义实例属性,利用原型定义公用方法和公共属性,该模式应用最为广泛。

 

function Person(name,age) {

 

    this.name = name;

    this.age = age;

    this.friends = ['ajiao','jianjian','pangzi'];

 

}

 

Person.prototype = {

 

    constructor: Person,

    logName: function() {

        console.log(this.name);

    }

 

}

 

var person1 = new Person('evansdiy','22');

 

var person2 = new Person('amy','21');

 

person1.logName();//'evansdiy'

 

person1.friends.push('haixao');

 

console.log(person2.friends.length);//3

1.1.5.原型动态模式 [top]

 

原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

 

function Person(name,age) {

 

    this.name = name;

    this.age = age;

 

    if(typeof this.logName != 'function') {

        Person.prototype.logName = function() {

            console.log(this.name);

        };

        Person.prototype.logAge = function() {

            console.log(this.age);

        };

    };

 

}

 

var person1 = new Person('evansdiy','22');//初次调用构造函数,此时修改了原型

 

var person2 = new Person('amy','21');//此时logName()方法已经存在,不会再修改原型

需要注意的是,该模式不能使用对象字面量语法书写原型对象(这样会重写原型对象)。若重写原型,那么通过构造函数创建的第一实例可以访问的原型对象不会包含if语句中的原型对象属性。

 

function Person(name,age) {

 

    this.name = name;

    this.age = age;

 

    if(typeof this.logName != 'function') {

        Person.prototype = {

            logName: function() {

                console.log(this.name);

            },

            logAge: function() {

                console.log(this.Age);

            }

        }

    };

 

}

 

var person1 = new Person('evansdiy','22');

 

var person2 = new Person('amy','21');

 

person2.logName();//'amy'

 

person1.logName();//logName()方法不存在

需要说明的是,各模式都有自己的应用场景,无所谓优劣。

 

原文网址:http://www.evansdiy.com/tips/create+object+in+javascript

分享到:
评论

相关推荐

    javascript创建对象的方式(二)

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

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

    本文将深入探讨JavaScript创建对象的8种常见方式,帮助你更好地理解和掌握这门动态类型的编程语言。 1. **字面量(Literal)方式** 这是最简单直接的创建对象的方式,通过大括号{}来定义一个对象,然后在内部用...

    javascript如何创建对象

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

    javascript创建对象的方式(一)

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

    javascript创建对象的3种方法

    总结来说,JavaScript创建对象的方法有多种,每种都有其适用的场景。JSON对象适合临时使用,`Object`实例适合简单场景,而构造函数及原型链则更适合构建复杂的、可复用的对象模型。在实际开发中,应根据项目需求选择...

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

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

    javascript中创建对象的几种方法总结

    在JavaScript中,有几种常见的创建对象的方法,这里我们将详细探讨这些方法。 1. **对象字面量**:这是最简单且直观的创建对象的方式。通过大括号 `{}` 创建一个空对象,然后通过点`.`或方括号`[]`来添加属性和方法...

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

    在JavaScript中创建对象主要涉及以下几种模式: 1. 工厂模式 工厂模式是最早期的对象创建方式之一,它通过一个函数来创建对象,并返回新创建的对象。这种方法的核心是利用函数封装创建对象的细节,然后通过返回值来...

    JS 创建对象(常见的几种方法)

    下面我们逐一分析给定文件中所提到的几种创建对象的方法。 首先是使用构造函数模式创建对象。构造函数是JavaScript中一种非常常见的创建对象的方式。通过定义一个具有共同属性和方法的构造函数,我们可以使用new...

    javascript面向对象编程的几种模式详解

    以下是对标题和描述中提到的几种JavaScript面向对象编程模式的详细解释: 1. **构造函数与字面量结合模式** 在JavaScript中,我们可以通过构造函数和字面量语法来创建对象。构造函数用于定义对象的类型,而字面量...

    JAVASCRIPT 面向对象编程精要

    JavaScript提供了几种面向对象的机制,包括继承和封装。 ##### 4.1 封装 JavaScript中的封装主要通过闭包实现。例如,可以创建一个返回私有属性和方法的对象的函数: ```javascript function createPerson(name, ...

    JavaScript面向对象的支持

    JavaScript中的面向对象特性主要体现在以下几个方面: 1. **基于原型的对象模型**: JavaScript采用的是基于原型的继承机制,而不是类的继承。这意味着每个对象都有一个`__proto__`属性,指向它的构造函数的原型...

    js面向对象之常见创建对象的几种方式(工厂模式、构造函数模式、原型模式).docx

    ### JavaScript面向对象之常见创建对象的方式 #### 引言 JavaScript 的灵活性体现在其创建对象的多种方式上。本文将详细介绍三种常见的对象创建方法:工厂模式、构造函数模式以及原型模式,并探讨它们各自的优缺点...

    javascript中数组、对象

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

    javascript对象参考手册

    此外,还会讲解字面量语法和构造函数两种创建对象的方式,以及原型、原型链和`__proto__`属性的用法。 接下来,手册会深入讨论JavaScript内置对象,如Array、Date、Math、String等,这些对象提供了处理数组、日期、...

    JAVASCRIPT中定义对象的几种方式.pdf

    `Object.create()`方法用于创建一个新对象,使用现有对象作为新创建对象的原型。 ```javascript let personProto = { greet: function() { console.log('Hello, my name is ' + this.name); } }; let person = ...

    JavaScript 三种创建对象的方法

    JavaScript中对象的创建有以下几种方式: (1)使用内置对象 (2)使用JSON符号 (3)自定义对象构造 一、使用内置对象 JavaScript可用的内置对象可分为两种: 1,JavaScript语言原生对象(语言级对象),如String、...

    deePool高效的JavaScript对象池

    2. 创建对象池:使用`DeePool.createPool()`方法创建指定类型的对象池。 3. 分配对象:使用`pool.get()`从池中获取对象。 4. 归还对象:完成使用后,通过`pool.put(obj)`将对象归还到池中。 5. 销毁对象池:在不再...

    javascript创建对象的几种模式介绍

    构造函数模式是一种通过使用 new 关键字调用函数来创建对象的方法。构造函数的首字母通常使用大写,以示区分。通过构造函数模式创建的对象,可以包含特定的数据和方法。在构造函数模式中,this 关键字用于定义对象内...

Global site tag (gtag.js) - Google Analytics