一、创建对象的几种方式
1、各自独立声明模式
var box1 = new Object(); //声明第一个对象并给各属性赋值 box1.name = 'Lee'; box1.age = 100; box1.run = function () { return this.name + this.age + '运行中...'; }; alert(box.run()); var box2 = new Object(); //声明第二个对象并给属性赋值 box2.name = 'Jack'; box2.age = 200; box2.run = function () { return this.name + this.age + '运行中...'; }; alert(box2.run());
此时box2和box1是相互独立的,不会混淆。
但是这样子每声明一个结构相同的对象,都得加一段代码,特别不方便,所以有了下面的工厂模式。
2、工厂模式
function createObject(name, age) { //集中实例化的函数 var obj = new Object(); obj.name = name; obj.age = age; obj.run = function () { return this.name + this.age + '运行中...'; }; return obj; }
这样子每次new对象时只需调用createObject()方法即可,同时,还可以传参初始化对象。
但由于new出来的对象都从属于Object,当我要使new出来的对象在本质做一些区分的时候,就不行了,此时就有了更简便的构造函数模式。
3、构造函数模式
function Box(name, age) { this.name = name; this.age = age; this.run = function () { return this.name + this.age + '运行中...'; }; } var box1 = new Box('Lee', 100); var box2 = new Box('Jack', 200); alert(box1.run()); alert(box1 instanceof Box); //很清晰的识别他从属于Box
构造函数模式很大程度上解决了对象复用及传参初始化问题,是最常用的new对象的模式。
注意:
此处box1.run != box2.run, 因为他们判断的是引用地址,由此可知,两个对象的方法分别存储在不同的地方,是两个不同的方法。
但 box1.run() == box2.run(),因为它们返回值一样。
当有了对象以后,自然而然就会涉及到对象属性及方法的共享问题(比如,在java中子类们共享父类的成员变量及方法)。
构造函数模式创建出的对象说白了还是相互独立的(比如上面的box1.run != box2.run),如果我要在两个对象之间共享某些属性的话,就必须要采用原型prototype了。
二、通过原型创建对象
1、原型模式
function Box() {} //声明一个构造函数 Box.prototype.name = 'Lee'; //在原型里添加属性 Box.prototype.age = 100; Box.prototype.arr = ['aaa','bbb']; Box.prototype.run = function () { //在原型里添加方法 return this.name + this.age + '运行中...'; }; var box1 = new Box(); var box2 = new Box(); //修改普通属性,看下会不会影响prototype alert(box1.name); //Lee box1.name = 'Rinima'; alert(box1.name); //Rinima alert(box2.name); //Lee,修改box1的普通属性,相当于直接在box1中添加一个属性,是不会牵扯到原型中的属性的。 //这一点非常好。但是如果是引用对象(数组)的话,就有问题了。 //修改引用属性,看下会不会影响prototype alert(box1.arr); //aaa,bbb box1.arr.push('ccc'); alert(box1.arr); //aaa,bbb,ccc alert(box2.arr); //aaa,bbb,ccc,修改box1的引用属性,却牵扯到了原型中的属性。 //这是因为arr只是个引用地址,指向数组真实存储的位置,修改box1中的引用属性就是修改引用所指向的数组,所以原型也被修改了 //这是我们不希望看到的!
该模式的优点:
1、所new出来的对象在prototype中的属性是共享的,此时box1.run == box2.run
2、能保证所new的对象实例的属性完全统一(和缺点2相对)
该模式的缺点:
1、当含有引用类型的属性时,引用类型所指向的属性是存在prototype中,直接在对象中修改引用属性就把所有对象的引用属性都修改了
2、该种模式省略了初始化传参,使得new出来的所有属性都是一样的
1.1、原型字面量模式
(原型模式的另外一种模式,大体上区别不大,都属于原型模式)
function Box() {}; Box.prototype = { //使用字面量的方式 constructor : Box, name : 'Lee', age : 100, run : function () { return this.name + this.age + '运行中...'; } };
该模式继承了原型模式的所有优缺点,但是也有自己特有的优缺点
优点: 更好的体现了封装性
缺点: constructor没有指向自身,必须手动强制指向
2、构造函数 原型模式
function Desk(name, age) { //不共享的使用构造函数 this.name = name; this.age = age; this.family = ['aaa', 'bbb', 'ccc']; }; Desk.prototype = { //共享的使用原型模式 constructor : Desk, run : function () { return this.name + this.age + this.family; } }; var desk1 = new Desk('Lee',100); var desk2 = new Desk('Jack',200); alert(desk1.family); //aaa,bbb,ccc desk1.family.push('ddd'); alert(desk1.family); //aaa,bbb,ccc,ddd alert(desk2.family); //aaa,bbb,ccc
优点: 这种模式完美解决了共享属性与不共享属性的问题,而且可以精确控制,是非常不错的模式。
缺点: 但是此种办法,原型与构造函数相分离,让人感觉很怪异,体现不了封装。
3、动态原型模式
function Box(name ,age) { //将所有信息封装到函数体内 this.name = name; //不共享的属性 this.age = age; if (typeof this.arr != 'object') { //共享的属性 alert('在第一次调用的时候...arr'); Box.prototype.arr = ['aaa','bbb']; } if (typeof this.run != 'function') { alert('在第一次调用的时候...run'); Box.prototype.run = function () { return this.name + this.age + '运行中...'; }; } } var box1 = new Box(); var box2 = new Box(); alert( box1.arr ); //aaa,bbb box1.arr.push('ccc'); alert( box1.arr ); //aaa,bbb,ccc alert( box2.arr ); //aaa,bbb
优点:这个模式继承了上一个模式(构造 原型)的所有优点,同时也完美解决了封装性问题
注意:此种模式书写原型时不可用字面量模式,会切断实例和新原型之间的联系的。???
基本到这里,以上两种模式已经能处理大多数问题,而且是比较好的模式了。
但是,还是有一些比较特定的需求,需要用到以下两种比较另类的模式。
4、寄生构造函数模式(工厂模式 构造函数模式)
function Box(name, age) { var obj = new Object(); obj.name = name; obj.age = age; obj.run = function () { return this.name + this.age + '运行中...'; }; return obj; }
5、稳妥构造函数模式
function Box(name , age) { var obj = new Object(); obj.run = function () { return name + age + '运行中...'; //直接打印参数即可 }; return obj; }
稳妥构造函数模式,是当构造函数里不允许使用this,外部实例化时不准用new时,才需要用到的模式。
我也不知道为啥会出现这样那么奇葩的需求。不过这么多的创建对象模式,确实比Java眼花缭乱多了。
以上是理解JavaScript创建对象与通过原型创建对象的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

Atom编辑器mac版下载
最流行的的开源编辑器

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境