JS 创建对象(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式,寄生构造函数模式,稳妥构造函数模式)

js面向对象之常见创建对象的几种方式(工厂模式、构造函数模式、原型模式) JS的语法非常灵活,简单的对象创建就有好几种不同的方法。这些过于灵活的地方有时候确实很让人迷惑,那么今天我们就来梳理一下JS中常用的创建对象的几种方法吧 立即下载

构造函数,原型对象,实例化对象的关系:

  • 每个函数(包括构造函数)都有一个原型对象(prototype)
  • 原型对象都包含一个指向构造函数的指针(constructor)
  • 原型对象上的属性和方法,都可以被构造函数的实例化对象所继承(所有实例化对象共享一个原型对象)
  • 实例化对象又都包含一个指向构造函数的原型对象的指针(__proto__),(p1.__proto__ === Person.prototype)(p1.__proto__.constructor === Person.prototype.constructor)(p1.__proto__.constructor === Person)

 

prototype 是函数才有的属性,切记,切记

__proto__ 是每个对象(包括函数)都有的属性

 1.工厂模式

function createPerson(name, age, job){
    var o = new Object();  // "原料"
    // "加工"
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o; // "出厂"
}
var person1 = createPerson("a1", 12, "程序");
var person2 = createPerson("b1", 18, "销售");
console.log(person1.name) // a1
console.log(person2.age) // 18

2.构造函数模式 

构造函数,是用来创建对象的函数,本质上也是函数
任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数 ;
任何函数,如果不通过 new 操作符来调用,那它跟普通函数也没有什么两样。

// 创建函数
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}

// 当作构造函数使用
var person = new Person('Nicholas',29,'Software Engineer'); // this --> person
person.sayName(); // 'Nicholas'
这里的 Person 就称为构造函数,person 称为 Person 函数对象的一个实例(复制品)


// 当作普通函数调用
Person('Greg',27,'Doctor'); // this --> window
window.sayName(); // 'Greg'

对比 

* 1.没有显式地创建对象;
* 2.直接将属性和方法赋给了 this 对象;
* 3.没有 return 语句;
* 4.构造函数都应该以 一个大写字母开头
function Person(){...}
而非构造函数则应该以一个小写字母开头
function person(){...}
* 5.使用 new 创建对象
* 6.能够识别对象(这正是构造函数模式胜于工厂模式的地方)

3.原型模式 

在 JS 中,无论什么时候,只要你创建了一个新函数,就会根据一组特定的规定为该函数创建一个 prototype 的属性,这个属性指向函数的原型对象。而在默认情况下,所有的原型对象都会自动获得一个 constructor (构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
person1.sayName(); // "Nicholas"
var person2 = new Person();
person2.sayName(); // "Nicholas"
alert(person1.sayName == person2.sayName); // true

 

在此,我们将 sayName() 方法和所有属性直接添加到了 Person 的 prototype 属性中,构造函数变成了空函数。与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。换句话说,person1 和person2 访问的都是同一组属性和同一个 sayName() 函数。

虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
var person2 = new Person();

person1.name = "Grag";
alert(person1.name); // "grag"---来自实例
alert(person2.name); // "Nicholas"--来自原型

通过使用 delete 操作符可以完全删除实例属性

var person1 = new Person();
var person2 = new Person();

person1.name = "Grag";
alert(person1.name); // "grag"---来自实例
alert(person2.name); // "Nicholas"--来自原型

delete person1.name;
alert(person1.name); // "Nicholas"--来自原型

通过使用 hasOwnProperty() 方法,可以检测一个属性是存在实例中,还是存在于原型中

var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name")); // false
alert(hasPrototypeProperty("person","name")); // true

person1.name = "Grag";
alert(person1.name); // "grag"---来自实例
alert(person1.hasOwnProperty("name")); // true
alert(hasPrototypeProperty("person","name")); // false
alert(person2.name); // "Nicholas"--来自原型
alert(person2.hasOwnProperty("name")); // false

delete person1.name;
alert(person1.name) // "Nicholas"--来自原型
alert(person1.hasOwnProperty("name")); // false

更简单的原型写法

用一个包含所有属性和方法的对象字面量来重写整个原型对象

function Person(){}
Person.prototype = {
    constructor: Person, // 由于字面量写法,导致 constructor (构造函数的指针)不再指向 Person 了,所以我们需要特意将它设置适当的值
    name: "Nicholas",
    age: 29,
    job: "Software Engineer",
    sayName: function(){
        alert(this.name);
    }
}
var person1 = new Person();
alert(person1.name) // "Nicholas"

原型对象的问题

原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说得过去,毕竟通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,就有问题了---全部共享一个属性(无论怎样修改,其他实例的值都是一样的)

4.混合模式(组合使用构造函数模式和原型模式)

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}
Person.prototype = {
    constructor: Person,
    sayName: function(){
        alert(this.name);
    }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Grag", 27, "Doctor");

person1.friends.push("Van");
alert(person1.friends); // Shelby,Court,Van
alert(person2.friends); // Shelby,Court
alert(person1.friends === person2.friends); // false
alert(person1.sayName === person2.sayName); // true

这种构造函数与原型混成的模式,是目前在 ECMAScript 中使用最广泛,认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。

5.动态原型模式

function Person(name, age, job){
    //属性
    this.name = name;
    this.age = age;
    this.job = job;
    //方法
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            alert(this.name);
        }
    }
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();

这里只在 sayName() 方法不存在的情况下,才会将它添加到原型中。
使用动态原型模式时,不能使用对象字面量重写原型。

6.寄生构造函数模式

function SpecialArray() {
      var values = new Array()
      values.push.apply(values, arguments)
      values.toPipedString = function() {
        console.log(this)
        return this.join('|')
      }
      return values
    }
    var colors = new SpecialArray('red', 'blue', 'green')
    console.log(colors.toPipedString(), 666)
    var c = SpecialArray('red', 'blue', 'green')
    console.log(c.toPipedString(), 999)

 

这个例子其实是高程里面的例子,我分别通过构造调用和直接调用两种方式来创建对象,并且都调用了里面的方法,可以看到,结果是完全一致的。这让我很纠结,感觉这个new在这里没有用了,有他没他都一样啊。
仔细翻看了高程里面的介绍,是这么说的:

通常,在前述几种模式都不适用的情况下,可以使用寄生构造函数模式
除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实是一模一样的。 

 emmm,也就是说,这个模式就是在其他模式都不适用的情况下可以考虑使用。但是什么情况下其他模式会都不适用呢?暂时没有碰到这种情况,即使是书中提到的例子也就是上面的例子,也并非是在其他模式都不适用的情况下才这么写的。
综上,寄生构造函数模式我感觉就跟废了差不多,了解一下就行了。当然,如果有对这个模式更深入的理解以及非他不可的情况出现,望不吝在评论区留下见解。


7.稳妥构造函数模式

function Person(name, age) {
      const obj = new Object()
      const height = 185
      const eat = function() {
        console.log('吃饭')
      }
      obj.sayName = function() {
        console.log(name, age, height)
        eat()
      }
      return obj
    }
    const p = Person('windy-boy', 18)
    p.sayName()

 

 

这就是稳妥构造函数模式。就是对外暴露一个可以访问函数内部变量和方法的接口。只有通过这个接口才可以访问函数内部的变量和方法,其他方式都不行。这样的模式就是稳妥构造函数模式。
对比一下寄生构造函数模式,有两点不同:

  •     没有this
  •     没有new

其实我一直认为没有通过new调用的函数(也就是所谓的构造调用)就是普通函数,这里把函数名首字母大写来作为构造函数的标识,以这样的方式来和构造函数搭上钩。这是强行搭讪啊。。。个人感觉直接叫稳妥模式还好点。当然,这只是我的一点吐槽,发明这种模式的大师在命名的时候肯定有自己的考量,至于他的考量是什么,我也没有他电话,联系不到他,就不得而知了。。。

相比寄生构造函数模式,稳妥构造函数模式感觉更有机会用到。比如为了防止一些变量被意外更改,就可以使用稳妥构造函数模式。
 

 

 

 

100道测试工程师笔试的Linux笔试题及答案_网络安全工程师关于linux的笔试大题 47.Linux系统中,一般把命令 ls 定义为 ls --color 的别名,以便以不同颜色来标识不同类型的文件。但是,如何能够使用原先的ls命令?83.在xdm的配置目录中,哪个文件用来设置在用户通过xdm登录后自动起动的应用程序?45.你的系统使用增量备份策略,当需要恢复系统时,你需要按什么顺序恢复备份数据?84.命令 netstat -a 停了很长时间没有响应,这可能是哪里的问题?51.Linux中,提供TCP/IP包过滤功能的软件叫什么?88.TCP/IP中,哪个协议是用来进行IP自动分配的? 阅读详情

相关推荐

Intel Arc显卡玩《三角洲行动》报错?手把手教你修改注册表跳过验证

本文针对Intel Arc显卡用户在运行《三角洲行动》时遇到的驱动验证报错问题,提供了详细的解决方案。通过安全修改Windows注册表,添加特定键值以跳过游戏驱动兼容性验证,并结合游戏内图形设置与Intel驱动面板的优化建议,旨在帮助玩家顺利进入游戏并提升游戏帧率与运行稳定性。

weixin_29310605的博客 695

初学JavaScript:JS中创建对象的模式(工厂模式/构造函数模式/原型模式/组合模式)

工厂模式 构造模式 原型模式 组合模式

lalala_dxf的博客 2187

uniapp无感刷新token实现过程

可以看到已经触发了刷新token接口,并且重新请求上次失败的列表接口,无感刷新token逻辑已经正常,但为什么列表接口请求成功,还一直loading没关闭捏,就是因为后续代码未执行,await接口的返回没有成功resolve。路漫漫其修远兮,前端道路逐渐迷茫,时隔好久好久终于想起了我还有一个小博客,最近在一直在弄uniapp,属实有被恶心到,但也至少会用了,最近实现了一个比较通用的功能,就是无感刷新token,但在过程中发现一个问题就是。3、排查await的列表接口为何没有成功resolve。

weixin_40618068的博客 3594

js中创建对象的几种常用方式

通过构造函数的方式创建对象,对象和类型之间建立了联系,但是构造函数存在的一个缺点就是造成了不必要的函数对象的创建,因为在js中函数也是一个对象,因此如果对象属性中包含函数的话,那么每次创建对象就会新建一个函数对象,浪费了不必要的内存空间,因为函数是所有创建实例对象所通用的。一个是没有办法通过传入参数来初始化值,另一个就是因为是所有实例对象所共有的,那么当原型上的属性的属性值是引用类型数据(例如数组),那么一个实例对数据的改变会影响到所有的实例对象。字面量这种方式创建大量相似对象时,会产生大量重复代码。

m0_58571759的博客 1563

ST MotorControl Workbench 6.2.1 自定义硬件配置避坑指南

本文详细介绍了ST MotorControl Workbench 6.2.1在自定义硬件配置中的常见问题与解决方案,涵盖功率板配置、采样电路校准、电机参数设置及代码生成避坑指南,帮助开发者高效完成电机控制项目开发。

red88的博客 1023

硬件原理图:从软件思维到硬件接口的嵌入式开发破局指南

本文为软件开发者提供了读懂硬件原理图的嵌入式开发破局指南。文章将硬件原理图类比为“硬件系统的架构图”,引导读者将软件API调用思维迁移到硬件接口理解上,详细解析了电阻、电容、二极管等常见元器件的“硬件API”功能与选型逻辑,并通过实战电路拆解,阐述了从原理图分析到驱动代码编写的完整思维链条,帮助开发者建立软硬件协同的系统级视角。

lg888的博客 496

JavaScript抽象工厂模式:打造高效的对象创建工厂

抽象工厂模式是一种创建型设计模式,它可以通过提供一个接口来创建一系列相关或相互依赖的对象,而无需指定它们的具体类。抽象工厂模式是一种非常实用的设计模式,它可以帮助我们轻松地创建一系列相关的对象,并保证它们的一致性和可扩展性。在JavaScript中,我们可以使用函数来实现抽象工厂模式,从而提高代码的可读性和可维护性。

Sun_blog 593

倍福TwinCAT3 OPC UA配置全流程:从安装到无密码访问(附常见问题解决)

本文提供了倍福TwinCAT3 OPC UA配置的完整实战指南,重点讲解如何实现无密码游客访问。从软件安装、授权配置、服务器初始化到深度排错,详细解析了配置流程中的关键步骤与常见陷阱,帮助工程师高效打通PLC与上位系统的数据通讯通道。

vulkan6gpu的博客 472

【编程向导】JavaScript-创建对象一期讲解

是用来创建对象的一种最常用的设计模式。工厂模式不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂。工厂模式常见于大型项目,例如 jQuery 的对象,我们创建选择器对象之所以没有就是因为$()已经是一个工厂方法,其他例子例如都是工厂模式的实现。eval()工厂的目的:在于判断接口最终用哪个类实例化(故与接口密不可分)。使用工厂最终达到的效果是:多态,和类与类之间的松耦合。

松阳的编程向导 2207

YOLOv10改进,YOLOv10二次创新C2f结构采用WTConv卷积(感受野的小波卷积),ECCV 2024

WTConv 的核心思想是通过结合卷积神经网络(CNN)的强大特征提取能力与小波变换的多尺度特性,来实现大感受野的卷积操作,同时避免传统大卷积核带来的参数爆炸问题。传统的卷积操作通过滑动小窗口在图像上逐步执行局部特征提取,感受野的大小直接取决于卷积核的尺寸。随着卷积核的增大,参数量呈指数增长,导致网络训练效率降低、计算资源消耗增加。为解决这些问题,WTConv 提出了在小波域中执行卷积操作的策略。小波变换是一种常用于信号处理的技术,能够将信号分解为不同频率成分。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1023

Vue3 - Element Plus 全局修改更换主题色配置详细教程,element-plus自定义主题色全局替换主色调强力解决方案,支持动态修改主题颜色/动态皮肤,将默认蓝色主题色更换为其他颜色!

vue3,nuxt3,element-plus,组件库,主题色,修改主题颜色,更换主题色,如何修改组件默认主题蓝色,项目主题色定制,修改失败,主题色覆盖不了,:root直接修改,hover颜色没改,自定义主题色,vue3全局设置elementPlus主题色最新详细修改教程,怎么修改全局的颜色,scss变量,覆盖原来的主题色改为自己的颜色,统一替换,有没有好办法,颜色不变,失败,无效,动态主题切换,主题颜色怎么在项目里直接改,plus主题色更换,覆盖默认主题色,最强最好用,设置主题色,换肤,皮肤,动态更换

🏆 前端领域优质创作者 1万+

JS中创建对象有几种方法

构造函数本身跟普通函数一样,也不存在定义构造函数的特殊语法。唯一区别在于调用的方式不同,任何函数只要通过new 操作符来调用,都可以叫做构造函数。默认情况下构造函数的首字母大写,不大写也没有问题,主要是为了与普通函数区分。

Sapling 827

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【JavaScript 学习笔记】创建对象

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34314962的博客 97

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

JS如何创建对象和继承对象

JS创建对象的几种方法:工厂模式,构造函数模式,原型模式,混合模式,动态原型模式 1 在工厂模式中,在构造函数内部创建一个新对象,最后返回这个对象。当实例化时,我们不需要用new关键字,就像调用方法一样就可以实例化。 工厂模式的缺点是容易和普通函数混淆,只能通过命名来确认它是一个 构造函数。不推荐使用这种模式。 //factory pattern function createPer...

weixin_30348519的博客 72

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

JS面向对象,从创建对象到对象继承

以前写过一篇关于JS创建对象的帖子,JS创建对象的几种方法,突然想温习一下,所以写了下面的小例子,用来回顾这七种create pattern。 每种pattern都有自己的特色。 1 工厂模式中,在构造函数内部用 o={}创建一个新对象,最后返回这个对象。当实例化时,不需要用new关键字,就像调用一般的方法一样。 我们可以把create函数设想成一个贴牌工厂,面对不同的需求,制作出内在相同,

影子的影子在这里看你 340

javaScript创建对象

一、对象 ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值,对象或者函数。所以js中对象就是一组键值对。 面向对象的语言中,都是通过类的来创建任意多个具有相同属性和方法的对象实例的。但是js中没有类的概念,接下来我先通过一个例子来阐述js中没有“类”的概念蕴含的哲学。这点会让初学者很困惑,但是也正因为放下了“类”的概念,js对象才有了其他编程语言没有的活力。事实上js中对象的...

weixin_30587927的博客 78

JavaScript 创建对象的几种方式

这里创建对象,主要介绍三种方式:工厂模式、构造函数模式、原型模式、组合使用构造函数模式和原型模式。1、工厂模式 工厂模式是用函数来封装创建对象的细节,在函数里面创建对象并返回对象。function createPerson(name,age,job){ var o = new Obkect(); o.name = name; o.age = age; o.job =...

Lea 5818

js创建对象模式

一、工厂模式 function createPerson(name, age){ var obj = new Object(); obj.name = name; obj.age = age; obj.display = function(){ alert(this.name); }; return obj; } var ...

weixin_43378716的博客 182

js-创建对象

文章目录1.new 操作符 + Object 创建对象2.字面式创建对象 参考: 1. 1.new 操作符 + Object 创建对象 调用系统构造函数创建对象 1 var person = new Object(); 2 person.name = "lisi"; 3 person.age = 21; 4 person.family = ["lida","lier","w...

qq_37636738的博客 363

JS中创建对象的几种设计模式

工厂模式 定义:工厂模式非常直观,将创建对象的过程抽象为一个函数,用函数封装以特定接口创建对象的细节。通俗地讲,工厂模式就是将创建对象的语句放在一个函数里,通过传入参数来创建特定对象,最后返回创建的对象。 缺陷:工厂模式虽然可以创建多个相似的对象,但却不能解决对象标识的问题,即怎样知道一个对象的类型(如下,我只知道s1是Object-...

weixin_33785108的博客 187

javascript创建对象的七种方式

工厂模式 // 工厂模式 function createPerson(name, age, job){ var obj = new Object() obj.name = name obj.age = age obj.job = job obj.sayName = function(){ console.log(this.name); ...

qq_39910307的博客 241
上一篇: css实现炫酷的圆环相交转动动画
下一篇: onmouseover 、onmouseout 与onmouseenter 、onmouseleave的区别
狗都不敲代码
博客等级 码龄4年 7粉丝 7原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值