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来调用,任何函数都 ...
随机推荐
- Java容器:Stack,Queue,PriorityQueue和BlockingQueue
Stack Queue PriorityQueue BlockingQueue ArrayBlockingQueue LinkedBlockingQueue PriorityBlockingQueue ...
- ScalaPB(4): 通用跨系统protobuf数据,sbt设置
我们知道,在集群环境节点之间进行交换的数据必须经过序列化/反序列化处理过程,而在这方面protobuf是一个比较高效.易用的模式.用户首先在.proto文件中用IDL来定义系统中各种需要进行交换的数据 ...
- [CVPR2017] Weakly Supervised Cascaded Convolutional Networks论文笔记
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "Helvetica Neue"; color: #042eee } p. ...
- post 和 get 的区别,直指本质
在我们初入java编程之路的时候,面试往往会有一个面试题:get和post的区别是什么?那么你真的知道他们的区别吗?接下来抽丝剥茧,让我们看看get和post到底什么东西,首先从本质的角度看get和p ...
- Spring对象生存周期(Scope)的分析
一.Scope定义 Scope用来声明容器中管理的对象所应该处的限定场景或者说对象的存活时间,即容器在对象进入相应的Scope之前,生产并装配这些对象,在该对象不再处于这些Scope之后,容器通常会销 ...
- codeforces 979D Kuro and GCD and XOR and SUM
题意: 给出两种操作: 1.添加一个数字x到数组. 2.给出s,x,k,从数组中找出一个数v满足gcd(x,k) % v == 0 && x + v <= s && ...
- 对于 Netty ByteBuf 的零拷贝(Zero Copy) 的理解
此文章已同步发布在我的 segmentfault 专栏. 根据 Wiki 对 Zero-copy 的定义: "Zero-copy" describes computer opera ...
- Unity3D学习(七):Unity多重采样抗锯齿设置无效的解决办法
前言 学习Shader的过程中发现模型锯齿严重,于是去Edit--Project Settings--Quality选项下将反锯齿设置为了8X Multi Sampling.结果没有任何改变,如图: ...
- 最好的营销是“调情”
每一个精彩的营销案例都应该像一个精彩的故事,而故事最精彩的讲述方式就是设置一个开放的结局,把解读和诠释的权利留给读者和观众.宣讲.洗脑式的营销时代已经终结,就像单相思的深情表白永远不如两情相悦的彼此挑 ...
- RBAC权限模型——项目实战(转)
一.前言 权限一句话来理解就是对资源的控制,对web应用来说就是对url的控制,关于权限可以毫不客气的说几乎每个系统都会包含,只不过不同系统关于权限的应用复杂程序不一样而已,现在我们在用的权限模型基本 ...