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


Posted in Javascript onJune 26, 2017

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

工厂模式

function createPerson(name, job) { 
 var o = new Object() 
 o.name = name 
 o.job = job 
 o.sayName = function() { 
  console.log(this.name) 
 } 
 return o 
} 
var person1 = createPerson('Jiang', 'student') 
var person2 = createPerson('X', 'Doctor')

可以无数次调用这个工厂函数,每次都会返回一个包含两个属性和一个方法的对象

工厂模式虽然解决了创建多个相似对象的问题,但是没有解决对象识别问题,即不能知道一个对象的类型

构造函数模式

function Person(name, job) { 
 this.name = name 
 this.job = job 
 this.sayName = function() { 
  console.log(this.name) 
 } 
} 
var person1 = new Person('Jiang', 'student') 
var person2 = new Person('X', 'Doctor')

没有显示的创建对象,使用new来调用这个构造函数,使用new后会自动执行如下操作

创建一个新对象

这个新对象会被执行[[prototype]]链接

这个新对象会绑定到函数调用的this

返回这个对象

使用这个方式创建对象可以检测对象类型

person1 instanceof Object // true 
person1 instanceof Person //true

但是使用构造函数创建对象,每个方法都要在每个实例上重新创建一次

原型模式

function Person() { 
} 
Person.prototype.name = 'Jiang' 
Person.prototype.job = 'student' 
Person.prototype.sayName = function() { 
 console.log(this.name) 
} 
var person1 = new Person()

将信息直接添加到原型对象上。使用原型的好处是可以让所有的实例对象共享它所包含的属性和方法,不必在构造函数中定义对象实例信息。

原型是一个非常重要的概念,在一篇文章看懂proto和prototype的关系及区别中讲的非常详细

更简单的写法

function Person() { 
} 
Person.prototype = { 
 name: 'jiang', 
 job: 'student', 
 sayName: function() { 
  console.log(this.name) 
 } 
} 
var person1 = new Person()

将Person.prototype设置为等于一个以对象字面量形式创建的对象,但是会导致.constructor不在指向Person了。

使用这种方式,完全重写了默认的Person.prototype对象,因此 .constructor也不会存在这里

Person.prototype.constructor === Person // false

如果需要这个属性的话,可以手动添加

function Person() { 
} 
Person.prototype = { 
 constructor:Person 
 name: 'jiang', 
 job: 'student', 
 sayName: function() { 
  console.log(this.name) 
 } 
}

不过这种方式还是不够好,应为constructor属性默认是不可枚举的,这样直接设置,它将是可枚举的。所以可以时候,Object.defineProperty方法

Object.defineProperty(Person.prototype, 'constructor', { 
 enumerable: false, 
 value: Person 
})

缺点

使用原型,所有的属性都将被共享,这是个很大的优点,同样会带来一些缺点

原型中所有属性实例是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性也勉强可以,毕竟实例属性可以屏蔽原型属性。但是引用类型值,就会出现问题了

function Person() { 
} 
Person.prototype = { 
 name: 'jiang', 
 friends: ['Shelby', 'Court'] 
} 
var person1 = new Person() 
var person2 = new Person() 
person1.friends.push('Van') 
console.log(person1.friends) //["Shelby", "Court", "Van"] 
console.log(person2.friends) //["Shelby", "Court", "Van"] 
console.log(person1.friends === person2.friends) // true

friends存在与原型中,实例person1和person2指向同一个原型,person1修改了引用的数组,也会反应到实例person2中

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

这是使用最为广泛、认同度最高的一种创建自定义类型的方法。它可以解决上面那些模式的缺点

使用此模式可以让每个实例都会有自己的一份实例属性副本,但同时又共享着对方法的引用

这样的话,即使实例属性修改引用类型的值,也不会影响其他实例的属性值了

function Person(name) { 
 this.name = name 
 this.friends = ['Shelby', 'Court'] 
} 
Person.prototype.sayName = function() { 
 console.log(this.name) 
} 
var person1 = new Person() 
var person2 = new Person() 
person1.friends.push('Van') 
console.log(person1.friends) //["Shelby", "Court", "Van"] 
console.log(person2.friends) // ["Shelby", "Court"] 
console.log(person1.friends === person2.friends) //false

动态原型模式

动态原型模式将所有信息都封装在了构造函数中,初始化的时候,通过检测某个应该存在的方法时候有效,来决定是否需要初始化原型

function Person(name, job) { 
  // 属性 
 this.name = name 
 this.job = job 
 // 方法 
 if(typeof this.sayName !== 'function') { 
  Person.prototype.sayName = function() { 
    console.log(this.name) 
  } 
 } 
} 
var person1 = new Person('Jiang', 'Student') 
person1.sayName()

只有在sayName方法不存在的时候,才会将它添加到原型中。这段代码只会初次调用构造函数的时候才会执行。

此后原型已经完成初始化,不需要在做什么修改了

这里对原型所做的修改,能够立即在所有实例中得到反映

其次,if语句检查的可以是初始化之后应该存在的任何属性或方法,所以不必用一大堆的if语句检查每一个属性和方法,只要检查一个就行

寄生构造函数模式

这种模式的基本思想就是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新建的对象

function Person(name, job) { 
  var o = new Object() 
 o.name = name 
 o.job = job 
 o.sayName = function() { 
  console.log(this.name) 
 } 
 return o 
} 
var person1 = new Person('Jiang', 'student') 
person1.sayName()

这个模式,除了使用new操作符并把使用的包装函数叫做构造函数之外,和工厂模式几乎一样

构造函数如果不返回对象,默认也会返回一个新的对象,通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值

稳妥构造函数模式

首先明白稳妥对象指的是没有公共属性,而且其方法也不引用this。

稳妥对象最适合在一些安全环境中(这些环境会禁止使用this和new),或防止数据被其他应用程序改动时使用

稳妥构造函数模式和寄生模式类似,有两点不同:一是创建对象的实例方法不引用this,而是不使用new操作符调用构造函数

function Person(name, job) { 
 var o = new Object() 
 o.name = name 
 o.job = job 
 o.sayName = function() { 
  console.log(name) 
 } 
 return o 
} 
var person1 = Person('Jiang', 'student') 
person1.sayName()

和寄生构造函数模式一样,这样创建出来的对象与构造函数之间没有什么关系,instanceof操作符对他们没有意义

以上所述是小编给大家介绍的JavaScript创建对象的七种方式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery监控数据是否变化(修正版)
Apr 12 Javascript
日期处理的js库(迷你版)--自建js库总结
Nov 21 Javascript
用javascript删除当前行,添加行(示例代码)
Nov 25 Javascript
使用jQuery的attr方法来修改onclick值
Jul 07 Javascript
Angularjs编写KindEditor,UEidtor,jQuery指令
Jan 28 Javascript
fullCalendar中文API官方文档
Feb 07 Javascript
Javascript实现跨域后台设置拦截的方法详解
Aug 04 Javascript
微信小程序 MinUI组件库系列之badge徽章组件示例
Aug 20 Javascript
jQuery事件绑定和解绑、事件冒泡与阻止事件冒泡及弹出应用示例
May 13 jQuery
基于Angular 8和Bootstrap 4实现动态主题切换的示例代码
Feb 11 Javascript
jquery插件懒加载的示例
Oct 24 jQuery
Vue中Object.assign清空数据报错的解决方案
Mar 03 Vue.js
基于 webpack2 实现的多入口项目脚手架详解
Jun 26 #Javascript
JavaScript的六种继承方式(推荐)
Jun 26 #Javascript
JavaScript数据类型和变量_动力节点Java学院整理
Jun 26 #Javascript
JavaScript基本语法_动力节点Java学院整理
Jun 26 #Javascript
JavaScript条件判断_动力节点Java学院整理
Jun 26 #Javascript
JavaScript脚本语言是什么_动力节点Java学院整理
Jun 26 #Javascript
JavaScript简介_动力节点Java学院整理
Jun 26 #Javascript
You might like
PHPMailer 中文使用说明小结
2010/01/22 PHP
zf框架的Filter过滤器使用示例
2014/03/13 PHP
PHP判断是否连接上网络的方法
2015/07/01 PHP
关于PHP中协程和阻塞的一些理解与思考
2017/08/11 PHP
Thinkphp5框架中引入Markdown编辑器操作示例
2020/06/03 PHP
Jquery阻止事件冒泡 event.stopPropagation
2011/12/11 Javascript
给超链接添加特效鼠标移动展示提示信息且随鼠标移动
2013/10/17 Javascript
浏览器窗口大小变化时使用resize事件对框架不起作用的解决方法
2014/05/11 Javascript
jQuery实现仿QQ空间装扮预览图片的鼠标提示效果代码
2015/10/30 Javascript
深入理解Node.js 事件循环和回调函数
2016/11/02 Javascript
vue.js国际化 vue-i18n插件的使用详解
2017/07/07 Javascript
在 Node.js 中使用 async 函数的方法
2017/11/17 Javascript
面包屑导航详解
2017/12/07 Javascript
详解Vue打包优化之code spliting
2018/04/09 Javascript
Vue CLI 3.x 自动部署项目至服务器的方法
2019/04/02 Javascript
简单了解JavaScript异步
2019/05/23 Javascript
Vue.js递归组件实现组织架构树和选人功能案例分析
2019/07/03 Javascript
在react-antd中弹出层form内容传递给父组件的操作
2020/10/24 Javascript
浅析JavaScript中的事件委托机制跟深浅拷贝
2021/01/20 Javascript
[51:53]DOTA2-DPC中国联赛 正赛 RNG vs Dragon BO3 第二场 1月24日
2021/03/11 DOTA
python版DDOS攻击脚本
2019/06/12 Python
pandas实现excel中的数据透视表和Vlookup函数功能代码
2020/02/14 Python
Django values()和value_list()的使用
2020/03/31 Python
纯CSS3实现运行时钟的示例代码
2021/01/25 HTML / CSS
能否解释一下XSS cookie盗窃是什么意思
2012/06/02 面试题
cf收人广告词
2014/03/14 职场文书
金融与证券专业求职信
2014/06/22 职场文书
社区敬老月活动总结
2015/05/07 职场文书
学校2015年纠风工作总结
2015/05/15 职场文书
严以律己专题学习研讨会发言材料
2015/11/09 职场文书
小学数学教学反思范文
2016/02/16 职场文书
2016年庆“七一”主题党日活动总结
2016/04/05 职场文书
ThinkPHP5和ThinkPHP6的区别
2021/03/31 PHP
Python爬虫之爬取哔哩哔哩热门视频排行榜
2021/04/28 Python
详解Node.js如何处理ES6模块
2021/05/15 Javascript
【D4DJ】美少女DJ企划 动画将于明年冬季开播第2季
2022/04/11 日漫