js中对象与对象创建方法的各种方法


Posted in Javascript onFebruary 27, 2019

前言

不管是哪门语言,千变万化不离其宗,深入理解其本质,方能应用自如。对应到js,闭包,原型,函数,对象等是需要花费大功夫思考、理解的。

这一次我们来说一说在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 = new 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方法就是定义在原型上的方法了,是所有实例一起共享的

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
仿校内登陆框,精美,给那些很厉害但是没有设计天才的程序员
Nov 24 Javascript
jquery pagination插件实现无刷新分页代码
Oct 13 Javascript
JavaScript中各种编码解码函数的区别和注意事项
Aug 19 Javascript
window.navigate 与 window.location.href 的使用区别介绍
Sep 21 Javascript
jquery快捷动态绑定键盘事件的操作函数代码
Oct 17 Javascript
Javascript this 关键字 详解
Oct 22 Javascript
javascript中的正则表达式使用指南
Mar 01 Javascript
js文本框走动跑马灯效果代码分享
Aug 25 Javascript
JavaScript实现给定时间相加天数的方法
Jan 25 Javascript
每日十条JavaScript经验技巧(一)
Jun 23 Javascript
Laydate时间组件在火狐浏览器下有多时间输入框时只能给第一个输入框赋值的解决方法
Aug 18 Javascript
详解如何使用node.js的开发框架express创建一个web应用
Dec 20 Javascript
vue router带参数页面刷新或回退参数消失的解决方法
Feb 27 #Javascript
react的滑动图片验证码组件的示例代码
Feb 27 #Javascript
原生JS forEach()和map()遍历的区别、兼容写法及jQuery $.each、$.map遍历操作
Feb 27 #jQuery
js/jquery遍历对象和数组的方法分析【forEach,map与each方法】
Feb 27 #jQuery
spring+angular实现导出excel的实现代码
Feb 27 #Javascript
react native 原生模块桥接的简单说明小结
Feb 26 #Javascript
JavaScript实现获取两个排序数组的中位数算法示例
Feb 26 #Javascript
You might like
PHP-MySQL教程归纳总结
2008/06/07 PHP
Laravel 解决composer相关操作提示php相关异常的问题
2019/10/23 PHP
PHP 实现缩略图
2021/03/09 PHP
url 编码 js url传参中文乱码解决方案
2010/04/11 Javascript
基于jquery的让页面控件不可用的实现代码
2010/04/27 Javascript
JavaScript实现向setTimeout执行代码传递参数的方法
2015/04/16 Javascript
node.js操作mysql(增删改查)
2015/07/24 Javascript
js事件驱动机制 浏览器兼容处理方法
2016/07/23 Javascript
AngularJS学习笔记(三)数据双向绑定的简单实例
2016/11/08 Javascript
jquery ui sortable拖拽后保存位置
2017/04/27 jQuery
详解使用angularjs的ng-options时如何设置默认值(初始值)
2017/07/18 Javascript
JS声明对象时属性名加引号与不加引号的问题及解决方法
2018/02/16 Javascript
Node.JS枚举统计当前文件夹和子目录下所有代码文件行数
2019/08/23 Javascript
JS防抖和节流实例解析
2019/09/24 Javascript
vue获取data数据改变前后的值方法
2019/11/07 Javascript
[00:05]ChinaJoy现场 DOTA2玩家高呼“CN DOTA BEST DOTA”
2019/08/04 DOTA
Python排序搜索基本算法之冒泡排序实例分析
2017/12/09 Python
解决Python 中英文混输格式对齐的问题
2018/07/16 Python
利用Python库Scapy解析pcap文件的方法
2019/07/23 Python
python3 requests库文件上传与下载实现详解
2019/08/22 Python
解决python打开https出现certificate verify failed的问题
2020/09/03 Python
python使用matplotlib绘制折线图的示例代码
2020/09/22 Python
HTML5中外部浏览器唤起微信分享
2020/01/02 HTML / CSS
Kangol帽子官网:坎戈尔袋鼠
2018/09/26 全球购物
金融专业推荐信
2013/11/14 职场文书
大学生军训自我鉴定
2014/02/12 职场文书
生日主持词
2014/03/20 职场文书
我的中国梦演讲稿500字
2014/08/19 职场文书
小学生志愿者活动方案
2014/08/23 职场文书
公安机关纪律作风整顿个人剖析材料材料
2014/10/10 职场文书
2015年三八妇女节活动总结
2015/02/06 职场文书
2015应届毕业生求职信范文
2015/03/20 职场文书
停电通知范文
2015/04/16 职场文书
2019开业庆典剪彩仪式主持词!
2019/07/22 职场文书
2019年共青团工作条例最新版
2019/11/12 职场文书
分享Python获取本机IP地址的几种方法
2022/03/17 Python