废话,可以跳过:好懒,好久没写东西了,总结了好久的正则表达式也没有出炉。最近在干啥,倒叙:git github怎么用,计算机网络,http协议,javascript面向对象,javascriptECMA标准,正则表达式,RESTful原则,php,css inline & block 等等,表示 inline和block还是一塌糊涂,等待研究。需要学的东西好多,亚历山大~~~
前言:可能会写三到四篇关于js链式继承以及面向对象的东西,大都是不同书籍的笔记、总结以及自己的理解。
涉及的书:
1.Object-Oriented JavaScript
2.Professional JavaScript for Web Developers[红书,javascript高级程序设计]
3.JavaScript Web Applications
正文
(一)javascript中"类"的继承是基于原型链的。什么是原型[prototype]链?
先举个例子
[想这个例子好纠结,纠结于js中“类”和Php、C#、java中类的含义其实是不一样的,我纠结于是否有必要阐述下两者的不同,想想还是算了。也许后文慢慢会说明白。如果你对其他语言中类的含义有所理解,希望在理解原型的时候,更多的是比较有何不同,着重理解原型链的本质,不要急于想用原型怎么达到类的效果。]
[我们可以用原型链做很多有趣事情,不用较真js如何构造一些诸如private public static 等关键字的实现]
类可以理解为种类,是一些特性的集合;对象是类的实现,是具体特性的实现。
动物,马,人,车都可以看做是类,是概念;具体到他家的狗,他妹,他家的车都是实物,是对象。
面向对象的程序设计,这种说法不一定确切,但是可以这么粗糙的理解。
继续举例子
原型链 更像是“我爸是李刚”,我儿子有事,先找我,我如果有事解决不了,就找李刚。
js中的每个对象,都包含有一个指针,指向它的原型。当我们调用一个js对象obj的属性或者方法时,obj先在直接属于自己的属性、方法中找,如果找不到,就在它的原型里找,如果找不到,再在原型的原型里找。
我是一个人,一个对象,我爹也是个人,一个对象。我儿子办成什么事情,外人不一定清楚到底是谁的本事。
objA是一个对象,它的原型objB也是一个对象,objC也是一个对象,每个对象都有他们自己的属性和方法。当objA.fun()执行时,如果objA不含有fun这个方法,解释器会在objA的原型对象objB查找,一直向上找。我自己认为,这种原型链的思想,不一定理解成父子的关系,也不一定要理解成继承关系。就像社会关系,不一定只是父子,也可以是师生、朋友。
这是原型链的一个概貌。和普遍意义上类的继承有很大差距,其他语言中如果按照“链”的方式去理解继承关系,更多是在类(Class)层面上,鸟有飞的方法,马和牛都是哺乳动物,他们都是生物。javascript是没有类(Class)这一说法的。
(二)原型如何实现
构造对象一般会见到两种最基本的形式:字面量和构造函数
/*字面量*/ var jim = {}; jim.name = "Jim"; jim.sayHello = function(){alert(this.name);}; var hanmeimei = { name:"hanmeimei", sayHello:function(){alert(this.name);} }; /*构造函数*/ function Person(name){ this.name = name; this.sayHello = function(){alert(this.name);}; } var zhangsan = new Person("zhangsan"); var lisi = new Person("lisi"); lisi.toString();
上面的代码中,原型在哪里??(不知道能扯多远,本来第一篇文章是讲o-o javascript那本书的笔记的,哎,就变成js对象基础介绍了)
javascript中函数也是一种对象,我们定义的Person 是Function的实例。
原型是函数实例的一个属性。
原型本身是一个对象,他是在函数定义的时候创建的。
Person定义的过程中,Person会得到一个prototype的属性,指向一个内部生成的对象(就是一个普通的Object)。执行 如lisi.toString();的时候,这个方法其实是这个原型对象的。
lisi又是如何和Person的原型对象扯上关系的呢?
var lisi = new Person("lisi");
这简单的一句话,华丽丽地做好好多你不知道的事情,比如说一下这些(有很多,具体可以参看ECMA的标准)
1.实例化一个Object对象,Person函数中的this指向这个对象
2.给这个对象加上一个内部私有属性(如__proto__,不通的浏览器宿主实现不一样),指向Person的原型(函数的原型对象是在函数定义的时候产生的,现在是实例化一个对象,这是两个过程)
3.执行函数Person中的代码
4.如果函数Person的返回值不是对象,或者没有返回值,返回步骤1中生成的对象;如果有返回值,返回这个对象。
小结:
1.原型(prototype)是函数的一个属性,原型对象在函数定义时产生。
2.通过构造函数产生对象的时候,这个对象会有一个内部属性(__proto__),指向函数的原型对象。
3.一个对象没有实现某方法、属性时,会向它内部指向的原型去查找。
(三)我们如何通过上面的小结,用原型链实现继承??
我们尝试地基于Person"类",实现一个Coder"类",继承Person的属性和方法。
function Person(name){ this.name = name; this.sayHello = function(){alert(this.name);}; } function Coder(language){ this.language = language; this.code = function(){alert("i am a "+this.language+" coder");}; } Coder.prototype = new Person("无名"); var c1 = new Coder("js");
c1.sayHello();
c1.code();
var c2 = new Coder("js");
c2.sayHello();
c2.name = "jim"; c2.sayHello();
c2.code();
你能理解吗?运行下看看~~~
//这是Person构造函数 //函数定义的时候,会产生一个原型对象,Person.prototype指向这个对象 function Person(name){ this.name = name; this.sayHello = function(){alert(this.name);}; } //这是Coder构造函数 //函数定义的时候,会产生一个原型对象,Coder.prototype指向这个对象 function Coder(language){ this.language = language; this.code = function(){alert("i am a "+this.language+" coder");}; } //这里是关键,我们修改了原生的原型对象,而是把prototype指向一个Person的实例,后面还会再次详细解释。 Coder.prototype = new Person("无名");
var c1 = new Coder("js");
c1.sayHello();
c1.code(); //执行构造函数,对象c有个内部属性(__proto__)指向Coder的原型对象
var c2 = new Coder("js"); //c2此时没有name属性,会查找原型对象中的name属性 alert(c2.name); //给c2增加name属性,此处再做解释 c2.name = "jim"; //同样,c2没有sayHello方法,执行的是原型对象的方法 c2.sayHello(); //c2自己的方法 c2.code();
我们人工的修改了Coder的prototype属性,指向一个Person的实例。
c2调用sayHello方法的时候,自己没有这个方法,就会通过__proto__指针查找Coder原型对象(即我们Person("未命名")产生的实例)的属性,找到sayHello执行即可。
特别需要注意的是,c2.name = "jim" 并不是修改了 原型对象的name属性,而是给c增加了name属性,并赋值”jim“。因为,Coder的实例只能通过__proto__获取原型对象的属性、方法,并无权修改。原型对象的属性、方法只能通过如 Coder.prototype.name = "XXX" 这种方式去修改。我写上面代码注释,起初写的是错的,只是犹豫不觉,最后和js群里尼奥交流了下,才意识到错了。
现在你能看出点端倪来了吗?Coder原型中的方法、属性,是实例共享的,实例通过__proto__指针可以访问原型中的属性方法,但是不能修改。这是基于原型继承的基本原理。
上面不是js继承最好的实现,只是个入门的介绍。不用纠结new Coder() 构造函数不可以传姓名,以及Coder.prototype = new Person("未命名")这种蹩脚的写法。这篇文字还停留在介绍原型基本原理,并顺便说了几句面向对象的基本概念。后面的章节会介绍很多js继承的实践,会按照书中的逻辑,一本一本的介绍(其实是写读书笔记)。
本章描述的原型链的概念,几乎可以在所有介绍js的主流书中找到,很多博客中也有详细说明。最后用一幅图作为结束:
你看懂了吗?下篇解释~~晚安
相关推荐
当访问一个对象的属性或方法时,如果对象本身没有定义该属性或方法,JavaScript 就会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的末尾(null)为止。 原型链图是用于表示 JavaScript 中对象之间原型...
说好的讲解JavaScript继承,可是迟迟到现在讲解。废话不多说,直接进入正题。 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考《面向对象JS基础讲解,工厂模式、构造...
主要介绍了JavaScript使用原型和原型链实现对象继承的方法,简单讲述了javascript原型与原型链的原理,并结合实例形式详细分析了javascript中对象继承的常见实现技巧,需要的朋友可以参考下
JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型。...由于 JavaScript 是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链
这篇文章主要介绍了JavaScript原型继承和原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在讨论原型继承之前,先回顾一下关于创建自定义类型的...
在JavaScript中,用 __proto__ 属性来表示一个对象的原型链。当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止! 比如现在有如下的代码: 扩展Object类,添加Clone和Extend方法 /...
在上一篇文章中,介绍了原型的概念,了解到在javascript中构造函数、原型对象、实例三个好基友之间的关系:每一个构造函数都有一个“守护神”——原型对象,原型对象心里面也存着一个构造函数的“位置”,两情相悦,...
原型和原型链作为深入学习JavaScript最重要的概念之一,如果掌握它了后,弄清楚例如:JavaScript的继承,new关键字的原来、封装及优化等概念将变得不在话下,那么下面我们开始关于原型和原型链的介绍。 什么是原型?...
主要介绍了JavaScript原型链与继承操作,结合实例形式总结分析了javascript原形链与继承的相关概念、使用方法及操作注意事项,需要的朋友可以参考下
原型链是JavaScript中继承的主要方法。 原型链的基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。 构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数...
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
了解JavaScript的继承与原型链之前首先需要了解JavaScript中对象创建的方式。 在JavaScript中创建对象 JavaScript中对象创建的方式有两种:工厂方法(Factory Functions)、构造器方法(Constructor Functions) 。 ...
原型链是一种机制,指的是JavaScript每个对象包括原型对象都有一个内置的[[proto]]属性指向创建它的函数对象的原型对象,即prototype属性。 作用:原型链的存在,主要是为了实现对象的继承。 一、 记住以下5句话...
而Object的原型对象用Object.__proto__ = null表示原型链的最顶端,如此变形成了javascript的原型链继承,同时也解释了为什么所有的javascript对象都具有Object的基本方法。原型对象的用途是为每个实例对象存储共享...
本文实例讲述了js对象继承之原型链继承的用法。分享给大家供大家参考。具体分析如下: 代码如下:[removed] //定义猫的对象 var kitty = {color:’yellow’,bark:function(){alert(‘喵喵’);},climb:...
面向对象概念(对象封装,各种继承,闭包原理,this作用域等)介绍清晰易懂
使用js实现继承的七种方式,详细讲解了js中的原型链继承,构造函数继承,组合继承(经典继承),原型式继承,寄生式继承,寄生组合式继承,以及ES6中的继承,描述原理以及实现和要点概述等。