第一百一十七篇: JavaScript 工厂模式和原型模式
好家伙,本篇为《JS高级程序设计》第八章“对象、类与面向对象编程”学习笔记
1.工厂模式
工厂模式是另外一种关注对象创建概念的创建模式。
它的领域中同其它模式的不同之处在于它并没有明确要求我们使用一个构造器。
取而代之,一个工厂能提供一个创建对象的公共接口,我们可以在其中指定我们希望被创建的工厂对象的类型。
function createPerson(name,age,job){
let person =new Object();
person.name= name;
person.age =age;
person.job =job;
person.getName = function(){
console.log(this.name);
}
return person;
}
let person_1 = createPerson("panghu","20","student")
person_1.getName();
console.log(person_1);
(看上去没什么问题,但怎么总觉得怪怪的)
let person =new Object(); /...
...
...
../ return person;
2.构造函数模式
前面几章提到过,ECMAScript中的构造函数是用于创建特定类型对象的。
像Object和Array这样的原生构造函数,运行时可以直接在执行环境中使用。
当然也可以自定义构造函数,以函数的形式为自己的对象类型定义属性和方法。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.getName = function () {
console.log(this.name);
};
}
let person_1 = new Person("panghu", "20", "student");
person_1.getName();
console.log(person_1);
在这个例子中,Person()构造函数代替了 createPerson()工厂函数。
实际上,Person()内部的代码跟createPerson()基本是一样的,只是有如下区别。
□没有显式地创建对象。
□属性和方法直接赋值给了this。
□没有return。
另外,要注意函数名Person的首字母大写了。
按照惯例,构造函数名称的首字母都是要大写的,非构造函数则以小写字母开头。
这是从面向对象编程语言那里借鉴的( 是的,非常好的借鉴 ),有助于在ECMAScript中区分构造函数和普通函数。
毕竟ECMAScript的构造函数就是能创建对象的函数。
要创建Person的实例,应使用new操作符。以这种方式调用构造函数会执行如下操作。
(1)在内存中创建一个新对象。
(2)这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性。
(3)构造函数内部的this被赋值为这个新对象(即this指向新对象)。
(4)执行构造函数内部的代码(给新对象添加属性)。
(5)如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
2.1.构造函数也是函数
构造函数与普通函数唯一的区别就是调用方式不同。除此之外,构造函数也是函数。
并没有把某个函数定义为构造函数的特殊语法。
任何函数只要使用new操作符调用就是构造函数,而不使用new操作符调用的函数就是普通函数。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.getName = function () {
console.log(this.name);
};
}
let person_1 = new Person("panghu", "20", "student");
person_1.getName();
//作为函数调用,添加到window对象
Person("xiaofu","20","student")
window.getName();
此处如果将Person当做普通函数来调用,那么this指向的就是全局作用域,数据会被添加到window对象
2.2. 构造函数的问题
构造函数虽然有用,但也不是没有问题。
构造函数的主要问题在于,其定义的方法会在每个实例上都创建一遍。
因此对前面的例子而言,person1和person2都有名为sayName()的方法,但这两个方法不是同一个Function 实例。
我们知道,ECMAScript中的函数是对象,因此每次定义函数时,都会初始化一个对象。
如果把方法分离出来,在全局作用域中进行定义,在当前对象需要多个方法,那么就要在全局作用域中定义多个函数.
这个问题可以通过原型模式解决
3.原型模式
(他来了,被营销号誉为Js三大难点的"原型"他来了)
理解复杂概念之前我们先从简单的地方入手(比如新华字典)
然后我们知道,原型指的是原来的模型
每个函数都会创建一个prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。
实际上,这个对象就是通过调用构造函数创建的对象的原型。
使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。
原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型,
3.1.实例共享原型模式的属性和方法
function Person(){}; Person.prototype.name = "panghu";
Person.prototype.age = "20";
Person.prototype.job = "student";
Person.prototype.getName =function(){
console.log(this.name);
} let person_1 = new Person();
person_1.getName();
let person_2 = new Person();
person_2.getName();
然后,我们来理解一下这段代码,
首先,我们要把Person的原型当成一个对象来看待,
于是我们现在有了三方势力,Person构造函数,Person原型对象,person_1和person_2两个实例对象
看看这幅图,
Person构造函数Person.prototype指向原型对象,而Person原型对象的constructor指向Person构造函数,
两个实例都只有唯一属性[[Prototype]]指向Person.prototype
3.2.原型层级
在通过对象访问属性时,会按照这个属性的名称开始搜索,搜索开始于对象实例本身
如果在对象实例上找到了,则返回对应的值,如果没找到,则搜索会沿着指针进入原型对象,然后在原型对象上找到属性后,再返回对应的值
function Person(){}; Person.prototype.name = "panghu";
Person.prototype.age = "20";
Person.prototype.job = "student";
Person.prototype.getName =function(){
console.log(this.name);
} let person_1 = new Person();
person_1.getName(); person_1.name ="xiaofu";
person_1.getName(); delete person_1.name
person_1.getName();
只要给对象实例添加一个属性,这个属性就会遮蔽原型对象上的同名属性,虽然不会修改,但会屏蔽对它的访问
3.3.原型的动态性
因为从原型上搜索值的过程是动态的,所以即使实例在修改原型之前已经存在,任何时候对原型对象所做的修改也会在实例上反映出来
function Person(){}; Person.prototype.saysomething =function(){
console.log("yes,we can");
} let person_1 = new Person(); person_1.saysomething();
但重写原型又是另一码事了
function Person() {}; let person_1 = new Person(); Person.prototype = {
constructor: Person,
name: "panghu",
age: "20",
job: "student",
saySomething() {
console.log("yes,we can");
}
}
person_1.saySomething();
虽然随时能给原型添加属性和方法,并能够立即反映在所有对象实例上、但这跟重写整个原型是两回事。
实例的[[Prototype]]指针是在调用构造函数时自动赋值的,这个指针即使把原型修改为不同的对象也不会变。
重写整个原型会切断最初原型与构造函数的联系,但实例引用的仍然是最初的原型。记住,实例只有指向原型的指针,没有指向构造函数的指针。
Person的新实例是在重写原型对象之前创建的。在调用person_1.saySomething()的时候,会导致错误。
这是因为person_1指向的原型还是最初的原型,而这个原型上并没有saySomething属性。
That's all
第一百一十七篇: JavaScript 工厂模式和原型模式的更多相关文章
- javascript 面向对象编程(工厂模式、构造函数模式、原型模式)
javascript 面向对象编程(工厂模式.构造函数模式.原型模式) CreateTime--2018年3月29日17:09:38 Author:Marydon 一.工厂模式 /** * 工厂模 ...
- 初涉JavaScript模式 (5) : 原型模式 【一】
什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...
- 初涉JavaScript模式 (7) : 原型模式 【三】
组合使用构造函数模式和原型模式 上篇,我们提到了原型模式的缺点,就是每个实例不能拥有自己的属性,因为纯原型模式所有的属性都是公开给每个实例的,故我们可以组合使用构造函数模式和原型模式.构造函数用来定义 ...
- Java进阶篇设计模式之三 ----- 建造者模式和原型模式
前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...
- 【js基础】创建对象的几种常见模式(工厂模式,构造函数模式,原型模式,构造原型组合模式)
一.工厂模式 缺点:没有解决对象识别的问题 优点:解决了创建多个相似对象的问题 function createPerson(name,age,job){ var o = new Object(); o ...
- js设计模式:工厂模式、构造函数模式、原型模式、混合模式
一.js面向对象程序 var o1 = new Object(); o1.name = "宾宾"; o1.sex = "男"; o1.a ...
- JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
什么是面向对象?面向对象是一种思想. 面向对象可以把程序中的关键模块都视为对象, 而模块拥有属性及方法. 这样如果我们把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作. 工厂 ...
- javascript创建对象的方法--原型模式
javascript创建对象的方法--原型模式 一.总结 1.原型模式解决内存浪费的方法(继承):通过继承,对象继承原型模式下的所有属性,对象不同于其它对象的的属性自己创建或者修改 2.原型的使用(p ...
- JavaScript之面向对象学习六原型模式创建对象的问题,组合使用构造函数模式和原型模式创建对象
一.仔细分析前面的原型模式创建对象的方法,发现原型模式创建对象,也存在一些问题,如下: 1.它省略了为构造函数传递初始化参数这个环节,结果所有实例在默认的情况下都将取得相同的属性值,这还不是最大的问题 ...
- javascript创建对象之函数构造模式和原型模式结合使用(四)
创建自定义类型的常见方式就是组合使用构造函数模式与原型模式一起使用. 构造函数模式用于定义实例对象的特有的部分(属性和方法),原型模式用于定义共享的部分. 这样最大限度的节省了内存的开销. funct ...
随机推荐
- CPS攻击案例(一)——基于脉冲宽度调制PWM的无人机攻击
本文系原创,转载请说明出处 Please Subscribe Wechat Official Account:信安科研人,获取更多的原创安全资讯 原论文链接:sec22-dayanikli.pd ...
- P7962 [NOIP2021] 方差 (DP)
题目的意思就是可以交换差分数组,对答案进行化简:n∑ai2−(∑ai)2 ,再通过手玩分析可得最优解的差分数组一定是单谷(可以感性理解一下),因此我们将差分数组排序,依次加入,每次可以选择加在左边 ...
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
- 插件化编程之WebAPI统一返回模型
WebApi返回数据我们一般包裹在一个公共的模型下面的,而不是直接返回最终数据,在返回参数中,显示出当前请求的时间戳,是否请求成功,如果错误那么错误的消息是什么,状态码(根据业务定义的值)等等.我们常 ...
- gets,fgets,puts,fputs,scanf,printf的作用,联系和区别
转载: https://blog.csdn.net/lc10915819/article/details/12747943
- VMware vSphere 8.0 正式版下载
请访问原文链接:https://sysin.org/blog/vmware-vsphere-8/,查看最新版.原创作品,转载请保留出处. 作者主页:www.sysin.org vSphere 8.0 ...
- 齐博x1钩子自动添加频道参数变量
频道或插件,增加功能的时候,可能要在后台增加开关参数.这个时候只需要增强对应的接口文件即可,比如创建这样一个文件\application\shop\ext\setting_get\give_jifen ...
- 【原创】i.MXRT J-Flash烧写算法使能eFuse熔丝位写入
临近年底,终于又憋了一篇文章出来,本来年初的时候是有计划把去年总结的一些东西整理下发布出来的,结果还是被工作和生活上各种琐事给耽搁了.哎,今年刚过了自己35岁的生日,眼瞅着这个人生节点 ...
- 七、Ajax请求
七.Ajax请求 客户端(浏览器)向服务端发起请求的形式: 地址栏:GET 超链接标签:GET form表单:GET或POST Ajax(重要):GET或POST或PUT或DELETE AJAX(As ...
- Azure DevOps Server 入门实践与安装部署
一,引言 最近一段时间,公司希望在自己的服务器上安装本地版的 Azure DevOps Service(Azure DevOps Server),用于项目内的测试,学习.本着学习的目的,我也就开始学习 ...