这一次我们来说一说在JavaScript中经常会用到的一个复杂基本类型,对象,先从对象的属性讲起,再讲对象的创建方法,基本涵盖了创建对象的各种方法,大家一起学习呀~

一、对象

要掌握对象的使用及继承,首先当然需要先理解它,接下来,将会对对象的属性类型进行一个整理

1、什么是对象

    对象其实是无序属性的集合,其属性可以包含基本值,对象或者函数,比如像下面这个例子就是一个person对象啦

var person = {
name: "NIcholas",
age: 29,
sayName: function() {
console.log(this.name);
}
}

从上面的例子我们可以看到,对象可以是由属性和其相应的值构成,对象中可以包含函数,也可以包含其它对象

2、属性类型

    在JavaScript中,其实有两种属性,包括数据属性和访问器属性

(1)数据属性

数据属性包含一个数据值的位置,在这个位置可以读取和写入值,一般来说,有4个描述其行为的特性:

a、[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,默认值为true

b、[[Enumerable]]:表示能否通过for-in循环返回属性,默认值为true

c、[[Writable]]:表示能否修改属性的值,默认值为true

d、[[Value]]:包含这个属性的数据值,默认值为undefined

一般来说,数据属性都有自己的默认值,那么如果我们要修改数据属性默认的特性,应该怎么办呢?这个时候就需要用到Object,defineProperty()方法啦,这个方法接收三个参数:属性所在的对象,属性的名字和一个描述对象,来看下面的例子

var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "Nicholas"
}); console.log(person.name); // Nicholas
// 重新赋值
person.name = "Greg";
console.log(person.name); // Nicholas

从上面的例子我们可以看到,因为设置了person对象的name属性为不可修改,因此无论你在后面怎么修改person的name属性的值,name属性的值都不会发生改变

(2)访问器属性

访问器属性不包含数据值,它们包含一对儿getter和setter函数,在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据,访问器属性有以下4个特性

a、[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,默认值为true

b、[[Enumerable]]:表示能否通过for-in循环返回属性,默认值为true

c、[[Get]]:在读取属性时调用的函数,默认值为undefined

d、[[Set]]:在写入属性时调用的函数,默认值为undefined

访问器属性不能直接定义,必须调用Object.definedProperty()来定义的,来看下面的例子

var book = {
_year:2004,
edition:1
} Object.defineProperty(book, "year", {
get: function() {
return this._year;
},
set: function(newValue) {
this._year = newValue;
}
});

这里要说明一下,book对象中_year前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性,还有呀,大家不要小看了Object.definedProperty()这个方法,这个方法可是很强大呀,像vue的双向数据绑定,其实就是用到了这个方法去实现的

(3)读取属性的特性

既然JavaScript有数据属性和访问器属性,那么我们怎样才能读取它们呀,这个时候就需要用到Object.getOwnPropertyDescriptor()方法了,这个方法可以取得给定属性的描述符,接收两个参数,分别是属性所在的对象和要读取其描述符的属性名称

二、对象的创建

在了解了对象之后,接下来我们就需要说下怎么创建对象了,最简单的方法,当然就是使用前面说的对象字面量的方法去创建啦,但是如果我们需要创建好多个对象,用前面的方法就不行了,我们需要用到其它更加简便的方法,帮助我们创建出多个对象

1、工厂模式

    这种模式其实是一个设计模式,抽象了创建具体对象的过程,主要是通过在函数内部创建一个对象,为其添加属性和方法,并将对象返回,从而实现创建多个对象的目的,来看下面的例子

function createPerson(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name);
};
return o;
} var person1 = createPerson("Nicholas", 29);
var person2 = createPerson("Greg", 27);

优点:能够解决创建多个对象的问题,兼容各个浏览器

缺点:没有解决对象识别的问题,不能知道一个对象的类型

2、构造函数模式

这种模式主要通过创建自定义的构造函数,从而定义自定义对象类型的属性和方法,来看下面例子

function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
}
} var person1 = new Person("Nicholas", 29);
var person2 = new Person("Greg", 27);

这里要说明一下,构造函数需要以一个大写字母开头,而非构造函数应该以一个小写字母开头,这个主要是为了区别构造函数和其它函数,构造函数其实本身也是函数,只是用来创建对象而已

其中,要创建Person的新实例,需要使用new操作符,其实这里会经过4个步骤,首先,将会创建一个新对象,接着会将构造函数的作用域赋给新对象,this指向了这个对象,接着会执行构造函数中的代码,为这个新对象添加属性,最后会返回新对象

优点:可以创建多个对象,解决对象的识别问题

缺点:每个实例都会创建不同的function实例,而其实创建完成同样任务的function实例是很没有必要的

这里还是要说明一下,对象类型的检测需要用到instanceof操作符,比如像上面的例子可以用下面的方法检测

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

使用构造函数模式可以解决对象的识别问题,而这也是工厂模式无法办到的

3、原型模式

    我们都知道,每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象就是原型对象,包含了所有实例共享的属性和方法,如果我们要创建的对象需要共享属性和方法,就可以使用这种方法创建

function Person() {
} Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.sayName = function() {
console.log(this.name);
} var person1 = new Person();
var person2 = new Person();
person1.sayName(); // Nicholas
person2.sayName(); // Nicholas

优点:不用为构造函数传递参数,可以创建多个相同的对象

缺点:原型中的属性被很多实例共享,当属性为包含引用类型值的属性时,修改一个实例中属性的值,另一个实例中的属性的值也会改变

4、组合使用构造函数模式和原型模式

    通过前面的分析,我们应该可以看到构造函数模式和原型模式的优点和缺点啦,构造函数可以创建多个不同属性值的对象,原型模式可以用于定义方法和共享的属性,我们可以将这两种模式结合起来,这种模式现在是使用最广泛的一种模式啦

function Person(name, age) {
this.name = name;
this.age = age;
} Person.prototype = {
constructor: Person,
sayName: function() {
console.log(this.name);
}
} var person1 = new Person("Nicholas", 29);
var person2 = new Person("Greg", 27); person1.sayName(); // Nicholas
person2.sayName(); // Greg
person1.sayName === person2.sayName; // true

从上面的例子我们可以看到,使用这种模式创建对象,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存,另外,这种混成模式还支持向构造函数传递参数,可谓是集两种模式之长

5、动态原型模式

    这种模式主要是将所有信息都封装在了构造函数里,因为在组合构造函数模式和原型模式中,构造函数和原型模式是独立的,有些开发人员会感到很困惑,因此,这种模式也是为了解决这个问题,通过在构造函数中初始化初始化原型,又保持了同时使用构造函数和原型的优点,换句话说,就是可以通过在构造函数中,检查某个应该存在的方法是否有效,来决定是否需要初始化原型

function Person(name, age) {
this.name = name;
this.age = age;
if(typeof this.sayName != "function") {
Person.prototype.sayName = function() {
console.log(this.name);
}
}
} var person1 = new Person("Nicholas", 29);
person1.sayName(); // Nicholas

这里要说明一下,在if语句中的代码,只有在首次调用构造函数时才会执行,之后原型已经得到初始化,不需要再做什么修改了

6、寄生构造函数模式

    这种模式其实和工厂模式很像,除了使用new操作符并把使用的包装函数叫做构造函数之外,和工厂模式可以说是一模一样的,这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象

function Person(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name);
}
return o;
} var person1 = new Person("Nicholas", 29);
person1.sayName(); // Nicholas

寄生构造函数模式和工厂模式真的是很像,那么既然有了工厂模式,为什么还要有寄生构造函数模式呢?其实这个模式主要是用来给js原生的构造函数定义一些新的方法,我们可以看下面这个例子

function SpecialArray() {
var values = new Array();
values.push.apply(values, argumens);
values.toPipedString = function() {
return this.join("|");
}
return values;
} var colors = new SpecialArray("red","blue");
console.log(colors.toPipedString()); // red|blue

从上面这个例子我们可以看到,我们在构造函数里面创建了一个新的数组,然后通过push方法初始化这个数组,并且又给数组的实例添加了一个toPipedString方法,并且将所创建的数组返回,因此呢,当我们通过new创建了SpecialArray实例时,其实就得到增加了新方法的数组实例啦,就可以在这个实例上使用我们添加的新的方法toPipedString

7、稳妥构造函数模式

    在说这种模式之前,要先说一下稳妥对象,稳妥对象就是指没有公共属性,而且其方法也不引用this的对象,稳妥对象最适合在一些安全的环境中,或者防止数据被其他应用程序改动时使用,稳妥构造函数模式遵循与寄生构造函数类似的模式,但是还是有下面的不同,第一个是新创建的对象实例方法不引用this,第二个是不使用new操作符调用构造函数

function Person(name, age) {
var o = new Object();
_name = name;
_age = age;
o.sayName = function() {
return _name;
}
return o;
} var person1 = Person("Nicholas", 29);
person1.sayName(); // Nicholas

在上面这个例子中,我们在构造函数中创建了一个对象后,可以继续添加一些私有的变量和函数,要修改这些私有的变量和函数,只能通过创建的对象的方法进行访问,这里在对象上创建的方法其实可以看作就是公有方法,比如说这里的_name和_age就是私有变量,而对象o的sayName方法就是访问私有变量的公有方法了,这里除了调用sayName()方法外,没有其它方法可以访问其数据成员

    8、es6中创建对象的方法

    最后要来说下es6中创建对象新增的方法啦,在es6中,引入了 Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类,基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
} var person1 = new Person("Nicholas", 29);
person1.sayName(); // Nicholas

上面这个例子其实就是组合构造函数模式和原型模式的改写,其中,constructor属性直接指向类本身,该方法会默认返回实例对象,在里面定义的属性和方法都是实例本身具有的方法,不是其它实例共享的,而像sayName方法就是定义在原型上的方法了,是所有实例一起共享的

好啦,今天就介绍到这里了,不知道大家对对象和对象的创建是否有了一个比较详细的了解了呢

 

    

js中对象和对象创建方法的更多相关文章

  1. JavaScript -- 时光流逝(三):js中的 String 对象的方法

    JavaScript -- 知识点回顾篇(三):js中的 String 对象的方法 (1) anchor(): 创建 HTML 锚. <script type="text/javasc ...

  2. JavaScript -- 时光流逝(五):js中的 Date 对象的方法

    JavaScript -- 知识点回顾篇(五):js中的 Date 对象的方法 Date 对象: 用于处理日期和时间. 1. Date对象的方法 <script type="text/ ...

  3. JavaScript -- 时光流逝(四):js中的 Math 对象的属性和方法

    JavaScript -- 知识点回顾篇(四):js中的 Math 对象的属性和方法 1. Math 对象的属性 (1) E :返回算术常量 e,即自然对数的底数(约等于2.718). (2) LN2 ...

  4. js中关于Blob对象的介绍与使用

    js中关于Blob对象的介绍与使用   blob对象介绍 一个 Blob对象表示一个不可变的, 原始数据的类似文件对象.Blob表示的数据不一定是一个JavaScript原生格式 blob对象本质上是 ...

  5. js中如何访问对象和数组

    js中如何访问对象和数组 一.总结 一句话总结:js访问对象点和中括号,访问数组的话就是中括号 对象 . [] 数组 [] 1.js访问对象的两种方式? . [] 可以使用下面两种方式访问对象的属性和 ...

  6. JS中的event 对象详解

    JS中的event 对象详解   JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...

  7. MVC中处理Json和JS中处理Json对象

    MVC中处理Json和JS中处理Json对象 ASP.NET MVC 很好的封装了Json,本文介绍MVC中处理Json和JS中处理Json对象,并提供详细的示例代码供参考. MVC中已经很好的封装了 ...

  8. js中的json对象详细介绍

    JSON一种简单的数据格式,比xml更轻巧,在JavaScript中处理JSON数据不需要任何特殊的API或工具包,下面为大家详细介绍下js中的json对象, 1.JSON(JavaScript Ob ...

  9. js中的DOM对象 和 jQuery对象 比较

    一,二者的区别 通过 jQuery 获取的元素是一个数组,数组中包含着原生JS中的DOM对象. 总结:jQuery 就是把 DOM 对象重新包装了一下,让其具有了 jQuery 方法. 二,二者的相互 ...

  10. js中的DOM对象和jQuery对象的比较

    1. 二者的不同之处: 通过jQuery获取的元素是一个数组, 数组中包含着原生JS中的DOM对象. 例如, 针对下面的一个div结构: <div id="Box">& ...

随机推荐

  1. git权限

    itHub--创建新的分支(转) 如何在 GitHub 的项目中创建一个分支呢? 其实很简单啦,直接点击 Branch,然后在弹出的文本框中添加自己的 Branch Name 然后点击蓝色的Creat ...

  2. Unity3D编辑器扩展(三)——使用GUI绘制窗口

    前两篇分别讲解了创建菜单https://www.cnblogs.com/xiaoyulong/p/10115053.html和创建窗口https://www.cnblogs.com/xiaoyulon ...

  3. python PyInstaller 库

    https://www.cnblogs.com/gopythoner/p/6337543.html https://www.cnblogs.com/duan-qs/p/6548875.html htt ...

  4. hightopo自己用开源的方案重构一遍

    经过一年多的学习吧前面路上的坑基本算踩过一遍了 所以下面计划吧hightopo网站上的demo用自己的方式重新写一遍

  5. windows下安装nodejs以及python2502,2503解决方案

    1. 2053和2052为什么会出现出现这个提示的时候,是在程序安装步骤 到达copy new file的时候 进入下一步进行报错,可以推测出应该是软件包在安装的时候,解压缩部署核心文件的时候出错. ...

  6. WSGI and Paste学习笔记

    The Problem Lots of web frameworks Zope, Quixote, Webware, SkunkWeb and Twisted Web etc Applications ...

  7. Linux的50个基本命令

    1.ls -a 列出当前目录下的所有文件,包括以.头的隐含文件(如-/.bashrc) ls –l 列出当前目录下文件的详细信息 2. pwd 查看当前所在目录的绝对路经 3. cd 目录之间的移动 ...

  8. 【翻译】Neural Collaborative Filtering--神经协同过滤

    [说明] 本文翻译自新加坡国立大学何向南博士 et al.发布在<World Wide Web>(2017)上的一篇论文<Neural Collaborative Filtering ...

  9. Inotify+Rsync实现Linux服务器文件同步

    做这个功能的时候遇到了好多坑,在此感谢一下这篇博客 http://kerry.blog.51cto.com/172631/734087/  ,大家参照这篇博客就能实现该功能. 另外如果想详细了解一下的 ...

  10. SVM算法简单应用

    第一部分:线性可分 通俗解释:可以用一条直线将两类分隔开来 一个简单的例子,直角坐标系中有三个点,A,B点为0类,C点为1类: from sklearn import svm # 三个点 x = [[ ...