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算法分析与设计]--顺序栈的实现
在程序的世界,栈的应用是相当广泛的.其后进先出的特性,我们可以应用到诸如计算.遍历.代码格式校对等各个方面.但是你知道栈的底层是怎么实现的吗?现在跟随本篇文章我们来一睹它的庐山真面目吧. 首先我们先定 ...
- 重温《STL源码剖析》笔记 第六、七、八章 next_permutation (字典序)
源码之前,了无秘密 ——侯杰 第六章算法 next_permutation 比如:01342 -> 01423 -> 01432 方法:从尾端开始往前寻找两个相邻的元素,令第一个元素为* ...
- JSON Patch
1.前言 可以这么说的是,任何一种非强制性约束同时也没有"标杆"工具支持的开发风格或协议(仅靠文档是远远不够的),最终的实现上都会被程序员冠上"务实"的名头,而 ...
- hexo+github创建属于自己的博客
配置环境 安装Node(必须) 作用:用来生成静态页面的 到Node.js官网下载相应平台的最新版本,一路安装即可. 安装Git(必须) 作用:把本地的hexo内容提交到github上去. 安装Xco ...
- 高通调试 SPI 屏的 bug
1. spi调试问题: 问题描述: spi屏幕lk启动的时候正常出现小企鹅,到kernel启动的过程黑屏并且花屏才到开机动画: 2. 黑屏的三个阶段: 参照:黑屏分析 分析开机过程黑屏,首先需要定位黑 ...
- onCreate和onStart谁的开销大?
大家都知道,onCreate方法在创建的时候开始调用一些方法来获取资源方面的东西,这个是在程序运行之初才执行的,一个完整的生命周期中,它只执行了一次,不被onDestroy掉,就一直不调用,而onSt ...
- W3C------JS
✄--------------------------------------------分割线--------------------------------------------✄ W3C:ht ...
- bzoj 2002 弹飞绵羊 分块
正解lct,然而本蒟蒻并不会.... 分块思路很清晰,处理出每个点弹出所在块所需要的步数及出去后的第一个位置 #include<cstdio> #include<cstring> ...
- 【源码分析】Canal之Binlog的寻找过程
binlog的寻找过程可能的场景如下: instance第一次启动 发生数据库主备切换 canal server HA情况下的切换 所以这个过程是能够保证binlog不丢失的关键点. 本文从源码的角度 ...
- 我和Python的Py交易》》》》》》数据类型
Python里的变量 ---门牌 Python在使用变量之前无须定义它的类型,但是必须声明以及初始化该变量. Python中给变量赋值就是声明,初始化变量(也就是创建一个相应数据类型的对象,而那些数据 ...