js面向对象的程序设计 --- 中篇(创建对象) 之 原型模式
·原型模式 我们创建的每一个函数都由一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有 实例共享的属性和方法。 如果按照字面意思来理解,那么prototype就是通过构造函数创建的那个对象实例的原型对象。使用原型对象的好处就是可以让所有对象实例共享它 所包含的属性和方法 // code示例
function Person(){} Person.prototype.name = 'Nicholas'; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function () {console.log(this.name); }; var person1 = new Person(); person1.sayName(); //Nicholasvar person2 = new Person(); person2.sayName(); //Nicholas console.log(person1.sayName === person2.sayName); // true
理解原型对象: 1:无论什么时候,只要创建了一个新函数们就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。 2:在默认情况下,所有原型对象都会自动获得一个constructor属性,至于其它方法,则都是从Object继承来的。 3:当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMAScript中管这个 指针叫[[Prototype]] 4: 要明确 [[Prototype]] 这个连接存在于实例与原型对象之间,而不是存在于实例与构造函数之间 示意图: // 图片
对示意图的理解: 1:Person.prototype指向了原型对象。而Person.prototype.constructor又指回了Person 2:Person的每一个实例,都包含一个内部属性,该属性仅仅指向了Person.prototype 3:原型最初只包含constructor属性,而该属性也是共享的,因此可以通过对象实例访问 4:当代码读取某个对象的属性时,都会执行一次搜索,如果在实例中找到,则返回该属性。没有则在原型对象中查找 5:当为对象实例添加一个属性时,这个属性会屏蔽原型对象的同名属性;换句话说,添加这个属性只会阻止我们访问原型中的那个属性,但不会修改 那个属性。即使将这个属性设置为null,也只会在实例中设置这个属性,而不会恢复其指向原型的连接。 注意:所有实现都无法访问到[[Prototype]],那我们怎么得到一个对象的原型对象呢?
// 返回[[Prototype]]的值console.log(Object.getPrototypeOf(person1) === Person.prototype); // true使用Object.getPrototypeOf()返回的对象其实就是这个对象的原型,而这在利用原型实现继承的情况下是非常重要的
注意:我们如何得出一个属性是存在于实例中,还是存在于原型中。这个方法(不要忘了它是从Object继承来的)只在给定属性存在于对象实例中时,才会返回true
function Dog(){}Dog.prototype.name = "tom";var dog_a = new Dog();console.log(dog_a.hasOwnProperty("name")); // falsedog_a.name = "jack"; // 该实例重写了name属性console.log(dog_a.hasOwnProperty("name")); // true
原型与in操作符 有两种情况使用in操作符:单独使用和在for-in循环使用 ·单独使用: in操作符通常会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。 于是我们可以结合对象的hasOwnProperty()方法设计一个公共函数,来确定是否只存在原型中 // code..
// 如果属性只存在原型中则返回truefunction test(obj,val){return (!obj.hasOwnProperty(val)) && val in obj;}
·for-in循环: 使用for-in循环,返回的时所有能够通过对象访问,可枚举(enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性 更简单的原型语法 为了减少不必要的输入,也为了从视觉上更好的封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象 //code..
function Person(age){this.age = age;}Person.prototype = {area : "CHINA",say : function () {console.log('hello');}}var p1 = new Person(11);console.log(p1.constructor); //ƒ Object() { [native code] }// 这里出了一个意外,constructor属性不再指向Person了。我们刚才的语法,实际上是重写了默认的prototype对象,因此constructor属性//变成了新对象的constructor属性(指向Object)构造函数,尽管instanceof操作符还能返回正确结果,但通过constructor已无法确定对象类型console.log(p1 instanceof Person);console.log(p1.constructor == Person);console.log(p1.constructor == Object);// 解决方式初级版Person.prototype = {constructor : Person,area : "CHINA",say : function () {console.log('hello');}}//弊端:这种方式重设constructor属性会导致它的[[Enumerable]]特性为true。默认情况下,原生的constructor属性是不可枚举的。//最终解决方法Object.defineProperty(Person.prototype,"constructor",{enumerable : false,value : Person})
原型的动态性 由于在原型中查找值的过程中是一次搜索,因此我们对原型对象所作的任何修改都能够立即从实例上反应出来---即使是先创建了实例后修改原型也照样如此。
function Person (name) {this.name = name;}Person.prototype.area = 'china';var friend = new Person('cl');console.log(friend.area); // chinaPerson.prototype.area = 'japan';console.log(friend.area); // japan// 实例与原型对象之间的连接只不过是一个指针,而非一个副本Person.prototype = {area : 'test',}console.log(friend.area); // japan// 重写原型对象切断了现有原型与之前已经存在的对象实例之间的联系;它们引用的仍然是最初的原型。
原生对象的原型 原型模式的重要性不仅体现在创建自定义类型方面,就连所有远程的引用类型,都是采用这种模式创建的。 所有原生引用类型(Object,Array,String等等),都在其构造函数的原型上定义了方法。
console.log(typeof Array.prototype.sort); // functionconsole.log(typeof String.prototype.substring); // function// 通过原生对象的原型,不仅可以取得所有默认方法的引用,而且也可以定义新方法。可以像修改自定义对象的原型一样修改原生对象的原型// 因此可以随时添加方法String.prototype.startsWith = function () {return this.indexOf(text) == 0;}// 尽管可以这样做,但是不推荐。因为这样会导致命名冲突或者意外的重写原生方法
组合使用构造函数模式和原型模式 创建自定义类型的最常见方式,就是组合使用构造函数与原型模式。构造函数模式用来定义实例属性,而原型属性用与定义方法和共享的属性。 结果,每个实例都会有自己的一份实例属性的副本,但又共享着对方法的引用,最大限度地节省了内存 这种构造函数与原型混成的模式,是目前在ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认方式 动态原型模式 有其他oo语言经验的开发人员看到独立的函数和原型时,很可能会感到困惑。动态原型模式正是致力于解决这个问题的一个方案,它把所有信息都封装在 构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持同时使用构造函数和原型的优点。
function Person(name ,age, job){this.name = name;this.age = age;this.job = job;if(typeof this.sayName != "function"){// 这段代码只有在初次调用构造函数才会执行Person.prototype.sayName = function () {console.log(this.name);}}}// 使用动态原型模式时,不能使用对象字面量重写原型。如果在已经创建了实例的情况下重写原型,那么就会切断现有实例与新原型之间的联系
寄生构造函数模式
function Person(name,age,job){var o = new Object();o.name = name;o.age = age;o.job = job;o.sayName = function () {console.log(this.name);}return o;}var friend = new Person('Ni',29,"eng");friend.sayName(); // Ni//在这个例子中,Person函数创建了一个对象,并以相应的属性和方法初始化该对象,然后又返回了这个对象。除了使用new操作符并且把使用的包装函数// 叫做构造函数之外,这个模式跟工厂模式其实是一模一样的
稳妥构造函数模式 所谓稳妥对象,指的是没有公共属性,而且其方法也没不引用this对象。稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用this和new), 或者在方式数据被其他应用程序改动时使用。稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的常例方法不引用this; 二是不使用new操作符调用构造函数。按照稳妥构造函数的要求,可以将前面的Person构造函数重写如下:
function Person(name){var o = new Object();o.sayName = function () {console.log(name);}return o; }var friend = Person('Ni'); friend.sayName(); // Ni//注意 : 在以这种模式创建的对象中,除了使用sayName()方法之外,没有其他方法访问name的值// 即使有其他代码会给这个对象添加方法和数据成员,但也不可能有别的方法传入构造函数中的初始数据。// 构造函数模式提供的这种安全性,使得它非常适合在某些安全执行环境。
转载于:https://www.cnblogs.com/cl94/p/11259420.html
js面向对象的程序设计 --- 中篇(创建对象) 之 原型模式相关推荐
- js面向对象的程序设计 --- 中篇(创建对象) 之 工厂模式和 构造函数模式
创建对象 虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量重复代码. ·工厂模式 工厂模式是一种广为人知的设计模式,这种模式 ...
- JS面向对象的程序设计之创建对象_工厂模式,构造函数模式,原型模式-1
前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下.如有纰漏或错误,会非常感谢您的指出.文中绝大部分内容引用自<Ja ...
- JS面向对象的程序设计之继承-继承的实现-借用构造函数
JS面向对象的程序设计之继承-继承的实现-借用构造函数 前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下.如有纰漏或错误 ...
- Js面向对象的程序设计——理解对象
Js面向对象的程序设计 Js面向对象的程序设计 理解对象 属性类型 Js面向对象的程序设计 理解对象 示例 : var person=new Object(); person.name="N ...
- JS面向对象的程序设计
面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装.继承.多态的特性!但JS中 对象与纯面向对象语言中的对象是不同的,ECMA标准定义 ...
- js创建对象之原型模式2原型与in操作符
<!DOCTYPE html> <html><head><meta charset="UTF-8"><title>< ...
- js面向对象的程序设计 --- 下篇 继承启蒙
继承是oo语言中一个最为人津津乐道的概念.ECMAScript支持实现继承,而且实现继承只要是靠原型链来实现的 ·原型链 其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 简单回顾一 ...
- JavaScript高级程序设计读书笔记(第6章面向对象的程序设计之创建对象)
2019独角兽企业重金招聘Python工程师标准>>> 面向对象语言都有"类"的概念,而通过类可以创建任意多个具有相同属性和方法的对象. JS中没有"类 ...
- 【天赢金创】面向对象的程序设计之创建对象
对象的定义:无序属性的集合,属性的值可以是基本值.对象或者函数. 每个对象都是基于一个应用类型创建的,这个引用类型可以是内置的(例如Object Array Math),也可以是用户自定义的. 基于O ...
最新文章
- Kmeans聚类算法分析(转帖)
- iOS架构-制作属于自己的cocoapods以及podspec文件讲解(20)
- python3 打印完整报错信息 以flask 为例
- JavaScript 技术篇-js字符串大小写转换,toLocalUpperCase()和toUpperCase()的区别详解
- Nginx的405 not allowed错误解决
- fft快速傅利叶变的C实现
- ABAP Netweaver和SAP Hybris的内存管理
- 谈区块链的时候别忘记了“新零售”
- ML/DL-复习笔记【四】- DeepLab系列模型总结
- 三维点云数据处理软件供技术原理说明_三维扫描数据处理技术_点云数据处理...
- 【R语言】如何直接调取Wind、iFinD数据接口教程
- Android模拟器6.0,逍遥安卓模拟器新版6.0.0 刺激战场手游流畅不卡专版
- jfreechart-x轴刻度倾斜45度
- python入门笔记——类和对象③(案例:自动随机文字游戏——决战紫禁之巅)
- 前端实现导入PPT在线编辑
- 北邮信通导论第三单元智能温控风扇
- css3切角文本框_CSS3如何实现4个切角
- ora-12505 监听程序当前无法识别sid
- Linux运维:推荐八款Linux远程连接工具
- 分支过程灭绝概率matlab,某类遗传环境下的两性分支过程:有关伴Y基因的灭绝概率问题...
热门文章
- node+读写文件_python高级:2.文件读写part2
- 基于深度学习的咖啡叶病害识别和严重程度评估(源代码+数据集)
- mysql pdo支持_使php支持pdo_mysql
- 连通域的原理与Python实现
- 【项目.源码】深度学习实现任意风格任意内容的极速风格迁移
- 今日头条下拉词框怎么做的呢?怎么优化推广呢?
- php validate验证用户,PHP validate 数据验证demo
- php十年磨一剑,十年磨一剑
- gpg: 找不到有效的 openpgp 数据。_萤火数据|找主播堪比相亲找对象,该如何避免心酸血泪史?...
- 计算机学习知识,如何学习计算机知识呢