js - 原型继承和应用

前言:本文大体摘自:https://blog.csdn.net/sysuzhyupeng/article/details/54645430    这位CSDN博主写的十分的好,逻辑性很强。后面 “如何安全的扩展一个内置对象 ” 是我添加的。顺便把这位博主的  详解js中extend函数  和  call和apply上手分析  摘抄下来。

原型继承:利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就叫做原型继承.

原型继承是js的一种继承方式,原型继承是什么意思呢,其实就是说构造函数和子构造函数,或者说类和子类之间(当然js中不存在类),唯一的继承传递方式是通过原型,而不是其他语言直接通过extends(当然ES6的语法糖出现了extends)。所以你需要手写prototype。(封装手写prototype的方法请看我的另一篇文章详解js中extend函数) 我们先看一个简单的例子

具体看例子:

1 function Parent(){
2       this.job = ‘teacher‘;
3    }
4    Parent.prototype.showJob = function(){
5       alert(this.job);
6    }
7    var child = new Parent();
8    child.showJob();      //‘teacher‘ 

很明显,这个例子中的child获得属性job和一个方法showJob,为什么会获得呢? 这时候来看看new Parent()到底做了什么

1  var obj = { };   //obj获得Parent的this引用
2    obj.job = ‘teacher‘;
3    obj.__proto__ = Parent.prototype;
4    var child = obj;

所以为什么child获得了属性job,是因为他执行了构造函数,child对象上获得了属性job。而为什么child获得了方法showJob, 是因为对象上有一个隐藏的原型__proto__ ,它指向了Parent.prototype。当我们在对象child上调用方法时,它首先检查对象自己是否具有这个方法,没有的话搜索自己的隐藏原型中有没有这个方法。

所以,原型继承是什么,它的本质是改变其他对象的__proto__,或者说让它丰富起来,以获得父构造函数或者祖先构造函数的方法,请看代码。

1  function Parent(){
2    }
3    Parent.prototype.showJob = function(){}
4    function Child(){
5    }
6    Child.prototype = new Parent();
7    Child.prototype.constructor = Child;
8    var grandChild = new Child();

这时候grandChild获得了showJob方法,因为它的__proto__中有showJob方法,而为什么它的隐式原型中有这个方法呢,因为new Child()中grandChild.__proto__指向了Child的prototype, 至于为什么Child的prototype中有showJob方法,因为Child.prototype.__proto__等于Parent.prototype. 
至于为什么有这么一句

1 Child.prototype.constructor = Child;

这是因为原本Child.prototype中有一个constructor属性指向Child本身,当执行Child.prototype = new Parent()的时候,Child.prototype.constructor指向了Parent,否则下一次new Child的时候,constructor的指向就会不正确,当然,这个在实际开发中即时漏掉也不会有大问题,因为我们很少会对constructor进行读写。 
以上代码还有另一个问题,为什么我们要把showJob这个方法写在Parent.prototype上呢,如果写成如下

1  function Parent(){
2         this.showJob = function(){}
3     }
4     function Child(){
5     }
6     Child.prototype = new Parent();

当然这样写也可以,child.prototype对象上有了showJob方法,而不是child.prototype.__proto__,这对于我们原型链的继承并没有影响。然而这样写的方法一多,child.prototype对象上的方法就越多,如果new了多次的话,在内存上会比写在原型上多一些消耗。

那么在实际开发中,会怎么实现面向对象的原型继承呢。正常在我们拿到需求的时候,如果需求逻辑复杂,且在多个页面中有相似逻辑的时候,我们就会想到使用面向对象了,因为面向对象解决的就是逻辑的封装和复用。 
假设页面A,页面B,页面C中存在相同逻辑,那么我们可以封装父构造函数对象

 1  function Parent(){}
 2    Parent.prototype = {
 3       method1: function(){},
 4       method2: function(){},
 5       ...
 6    }
 7    function A(){      //页面A
 8       this.A = A;
 9    }
10    A.prototype = new Parent();
11    A.prototype.otherMethod = function(){};
12
13    var a = new A();   //使用对象
14    a.init...

首先将页面A,页面B,页面C中相同逻辑抽离,相同逻辑可以是同一个ajax请求返回数据,或者是数据格式化等等的相同操作。将这些方法在Parent.prototype中定义,至于A,B,C页面自己特有的方法,则在如A.prototype中定义。这样很好地了解决了我们的问题,逻辑清晰,代码复用性强。 如果在Parent方法参数中加入了回调callback,并且在callback中想调用子函数方法或者属性,可以参考我另一篇博文call和apply上手分析

hasOwnProperty

hasOwnProperty方法可以检测一个属性是存在于实例中,还是存在于原型中。

 1  function Parent(){
 2       this.name = ‘sysyzhyupeng‘;
 3    }
 4    Parent.prototype.job = ‘teacher‘;
 5    Parent.prototype.showJob = function(){
 6    }
 7    var parent = new Parent();
 8    parent.hasOwnProperty(‘name‘);  // true
 9    parent.hasOwnProperty(‘job‘);  // false
10    //方法也可以
11    parent.hasOwnProperty(‘showJob‘);  // false 

in

in运算符和hasOwnProperty不同,只要存在在原型上或者对象上就返回true

 1  function Parent(){
 2       this.name = ‘sysyzhyupeng‘;
 3    }
 4    Parent.prototype.job = ‘teacher‘;
 5    Parent.prototype.showJob = function(){
 6    }
 7    var parent = new Parent();
 8    ‘name‘ in parent;  // true
 9    ‘job‘ in parent  // true
10    for(_key in parent){
11       console.log(_key);  // ‘name‘, ‘job‘, ‘showJob‘
12    }

在使用for-in循环时,返回的是所有能通过对象访问的且可枚举的属性。所有开发人正常定义的属性都是可枚举的,只有在IE8及更早版本除外。

Object.keys

ES5的Object.keys方法可以返回对象上的所有可枚举属性(注意只有对象上的,从原型上继承的没有)

如何安全的扩展一个内置对象

给内置对象新增成员和方法,叫做扩展内置对象。这种行为是不可取的。因为原生的内置对象本身就有一些方法和属性,在一个项目中,如果你替换了这些方法,别人就用不到了,容易造成代码崩溃,不宜维护。

如何安全的扩展一个内置对象呢?   就比如 内置对象Array, 我们既想用它本身的一些方法,又想给它添加一个sayHello()方法。这样到底怎么去做呢?

首先我们创建一个对象,让这个对象继承内置对象Array,这样Array数组里面的方法就可以在我们创建的对象中使用,然后在我们创建的对象添加我们自定义的方法。这样无论我们怎么修改自己创建的对象里面的方法,都不会影响到内置对象。

 1        function MyArray() {      //自己定义函数对象MyArray
 2             //我自己定义的属性
 3             this.name = "我是一个数组";
 4             this.sayHello = function () {
 5                 console.log("我的sayHello方法");
 6             }
 7         }
 8
 9         var arr = new Array();     //内置对象Array创建的对象arr
10
11         MyArray.prototype = arr;  // 替换原型对象 也就是原型对象继承数组,我的数组中就有了原生数组对象的所有的属性和方法
12         MyArray.prototype.hello =function () {
13             console.log("大家好,我是自定义对象MyArray的原型中的hello方法");
14         }
15
16         var myArr = new MyArray();  //myArr这个对象就继承自arr
17
18         myArr.push(100);         //原生内置对象Array自带的push的方法
19         myArr.push(2,3,4,5)
20         console.log(myArr);
21         myArr.sayHello();
22         myArr.hello();           

原文地址:https://www.cnblogs.com/gshao/p/9460520.html

时间: 2024-10-08 12:51:47

js - 原型继承和应用的相关文章

JS原型继承与类的继承

我们先看JS类的继承 1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>JS类的继承</title> 7 </head> 8 9 <body> 10 /* -- 类式继承 -- */ 11 <script type="text/javascript"> 12 //先声

JS原型继承和类式继承

类式继承(构造函数) JS中其实是没有类的概念的,所谓的类也是模拟出来的.特别是当我们是用new 关键字的时候,就使得"类"的概念就越像其他语言中的类了.类式继承是在函数对象内调用父类的构造函数,使得自身获得父类的方法和属性.call和apply方法为类式继承提供了支持.通过改变this的作用环境,使得子类本身具有父类的各种属性. JavaScript var father = function() { this.age = 52; this.say = function() { al

js原型继承

原型链: Object(构造函数) object(类型(对象)) var o = {}; alert(typeof o); //结果是object alert(typeof Object); //结果是function 每一个对象都有一个属性叫 __proto__ ,这个属性就是这个对象的原型(o. __proto__),函数可通过 函数名.prototype 获取原型,对象可以通过 对象.__proto__(双下划线)获取. 对象有原型,原型也是对象,所以原型也有原型,所有的函数都是对象,继承

关于js原型继承

js的每个类都有一个prototype对象 访问对象的属性时,会先访问到对象自身是否有定义这个属性 如果没有定义,就会去访问对象所属类型的prototype对象是否有此属性 原型继承就是把类型的prototype指向一个父类的新对象,这样每派生一个新类出来都会构造一个新的父类对象作为原型,这个对象和父类的prototype是分离的 因而可以用于添加子类的新属性而不影响父类 > function cls(){xx = function(){console.log(11)}} undefined >

JS 原型继承的几种方法

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <script type="text/javascript"> function Person() { this.name = '老王

我的博客园初篇 解密 js原型继承

网上的关于原型继承的文章多入牛毛 但是我感觉并不适合新手了解 首先假如这位新手了解过面向对象java啊 c#啊他会理解继承 但是和javascript的继承有有所不同,又假如这位新手初入前端 以前没了解过面向对象 你和他说一大堆术语 更加把他搞得蒙头转向.我在这里尝试用人类认知的模式来解释什么事原型继承以及为什么需要它. 从某种意义来说面向对象的三大特性在我看来是为了“偷懒”(纵观全世界科技发展莫不如此)而由聪明人想出来的法子,在代码世界中,代码的复用也就是多次使用时司空见惯的,比如你一进门就写

js原型继承的几种方式

1. 原型链继承 2,构造函数继承(对象冒充继承) 3,组合继承(原型链继承+构造函数继承) 4,原型式继承 5. 寄生组合式继承 一.原型链继承 function Show(){ this.name="run"; } function Run(){ this.age="20"; //Run继承了Show,通过原型,形成链条 } Run.prototype=new Show(); var show=new Run(); alert(show.name)//结果:ru

分享一个js原型继承的方法

function Person(){ this.color = [23,2,3,32] } undefined var p = Object.create(new Person()) undefined p.color.push(1)

JS 类继承 原型继承

参考文档:JS原型继承和类继承 <script src="jquery-2.0.3.js"> </script> <script> /*//类继承 var father=function(){ this.age=53; this.say=function(){ console.log("name:"+this.name+",age:"+this.age); } }; var child=function(){