javascript原型Prototype

javaScript创建对象一文中提到过:用构造函数创建对象存在一个问题即同一构造函数的不同实例的相同方法是不一样的,所以我们用原型把构造函数中公共的属性和方法提取出来进行封装,达到让所有实例共享的目的。

接下来进一步介绍javaScript原型。

一、javaScript原型机制

1、函数与原型的关系

js中创建一个函数,就会自动创建一个prototype属性,这个属性指向函数的原型对象,并且原型对象会自动获得一个constructor(构造函数)属性,指向该函数。

举例:以前面的原型模式创建对象为例说明

 

Person对象和Person对象的原型之间的关系如下图1。

图1函数、实例与原型的关系(图来着JS高程)

简单一句话就是:Person.prototype.constructor指向Person,可以在浏览器中测试一下。

2、实例与原型的关系

通过构造函数创建一个实例,该实例内部将包含一个属性(指针),指向构造函数的原型对象。

举例:Person构造函数的实例Person1和Person2的[[Prototype]]属性都指向Person的原型。如图1所示。

Note:[[Prototype]]连接是存在于实例和构造函数的原型之间,而不是存在实例与构造函数之间。

关于这个指针,ECMA-262中叫[[Prototype]],没有标准的方式访问[[Prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性__protp__,而在其他实现中,这个属性对脚本不可见。

3、原型链

实例有自己的属性和方法,而原型封装了所有实例共享的属性和方法,那这种共享是通过什么方式实现的呢?答案是原型链。

当要访问实例的属性时,解析器会执行一次搜索。首先从实例对象开始,如果在实例中找到了这个属性,则返回该属性的值;重点是如果没有找到的话,则继续搜索[[Prototype]]指针指向的原型对象,在原型对象中查找该属性,如果找到,则返回该属性的值。所以通过这种方式多个实例就能共享保存在原型中的属性和方法。这也是js的原型链。

Note:理解了原型链,很自然就能明白几个问题。

a、给实例添加一个与原型中同名的属性,就会将其屏蔽。因为搜索原型链时在实例中就能找到然后就返回了,根本到不了原型。

b、可以通过实例爬原型链访问原型中的值,但却不能通过实例重写原型中的值。同理。

c、原型的动态性,在原型上新增属性或方法能立即从实例反应出来。

二、原型相关的方法介绍

1、isPrototypeOf()方法

虽然实例的[[Prototype]]属性无法访问的,我们可以通过isPrototypeOf()方法来确认原型和实例之间的关系。这个方法呢是站在原型的角度来检测原型是不是某个实例的原型。A.isPrototypeOf(B),如果A的B的原型返回true,否则返回false。

举例:因为Person的两个实例lxy和personA内部都有一个[[Prototype]]属性指向Person.prototype。所以isPrototypeOf方法会返回true。

<script type="text/javascript">
    function Person(){

    }
    Person.prototype.name="lxy";
    Person.prototype.age=22;
    Person.prototype.job="Software Engineer";
    Person.prototype.sayName=function(){
        alert(this.name);
    }

    var lxy=new Person();
    var personA=new Person();
    console.log(Person.prototype.isPrototypeOf(lxy)); //true
    console.log(Person.prototype.isPrototypeOf(personA)); //true
</script>

2、Object.getPrototypeOf()方法

这个方法是ECMAScript 5中新增的,返回实例的[[Prototype]]值。

这个方法是非常有用的,因为它是在Object上实现的。所以把任何实例扔给Object,它都能获得实例的原型。

举例

<script type="text/javascript">
    function Person(){

    }
    Person.prototype.name="lxy";
    Person.prototype.age=22;
    Person.prototype.job="Software Engineer";
    Person.prototype.sayName=function(){
        alert(this.name);
    }

    var lxy=new Person();
    console.log(Object.getPrototypeOf(lxy));
    console.log(Object.getPrototypeOf(lxy)==Person.prototype); //true
    console.log(Object.getPrototypeOf(lxy).age);//22
</script>

结果:

3、hasOwnPrototype()方法

这个方法用于检测某个属性是否真正存在于实例中。是返回ture,否则返回false。

就像我们自己有一些资源和技能,但是也可以从爹妈那里得到一些资源和技能,比如看起来你有套别墅,但是你要知道哪些是你真正属于你自己的,哪些是爹妈给你的。

举例:比如我一出生父母就给我个名字lxy,这时候我用hasOwnPrototype()方法检测这个"name"属性是不真是我的,就会返回false。

后来我自己改了个名字starof,再用hasOwnPrototype()方法检测,这时就会返回true。

再后来我不想用这个名字了,我就把它delete掉了,用回了我父母给的名字。这时候再用hasOwnPrototype()方法检测这个"name"属性是不是我自己的,就会返回false。

这个一波三折的故事代码如下:

<script type="text/javascript">
    function Person(){

    }
    Person.prototype.name="lxy";

    var lxy=new Person();
    console.log(lxy.name);
    console.log(lxy.hasOwnProperty("name"));  //false
    lxy.name="starof";//通过重写屏蔽原型属性name,所以这个name就变成了实例属性
    console.log(lxy.name);
    console.log(lxy.hasOwnProperty("name"));  //true
    delete lxy.name;
    console.log(lxy.name);
    console.log(lxy.hasOwnProperty("name"));  //false
</script>

4、in操作符,for-in循环,Object的keys()和getOwnPropertyNames()

in操作符在通过对象能够访问属性时返回true,无论该属性是实例属性还是原型属性。

for-in循环,返回所有能够通过对象访问的,可枚举的属性。即包括实例属性也包括原型属性。

屏蔽了原型中不可枚举的属性的实例属性也会在for-in循环中返回,因为根据规定,所有开发人员定义的属性都是可枚举的——只有在IE8及更早版本中例外。

Object.keys()方法,取得实例上所有可枚举的实例属性。该方法接收一个实例作为参数,返回一个包含所有可枚举属性的字符串数组。

Object.getOwnPropertyNames()方法,获得所有实例属性,无论它是否可枚举。

 

三、原型语法

第一种:每添加一个属性和方法,都直接在原型上加。

<script type="text/javascript">
    function Person(){
    }
    Person.prototype.name="lxy";
    Person.prototype.age=22;
    Person.prototype.job="Software Engineer";
    Person.prototype.sayName=function(){
        alert(this.name);
    }

    var lxy=new Person();
</script>

第二种:对象字面量的方法

<script>
    function Person(){
    }
    Person.prototype={
        name:"lxy",
        age: 22,
        job:"Software Engineer",
        sayName:function(){
            alert(this.name);
        }
    };
    var lxy=new Person();
</script>

第二种语法比较简单,少写几行代码,但是有一点要注意,字面量形式,完全重写了prototype属性,所以constructor不再指向Person,而是Object了。

 

如果constructor很重要,可手动设置为Person,如下。

<script>
    function Person(){
    }
    Person.prototype={
        constructor:Person,
        name:"lxy",
        age: 22,
        job:"Software Engineer",
        sayName:function(){
            alert(this.name);
        }
    };
    var lxy=new Person();

    console.log(lxy.constructor==Person);//true
    console.log(lxy.constructor==Object);//false
</script>

但是这样写会导致constructor的[[Enumerable]]特性被置为true。因为开发人员定义的属性都是可枚举的。

如果是兼容ECMAScript5的JS引擎可使用Object.definePrototype。

 

本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:http://www.cnblogs.com/starof/p/4904929.html有问题欢迎与我讨论,共同进步。

时间: 2024-11-08 22:12:13

javascript原型Prototype的相关文章

JavaScript 原型 prototype 使用经验

function Foo(){} Foo.prototype.sayName = function(){ return '初始原型'; } var foo1 = new Foo(); foo1.sayName() //'初始原型' // new 方式重写原型:切断了新实例 与 原有原型之间的连接 function Bar(){} Foo.prototype = new Bar(); // var foo2 = new Foo(); foo2.sayName(); // error 报错:找不到这

深入理解javascript原型和闭包(3)——prototype原型

转载于http://www.cnblogs.com/wangfupeng1988/p/3978131.html 既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解javascript原型和闭包(1)——一切都是对象)中说道,函数也是一种对象.他也是属性的集合,你也可以对函数进行自定义属性. 不用等咱们去试验,javascript自己就先做了表率,人

理解javascript原型和作用域系列(3)——prototype原型

既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(理解javascript原型和作用域系列(1)——一切都是对象)中说道,函数也是一种对象.他也是属性的集合,你也可以对函数进行自定义属性. 不用等咱们去试验,javascript自己就先做了表率,人家就默认的给函数一个属性——prototype.对,每个函数都有一个属性叫做prototype. 这个prot

Javascript中的原型prototype

prototype属性可算是JavaScript与其他面向对象语言的一大不同之处. 简而言之,prototype就是“一个给类的对象添加方法的方法”,使用prototype属性,可以给类动态地添加属性和方法,以便在JavaScript中实现“继承”的效果. 通过以此函数作为构造函数构造出来的对象都自动的拥有构造函数的prototype对象的成员属性和方法. 其中的要点是: prototype是函数(function)的一个必备属性(书面一点的说法是"保留属性")(只要是function

[js高手之路]一步步图解javascript的原型(prototype)对象,原型链

我们接着上文继续,我们通过原型方式,解决了多个实例的方法共享问题,接下来,我们就来搞清楚原型(prototype),原型链的来龙去脉. function CreateObj(uName) {             this.userName = uName;         }         CreateObj.prototype.showUserName = function(){             return this.userName;         }         va

简单理解javascript的原型prototype

原型和闭包是Js语言的难点,此文主要讲原型. 每一个方法都有一个属性是 prototype 每一个对象都有一个属性是 _proto_ 一旦定义了原型属性或原型方法,则所有通过该构造函数实例化出来的所有对象,都继承了这些原型属性和原型方法,这是通过内部的_proto_链来实现的. /* Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型.这个函数包括构造函数和普通函数,我们讲的更多是构造函数的原型,但是也不能否定普通函数也有原型. 每一个方法都有一个属性叫

戏说javascript原型(prototype)实现面向对象

原型prototype JS中的方法分为三类:类方法,对象方法,原型方法 比如:一个类(Function,为对比java,以下统称为类) function Parent(name){ this.name=name; this.sayHello=function(){ alert('Hello,'+name); } } Parent类中sayHello方法就是对象方法,类比java中的实例方法 那么我这样定义一个方法呢? Parent.run=function(){ alert('run--');

秒懂javascript的原型(prototype)对象、原型链的前世今生

在上文中我们通过原型方式,解决了多个实例的方法共享问题,接下来,我们就来搞清楚原型(prototype),原型链的来龙去脉. function CreateObj(uName) { this.userName = uName; } CreateObj.prototype.showUserName = function(){ return this.userName; } var obj1 = new CreateObj('ghostwu'); var obj2 = new CreateObj('

在 JavaScript 中 prototype 和 __proto__ 有什么区别

本文主要讲三个 问题 prototype 和 proto function 和 object new 到底发生了什么 prototype 和 proto 首先我们说下在 JS 中,常常让我们感到困惑的地方,就是 prototype 和 __proto__ 到底是干嘛的 1. __proto__ 就是 Javascript中 所谓的原型 (这里,我们还是拿具体的例子来说明吧) function A (name) { // 这里是一个构造函数 thia.name = name } var Aobj