我们创建的每个函数都有一个原型属性,它是一个指向原型对象的指针,这个原型对象中的属性和方法可以被所有实例共享。
函数Person(){ } Person . prototype . name=' Nicholas ';person . prototype . age=29;person . prototype . SayName=function(){ alert(this . name);};var Person 1=new Person();person 1 . SayName();//' Nicholas ' var Person 2=new Person();person 2 . SayName();//‘Nicholas’alert(person 1 . say name==person 2 . say name);//真一.了解原型对象
每当创建新函数时,都会根据一组特定的规则为该函数创建一个原型属性,这些规则指向该函数的原型对象。
默认情况下,所有原型对象都会自动获得一个构造函数属性,该属性包含一个指向原型属性所在函数的指针。
当调用构造函数创建新实例时,实例内部将包含指向构造函数原型对象的指针(内部属性)。ECMA-262版本5调用这个指针[[原型]]。
虽然没有在脚本中访问[[Prototype]]的标准方法,但Firefox、Safari和Chrome在每个对象上都支持一个属性_ _ proto _ _。在其他实现中,脚本完全看不到这个属性。
但是,非常重要的一点是,要清楚这种连接存在于实例和构造函数的原型对象之间,而不是实例和构造函数之间。
以使用Person构造函数和Person.prototype创建实例的代码为例,图6-1展示了各种对象之间的关系。
这里,Person.prototype指向原型对象,Person.prototype.constructor指向Person。
Person1和person2都包含一个内部属性,只指向Person。原型;换句话说,它们与构造函数没有直接关系。
您可以拨打person1.sayName()。这是通过查找对象属性的过程来实现的。(它会先在实例上搜索,如果找不到,它会继续搜索原型。)
使用isPrototypeOf()方法判断实例和原型对象alert (person)之间的关系。原型。is rototype of(person 1));//true alert(person . prototype . is rototype of(person 2));//true使用Object.getPrototypeOf()方法返回实例的原型对象alert(object . getprototypeof(person 1)=person . prototype);//true使用hasOwnProperty()方法检测属性是存在于实例中还是原型中。alert(person 1 . hasown property(' name '));//false为原型person 1 . name=' Greg ';alert(person 1 . name);//'Greg'——来自实例警报(person1。hasown property(' name ');//真二。更简单的原型语法
在前面的示例中,您必须为每个添加的属性和方法键入一次Person.prototype。为了减少不必要的输入,更好地可视化封装原型函数,更常见的是用包含所有属性和方法的对象文字重写整个原型对象。
function Person(){ } Person . prototype={ name : ' Nicholas ',年龄: 29,job: 'Software Engineer ',say name : function(){ alert(this . name);}};在上面的代码中,我们将Person.prototype设置为等于以对象的文字形式创建的新对象。最后的结果是一样的,只有一个例外:构造函数属性不再指向Person。
如前所述,每次创建函数时,都会同时创建其原型对象,并且该对象会自动获取构造函数属性。
var friend=new Person();警报(对象的朋友实例);//true alert(Person的朋友实例);//true alert(friend . constructor==Person);//false alert(friend . constructor==Object);//此处为true,使用instanceof运算符测试Object和Person仍然返回true,但是构造函数属性等于Object而不是Person。
如果构造函数的值真的很重要,可以故意将其设置回适当的值,如下所示。
函数Person(){ } Person。原型={构造函数: Person,名字: '尼古拉斯',年龄: 29,job: '软件工程师',说出名字: function(){ alert(这。姓名);}};三、原生对象的原型
所有原生引用类型(对象、数组、字符串、等等)都在其构造函数的原型上定义了方法。
例如,在数组。原型中可以找到排序()方法,而在字符串。原型中可以找到子字符串()方法。尽管可以这样做,但不推荐修改原生对象的原型。
四、原型对象的问题
原型模式的最大问题是由其共享的本性所导致的。修改其中的一个,另一个也会受影响。
函数Person(){ } Person。原型={构造函数: Person,姓名: '尼古拉斯',年龄: 29,工作: '软件工程师',朋友: ['Shelby ',' Court'],说出名字: function(){ alert(this。姓名);}};var Person 1=new Person();var Person 2=new Person();人1。朋友。push(' Van ');警惕(人1。朋友);//'谢尔比,法院,范警报(人员2。朋友);//‘舍比,法院,范’警报(第1人。朋友===人2。朋友);//真五、原型链
其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。然后层层递进,就构成了实例与原型的链条,这就是所谓原型链的基本概念。
函数SuperType(){ this。属性=true} SuperType。原型。GetSuperVaLue=function(){返回这个。财产;};function SubLe(){ this。subparty=false}//继承了超类型子类型。prototype=new SuperType();亚型。原型。getsubvalue=function(){返回这个。子属性;};定义变量实例=new SubLe();警报(实例。GetSuperVaLue());//真一张图说明:
财产则位于子类型。原型中。这是因为财产是一个实例属性,而getSuperValue()则是一个原型方法。既然子类型。原型现在是超类型的实例,那么财产当然就位于该实例中了。