JavaScript构造函数
JavaScript
不同于其他强类型语言,没有类的概念,但是它支持可以与实例共同使用特殊的Constructor
构造器,使用new关键字创建新的实例,并告知JavaScript
使用对象的内规则去定制这个实例。实际上实例中的this
指向的是新的实例。
典型的面向对象编程语言如java
和C++
都存在类(class
)的概念,在javaScript
使用Object
对象,其实在javaScript
就是一堆对象在用来用去。
如果你还不知道,javaScript
函数可以兼作对象构造函数。例如,要编写面向对象编程中的类,可以写成下面这种代码。
function Person(name){
this.name = name;
}
let Aaron = new Person("Aaron");
let Angie = new Person("Angie")
console.log(Angie instanceof Person); // true
通过上面的输出结果可以得出Angie
确实是属于Person
这个构造函数的。
构造函数优/缺点
javaScript
创建对象的方式有很多,通过Object
构造函数或对象字面量的方式也可以创建单个对象。
优点:
- 代码结构清晰,便于维护
- 可以利用构造函数模拟
class
做的事 - 代码复用
缺点:
- 资源浪费,每个对象都有其对应的属性,在
new
构造函数的时候,那么需要为每个属性单独开辟空间,存放属性。
构造函数与普通函数的区别
- 构造函数使用new关键字调用;普通函数不用
new
关键字调用 - 构造函数内部可以使用
this
关键字;普通函数内部不建议使用this
,因为这时候this
指向的是window
全局对象,这样无意间就会为window
添加了一些全局变量或函数 - 构造函数默认不用
return
返回值;普通函数一般都有return
返回值 - 构造函数首字母建议大写;普通函数首字母建议小写
关于new
以上文中的Person
()函数举个栗子:
- 创建一个空对象。
var Person={}
- 将构造函数
Person()
中的this指向新创建的对象Aaron
。 - 将Aaron的_proto_属性指向
Person
函数的prototype,创建对象和原型间关系 - 执行构造函数
Person()
内的代码。
创建对象的方式
第一种
var Person = new Object();
Person.name = 'Nike';
Person.age = 29;
第二种
var Person = {
name:'Nike',
age:29
}
第三种
Object.defineProperty(objName,"key",{
// 能否使用delete、能否需改属性特性、或能否修改访问器属性、,false为不可重新定义,默认值为true
configurable:false,
// 对象属性是否可通过for-in循环,flase为不可循环,默认值为true
enumerable:false,
// 对象属性是否可修改,flase为不可修改,默认值为true
writable:false,
// 对象属性的默认值,默认值为undefined
value:'Aaron'
})
第四种
Object.defineProperties(objName,{
"a":{
value:"value",
writable:true
},
"b":{
value:"value",
writable:true
}
})
创建构造函数的方法
这种方法最简单的一种方法,使用object
对象,在函数中最后返回。我们可能经常说的一句话就是,没对象,没对象,没对象,没对象你new
一个呀。
方法一
实际上这是我们在实际中最常用的对象定义方式,但是我要有好多拥有相似属性的对象怎么办呢?那要是一个个的定义,就会产生大量的代码,何不建个工厂,批量的生产出我们的对象呢,然后就有了工厂模式,通过一个工厂来达到我们想要的目的。
// 工厂模式
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’)
可以无数次调用这个工厂函数,每次都会返回一个包含两个属性和一个方法的对象,工厂模式虽然解决了创建多个相似对象的问题,但是没有解决对象识别问题,即不能知道一个对象的类型。
方法二
工厂模式解决了多个相似对象的创建问题,但是问题又来了,然而这些对象是使用object
对象来实现的,怎么区分它们的对象具体类型呢?这时候我们就需要切换到另一种模式了,构造函数模式:
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
- 返回这个对象
当你去new
一个构造函数的时候,该函数不在默认返回undefined
,而是把this
做为默认值return
出去。
person1 instanceof Object // true
person1 instanceof Person //true
但是使用构造函数创建对象,每个方法都要在每个实例上重新创建一次。
方法三
当我们创建一个函数时,该函数就会具备一个prototype
属性,这个属性指向通过构造函数创建的那个函数的原型对象。通俗点讲原型对象就是内存中为其他对象提供共享属性和方法的对象。
所有的对象都有一个原型对象prototype
,原型对象中有一个constructor
属性指向包含prototype
属性的函数,当我们访问一个对象中的属性时,首先会询问实例对象中有没有该属性,如果没有则继续查找原型对象。
在原型模式中,不必再构造函数中定义实例属性,可以将属性信息直接赋予原型对象:
function Person() {
}
Person.prototype = {
name: ‘jiang’,
job: ‘student’,
sayName: function() {
console.log(this.name)
}
}
var person1 = new Person()
通过对原型对象模式的初步了解,我们发现所有的实例对象都共享相同的属性,这是原型模式的基本特点,但往往对于开发者来说这是把“双刃剑”,在实际开发中,我们希望的实例应该是具备自己的属性,这也是在实际开发中很少有人单独使用原型模式的主要原因。
将信息直接添加到原型对象上。使用原型的好处是可以让所有的实例对象共享它所包含的属性和方法,不必在构造函数中定义对象实例信息。
不过这种方式还是不够好,应为constructor
属性默认是不可枚举的,这样直接设置,它将是可枚举的。所以可以时候,Object.defineProperty
方法
Object.defineProperty(Person.prototype, ‘constructor’, {
enumerable: false,
value: Person
})
方法四
这是使用最为广泛、认同度最高的一种创建自定义类型的方法。它可以解决上面那些模式的缺点。
在实际开发中,我们可以使用构造函数来定义对象的属性,使用原型来定义共享的属性和方法,这样我们就可以传递不同的参数来创建出不同的对象,同时又拥有了共享的方法和属性。
使用此模式可以让每个实例都会有自己的一份实例属性副本,但同时又共享着对方法的引用
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
方法不存在的时候,才会将它添加到原型中。这段代码只会初次调用构造函数的时候才会执行。
JavaScript构造函数的更多相关文章
- JavaScript 构造函数
关于JavaScript构造函数,如今出现了很多JavaScript的框架,例如jQuery.Ext等等这些,这些将JavaScript作为一种面向对象的语言进行编程,那么JavaScript到底是怎 ...
- javascript 构造函数方式定义对象 (转载)
javascript 构造函数方式定义对象 javascript是动态语言,可以在运行时给对象添加属性,也可以给对象删除(delete)属性 <html> <head> & ...
- Javascript 构造函数、原型对象、实例之间的关系
# Javascript 构造函数.原型对象.实例之间的关系 # 创建对象的方式 # 1.new object() 缺点:创建多个对象困难 var hero = new Object(); // 空对 ...
- Javascript 构造函数原型继承机制
我们先聊聊Js的历史,1994年Netscape公司发布了Navigator浏览器0.9班.这是历史上第一个比较成熟的网络浏览器.轰动一时.但是,这个版本的浏览器只能用来浏览,不具备交互功能,最主要的 ...
- JavaScript构造函数学习笔记
1 理解Javascript constructor实现原理 在 JavaScript 中,每个函数都有名为“prototype”的属性,用于引用原型对象.此原型对象又有名为“constructor” ...
- Javascript构造函数与prototype
构造函数 构造函数的缺点 prototype的引入 Prototype模式的验证方法 构造函数 在Javascript语言中,new命令后面跟的不是类,而是构造函数(constructor). 构造函 ...
- javascript 构造函数方式定义对象
javascript是动态语言,可以在运行时给对象添加属性,也可以给对象删除(delete)属性 <html> <head> <script type="tex ...
- 深入javascript——构造函数和原型对象
常用的几种对象创建模式 使用new关键字创建 最基础的对象创建方式,无非就是和其他多数语言一样说的一样:没对象,你new一个呀! var gf = new Object(); gf.name = &q ...
- JavaScript构造函数+原型创建对象,原型链+借用构造函数模式继承父类练习
虽然经常说是做前端开发的,但常常使用的技术反而是JQuery比较多一点.在JavaScript的使用上相对而言少些.尤其是在创建对象使用原型链继承上面,在项目开发中很少用到.所以今天做个demo练习一 ...
- JavaScript 构造函数 prototype属性和_proto_和原型链 constructor属性 apply(),call()和bind() 关键字this
1.构造函数: 通常构造函数首字母需要大写,主要是为了区别ECMAScript的其它函数.(高程三 P145) 构造函数与其他函数的唯一区别,就在于调用它们的方式不同.只要通过new来调用,任何函数都 ...
随机推荐
- ScalaPB(3): gRPC streaming
接着上期讨论的gRPC unary服务我们跟着介绍gRPC streaming,包括: Server-Streaming, Client-Streaming及Bidirectional-Streami ...
- 为什么「margin:auto」可以让块级元素水平居中?
知乎链接:http://www.zhihu.com/question/21644198 关于BFC的解释:W3CFans http://www.w3cfuns.com/thread-5595727-1 ...
- 单片机开发——01工欲善其事必先利其器(Keil软件安装破解)
本文是博主<单片机开发>博客第一篇文章,主要讲述51单片机编程软件Keil uVision4的安装及破解过程. 1. Keil uVision4安装包文件 PATH:链接 ...
- Python_字符串的映射与可变字符串的应用
''' maketrans().translate() maketrans()方法用来生成字符映射表,而translate()方法则按映射表中定义的对应关系转换并替换其中的字符,使用这两个方法的组合可 ...
- PAT1136:A Delayed Palindrome
1136. A Delayed Palindrome (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...
- PAT1013: Battle Over Cities
1013. Battle Over Cities (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue It ...
- Java并发包之同步队列SynchronousQueue理解
1 简介 SynchronousQueue是这样一种阻塞队列,其中每个put必须等待一个take,反之亦然.同步队列没有任何内部容量,甚至连一个队列的容量都没有.不能在同步队列上进行peek,因为仅在 ...
- SSIS 检查点
在SSIS中,检查点实际上是一个记录系统,用于记录控制流中Task组件的执行状态.通过合理地配置Checkpoint,在Package运行出错之后,重新执行Package,可以跳过上一次已经成功执行的 ...
- Ueditor 专题
https://github.com/xwjie/SpringBootUeditor 提交表单提交表单设置按照部署编辑器的教程,完成编辑器加载 把容器放到form表单里面,设置好要提交的路径,如下面代 ...
- jQuery学习之旅 Item6 好用的each()
1.javascript 函数的调用方式 首先来研究一下jquery的each()方法的源码,在这之前,先要回顾一下javascript函数具体调用样式: 普通函数调用 setName(); 可以作为 ...