在使用面对对象编程时,对象间的继承关系自然少不了!而原型正是实现javascript继承的很重要的一种方法!JS的原型链只针对 对象,仅对象才具有的!!!
function person(name, age) { this.name = name; this.age = age; } person.prototype.getInfo = function() { alert("My name is "+this.name+", and I have "+this.age+" years old"); } var zhangchen = new person("zhangchen", 23); zhangchen.getInfo(); //output My name is zhangchen, and I have 23 years old;
从运行的结果我们可以看出,通过关键字new创建的zhangchen这个对象继承了person中通过原型定义的getInfo()方法.
下面我们具体来看新建的zhangchen这个对象是如何继承person对象的属性和方法的。
原型:在使用javascript的面对对象编程中,原型对象是个核心概念。在javascript中对象是作为现有实例(即原型)对象的副本而创建的,该名称就来自于这一概念。此原型对象的任何属性和方法都将显示为 从原型的构造函数创建的 对象的 属性和方法。当创建zhangchen对象时:
var zhangchen = new company("zhangchen", 23);
可以说,这些对象从其原型继承了属性和方法。
zhangchen所引用的对象将从它的原型继承属性和方法,对象zhangchen是由new方法 通过 company("zhangchen",23)函数构建得来的
在javascript中,每个函数都有名为prototype的属性,用于引用该函数的原型对象。该函数对应的原型对象又有名为constructor的属性,它反过来引用函数本身。
这是一种循环引用,如下图
现在,通过new运算符将函数(person)构建成对象时,所获得的对象将继承person.protype的属性。在上图,可以看到person.prototype对象有一个回指person函数的构造函数属性。这样,每个person对象(从person.prototype继承而来)都有一个回指person函数的构造函数属性。
person.prototype 和 person实例中还可以调用其他方法,比如toString、toLocaleString和valueOf,但它们都不来自person.prototype。而是来自于javascript中的Object.prototype,它是所有原型的最终基础原型。( Object.prototype 的原型是 null )
原型链:每个JavaScript对象都继承一个原型链,而所有原型链都终止于Object.prototype。注意,这种继承是活动对象之间的继承。它不同于继承的常见概念,后者是指在声明类时类之间的发生的继承。因此javaScript继承动态性更强。它使用简单算法实现这一点,如下所示:当你尝试访问对象的属性、方法时,javaScript将检查该属性、方法是否是在该对象中定义的。如果不是,这检查对象的原型。如果还不是,则检查对象的原型的原型,如此直到Object.prototype。
以上看的不是很明白 讲的这个对象那个对象傻傻分不清 没关系 看看下面这篇:
一、初始原型
在javaScript中,原型也是一个对象,通过原型可以实现对象的属性继承(上一层的属性,下一层属性可以调用),javaScript的对象都包含了一个“[[Prototype]]”作为对象的内部属性,这个属性对应的就是该对象的原型。 “[[Prototype]]"作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了_proto_这个非标准属性(不是所有浏览器都支持)的访问器(ECMA引入标准对象原型访问器“Object.getPrototype(object)”)。在javaScript的原型对象中,还包含一个“constructor”属性,这个属性对应创建所有指向该原型的实例的构造函数---这句话这麽拗口,那到底是什么意思呢!!? 很简单 constructor属性① 原型② 能够通过new方法得到该原型的函数③ 这句话涉及到的三个知识点;就是指 原型② 能够通过 constructor属性① 得到 所有 能够通过new方法得到该原型的函数③ ,另外补充的一点当函数通过new方法创建原型对象时,如果出错,在“错误的”(不是我们想要的)原型中 constructor属性 会指出错误原因!
var person = function(name,age){ this.name = name; this.age = age; } var p1 = new person(); //不会报错 但所有属性都是undefined 缺少参数! function a(name,age){alert(1);} a(); //无参数 可以调用 不会报错(函数体内不涉及到参数) //constructor 当你实例化某个对象时,必须要给出指定的参数 又叫构造方法
那么有人就有问题了,new方法是什么呢?不急,向下看!
二、规则
在javaScript中,每个函数 都有一个prototype属性,当一个函数被用作构造函数来创建实例时,这个函数的prototype属性值会被作为原型赋值给所有对象实例(也就是设置 实例的‘_proto_’属性),也就是说,所有实例的原型引用的是函数的prototype属性。(‘只有函数对象才会有这个属性!’)
New方法的过程分为三步(new方法又称为实例化)
var p = new Person(‘张三‘,20);
1. var p={};初始化一个对象p。
2. p._proto_=Person.prototype;将对象p的_proto_属性设置为Person.prototype
3. Person.call(p,"张三",20);调用构造函数Person来初始化p。关于call、apply使用
三、初识object
Object对象本身是一个函数对象。(CODE TEST)既然是Object函数,就肯定会有Prototype属性,所以可以看到"Object.prototype"的值就是"Object{}"这个对象。反过来,当访问"Object.prototype"对象的"constructor"(构造器)这个属性的时候,就得到了Object函数。
另外,当通过"Object.prototype._proto_"获取Object原型的原型的时候,将会得到"null",也就是说"Object{}"原型对象就是原型链的终点了。这里会有人喜欢出面试题:原型链的根只能为Object!× 还能为null
四、初识Function
对于所有的对象,都有_proto_属性,这个属性对应该对象的原型。
对于函数对象,除了_proto_属性之外,还有Prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的_proto_属性)
原型链
因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。
一、属性查找
当查找一个对象的属性时,javaScript会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是Object.prototype),如果仍然没有找到指定的属性,就会返回undefined。
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.MaxNumber = 9999; Person.__proto__.MinNumber = -9999; var will = new Person("Will", 28); console.log(will.MaxNumber); // 9999 console.log(will.MinNumber); // undefined
在这个例子中分别给”Person.prototype “和” Person._proto_”这两个原型对象添加了”MaxNumber “和”MinNumber”属性,这里就需要弄清”prototype”和”proto”的区别了:
"Person.prototype"对应的就是Person构造出来所有实例的原型,也就是说"Person.prototype"属于这些实例化原型链的一部份,所以当这些实例进行属性查找时候,就会引用到"Person.prototype"中的属性。
对象创建方式影响原型链
var July = { name: "张三", age: 28, getInfo: function(){ console.log(this.name + " is " + this.age + " years old"); } } console.log(July.getInfo());
当使用这种方式创建一个对象的时候,原型链就变成下图了,July对象的原型是“Object.prototype”也就是说对象的构建方式会影响原型链的形式
总结:
1、在javascript中,每一个函数实际上都是一个函数对象
2、原型链的根原型为Object,即所有原型的最上层原型都为Object
3、所有的对象都有_proto_属性,该属性对应该对象的原型
4、所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的对象的_proto_属性。
5、注意:函数对象没有_proto_属性,对象没有prototype属性
6、所有的原型对象都有constructor属性,该属性对应创建所有指向该原型的实例化的构造函数
7、函数对象和原型对象通过prototype和constructor属性进行相互关联。
文章来自 “编程的人”,