`

js原型prototype,proto与function之间的关系图

 
阅读更多

原文地址:http://peihexian.iteye.com/blog/2147079
美工人员一般是用js写个function校验表单数据的合法性,例如

function checkAndSubmit(){
   if (document.getElementById('username').value=='') {
      alert('请输入登录用户名!');
      return false;
  }
  document.form[0].submit();
} 
<input type="button" value="登录" onclick="return checkAndSubmit();"/>

 

点击登录按钮后触发function的执行,写到这对美工来讲也就够用了,但是对程序员不行,程序员得封装、继承与多态不是?

 

如何像写java或者c#那样写复杂的js代码呢?

 

Question:如何在js中定义类?

Answer:定义function就是定义类了,例如:

function Person(){
}
var p=new Person();

 

上面定义的Person就是类,下面的p就是Person类的实例了,实例化类实例的时候是通过new 加类名称Person及构造函数()完成的。

如果类有构造函数参数,则类的定义就是下面这样:

function Person(name,age){
   this.name=name;
   this.age=age;
}

var p1=new Person('tom',11); //创建Person的类实例,传递构造函数参数。

 

除了和美工写function一样的写法,能不能显得专业一点呢?可以的,像下面这样:

        var Person=function(name,age){
            this.name=name;
            this.age=age;
        }

        var p1=new Person('tom',11);

 

 

这里面有个问题,见下面的代码:

 

var p2={name:'jake',age:12};

 

上面的p2同样是类实例,同样有name和age属性,这两种定义方法一样吗?看看chrome调试里面的输出:



  

通过chrome的调试工具可以看到,p1就是Person类型的实例,p2是Object类型的实例。

p2的另外一种等价写法类似于

 

        var p3=new Object();
        p3.name='mike';
        p3.age=2;

 

在chrome里面调试的输出结果如下:

 



 看到了吧?p2和p3都是Object类的实例,不是我们自定义类的类实例!

所以,定义自定义JS类的正确方式就是function 类名称(构造函数参数)这样去定义,而不是 var o={key:value} 或者var o=new Object();o.key=value;等方式。

 

Question:如何定义类属性和类方法及静态方法? 

Answer:

           function Person(name,age){

            this.name=name;
            this.age=age;
            this.say=function(){
                console.log(this.name);
            }
        }
        var p1=new Person('tom',11);
        p1.say();

 以上就是定义类属性name和age以及方法的示例,很简单。

在java或者c#里面都可以定义静态方法,js里面可以定义静态方法吗?答案是可以!定义静态方法的语法是类名.静态方法名称=function(){}的方式,例如:

        function Person(){}//定义类
        //定义Person类的静态方法test
        Person.test=function(){
            console.log("static method");
        }
        //调用静态方法
        Person.test();

 

除了在定义function的时候定义属性和方法,还可以在类定义以后追加属性和方法,例如:

 

        function Person(name,age){
            this.name=name;
            this.age=age;
            this.say=function(){
                console.log(this.name);
            }
        }

        var p1=new Person('tom',11);
        //利用prototype追加非静态方法,要是直接直接写Person.hello=function就是定义静态方法了
        Person.prototype.hello=function(){
            console.log(this.age);
        }

        p1.hello();

 这里面出现了一个prototype,这个玩意是个什么东西呢?是用来追加非静态属性或者方法的吗?千万不要这么理解,这个prototype叫做原型,是独立存在的对象,每一个类都有一个对应的prototype,即每一个类都一个对应的原型,有点类似于java里面每一个类被JVM加载以后都有一个对应的Class对象一样,见下面的图:

 

 



 

 

在上面的图中,每一种类类型都有对应的prototype原型对象,是不是很像JVM里面的Class对象一样?Object、Function、Cat都是类类型,都有对应的prototype对象,cat,o都是类实例而不是类,所以没有对应的prototype。

 为了让看上面的乱麻一样的关系图简单一点,先说点简单的,每一个类都有一个prototype属性,该属性指向对应的prototype对象,如Object有一个protytpe属性,指向与object唯一对应的原型对象,Cat类也有一个prototype属性指向了与Cat类唯一对应的prototype原型对象,上面的图中没有写出来,其实就是类名称右侧向右的那根黑色箭头线(说的是类的prototype属性)。

好了,知识点一:类的prototype属性指向与该类唯一对应的prototype对象。

 接着说简单的,死记硬背型的,原型对象(就是图里面的prototype)都有一个constructor属性,该属性反过来指向该类的构造函数(其实就是那个function本身啦),例如

function Person(){
}

Person.prototype.constructor==Person //true

 

 知道了这一点,看上面图中的原型对象的constructor都指向类本身就明白了,问题是知道有这么回事可以干啥?原型对象知道构造函数在哪里以后就可以实例化类实例的时候调用该构造函数了,从这一点来讲,和JVM里面知道类的Class信息以后可以通过反射去实例化类实例是一样的道理。

 

搞清了类(function),类原型对象(prototype对象,同时也是类的prototype属性所指向的对象),原型对象的constructor这几个死记硬背型的关系以后,下面就是_proto_这东东了。

 

javascript中一切都是对象,每个对象都是基于原型对象创建的,每个对象中都有__proto__属性,这个属性指向的就是它基于的原型对象

例如上面的o={},这里面的o的类型是Object类型的,所以o的_proto_属性指向了Object.prototype也就是说o._proto_==Object.prototype,但是这种关系没办法写js去验证,因为除非FF以外其他浏览器都不让程序员访问_proto_这个属性。

继续看简单的,上面的mycat=new Cat(),即mycat是Cat类的实例,所以mycat._proto_==Cat.prototype,即mycat的_proto_属性指向它对应类型的prototype属性或者叫对应的原型对象了。

上面的Cat是个类,也是一个function,JS里面所有的function都是Function的实例,注意后面的是大写F,所以Cat类的_proto_指向了Function类对应的原型对象。

原型对象也是对象吧(都叫原型对象了当然是对象的啦)?是对象就得有类型吧?所以上面图中的Cat类对应的原型对象和Function类对应的原型对象的_proto_指向了什么?指向了Object的prototype,任何的原型对象都是Object的实例。

 

好了,再往下就应该是研究Object和Function之间的纠缠关系了,但是和我要写的类的继承关系不大,先写类的继承问题。

 

Question:如何定义继承关系?

Answer:

 

        function Base(){
            console.log("base constructor");
            this.hello1=function(){
                console.log("hello1");
            }
        }

        function Child(){
            console.log("child constructor");
            this.hello2=function(){
                console.log("hello2");
            }
        }
        Child.prototype=new Base();
        var c=new Child();

        c.hello2();
        c.hello1();

 

  代码好写,理解后面的关系头疼的我出去溜达了好几圈,大爷的。

  最关键就是红色那一行,Child.prototype=new Base();  上面分析过了,类的prototype属性指向与本类唯一对应的原型对象上面,也就是说,没有这行代码的话Child.prototype指向的是与Child唯一对应的原型对象,后面的new Base()创建出来了一个Base类的实例,该实例肯定可以调用Base类的所有方法(是Base的实例嘛),然后让Child.prototype=Base类的实例发生了什么?这里面引出了原型链这个东西。

把那一行代码先拆成两行吧,好理解一点:

//Child.prototype=new Base()拆分成以下两行
var o=new Base();
Child.prototype=o;

 

 上面的o是实例对吧?具体来说是Base类的实例对吧? 实例没有prototype属性,但是有_proto_属性是吧?忘了的话看前面加黑加粗的文字,o._proto_==Base.prototype对吧?

 Child.prototype=o以后,Child.prototype._proto_==Base.prototype对吧?好了,到这就先打住,一般来讲还没乱呢。

 

var c=new Child(); 要是没有前面的红色那行Child.prototype=new Base();的话,c就是Child类的实例吧?c._proto_==Child.prototype吧?很简单,但是前面加红那一行让Child.prototype._proto_=Base.prototype了是吧?

那现在c._proto_._proto_=Base.prototype了吧?

c.hello2()调用的就是Child类里面自己的,这个肯定没问题的。

c.hello1()调用的时候Child类里面没有这个方法吧?没有为啥还能调用Base类的呢?JS调用方法或者读取类属性的时候从_proto_链中去找,一直找到Object.prototype为止!

c._proto_找不到hello1()方法,那就到c._proto_._proto_里面去找,上面已经推导出了,c._proto_._proto_是Base.prototype,所以就找到了hello1()方法,也就可以调用成功了。

 

但是按照正常人类的理解,Child.protoype=new Base();以后不是Child类原来指向的Child.prototype就没了吗?为啥尼玛的new Child()还是能有Child类里面的方法呢?这是个问题

 

这里面有一篇特别好的文章,看这里吧:http://weizhifeng.net/javascript-the-core.html

 

 

 

  • 大小: 60 KB
  • 大小: 18.9 KB
  • 大小: 13.1 KB
分享到:
评论
1 楼 hoofoo 2016-08-30  
关于博主最后一句疑问:“但是按照正常人类的理解,Child.protoype=new Base();以后不是Child类原来指向的Child.prototype就没了吗?为啥尼玛的new Child()还是能有Child类里面的方法呢?”那是因为hello2是在函数Child体内通过this.hello2的方式定义的,这使得hello2成为了函数Child的一个属性,而不是prototype的属性,所以当你把Child的prototype替换掉后,还是能够通过Child的实例对象c访问到hello2。除非你使用Child.prototype.函数名 = function(){}的方式定义。代码如下:
function Base(){  
    console.log("base constructor");  
    this.hello1=function(){  
        console.log("hello1");  
    }  
  }  
  
  function Child(){  
    console.log("child constructor");  
    this.hello2=function(){  
        console.log("hello2");  
    }  
   }  
  Child.prototype.test3 = function(){console.log('test');}
  Child.prototype=new Base();
  var c=new Child();  
  
  c.hello2();//base constructor
  c.hello1();//child constructor
  c.test3();//这句报错,提示信息:Uncaught TypeError: c.test3 is not a function(…)

 

相关推荐

    深入浅析JavaScript中prototype和proto的关系

    prototype,每一个函数对象都有一个显示的prototype属性,它代表了对象的原型(Function.prototype函数对象是个例外,没有prototype属性)。 __proto__:每个对象都有一个名为__proto__的内部隐藏属性,指向于它所对应的...

    JS原型prototype和__proto__用法实例分析

    JavaScript中的原型(Prototype)机制是实现继承的一种方式,它涉及到两个关键的概念:`prototype`和`__proto__`。这两个属性在JavaScript的对象和函数中扮演着不同的角色。 首先,`prototype`属性主要用于函数对象...

    js原型链详解

    如果在Person的实例上找不到某个属性或方法,JavaScript会查找该实例的__proto__,也就是其构造函数的prototype所指向的原型对象,若仍未找到,则会继续往上查找,直到到达原型链的末端(通常是指向Object.prototype...

    JavaScript中的原型prototype完全解析

    接下来,我们将详细解析JavaScript中的原型和prototype,以及与之密切相关的__proto__属性和原型链。 首先,要理解prototype,需要明白以下几个关键概念: 1. JavaScript中所有东西都是对象:在JavaScript中,数字...

    详解帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    例如,`Foo.prototype`也有自己的`__proto__`,它可能指向`Function.prototype`,而`Function.prototype`的`__proto__`则指向`Object.prototype`,最后达到`null`。 通过`new`操作符实例化函数时,会创建一个新的...

    js prototype和__proto__的关系是什么

    在JavaScript中,prototype和__proto__是理解对象原型继承机制的关键知识点。下面将详细介绍这两者之间的关系以及它们在JavaScript对象继承中所扮演的角色。 首先,prototype属性是函数所独有的。在JavaScript中,...

    JavaScript原型链

    JavaScript原型链是JavaScript语言中的一个核心特性,它关乎对象之间的继承关系。在JavaScript中,一切皆为对象,而原型链则是实现对象间属性和方法共享的一种机制。理解原型链对于深入学习JavaScript至关重要。 ...

    JavaScript的prototype

    JavaScript中的`prototype`是一个核心概念,它涉及到对象继承和函数原型。在JavaScript中,每创建一个函数,该函数就会自动获得一个名为`prototype`的属性,这个属性是一个对象,用于实现对象间的继承。同时,每个...

    JS原型和原型链原理与用法实例详解

    JS原型和原型链是JavaScript语言中的核心概念,它们构成了JavaScript对象继承的基础。在JavaScript中,对象可以通过原型链实现对其他对象的属性和方法的继承。下面我们将详细讲解这两个概念以及它们的工作原理。 **...

    JS中的prototype

    通过理解`prototype`以及与之相关的概念,如原型链、方法重写和`call()`,开发者可以更有效地利用JavaScript的面向对象特性,实现复杂的继承和扩展。在实际开发中,熟练掌握这些知识对于编写可维护和高效的代码至关...

    JavaScript中的prototype(原型)属性研究

    在JavaScript中,每个函数都有一个prototype属性,这个属性指向一个对象,这个对象就是所谓的原型对象。当我们创建一个函数实例时,实例会自动获取一个内部属性[[Prototype]],这个属性通常通过`__proto__`或者`...

    JavaScript_Prototype(源代码+中文手册).rar

    2. **构造函数、原型与实例**:构造函数(如`Function`、`Object`等)用于创建新的对象,每个构造函数都有一个`prototype`属性,这个属性是一个对象,用于存储共享的方法和属性。当我们使用`new`关键字创建新对象时...

    图解prototype、proto和constructor的三角关系

    在JavaScript中,prototype、proto(或__proto__)和constructor是理解对象继承和构造函数之间关系的关键概念。首先,我们来看它们之间的三角关系。 **构造函数(Constructor)** 构造函数是一种特殊的函数,用于...

    javascript 原型模式实现OOP的再研究

    JavaScript中的原型模式是一种实现面向对象编程(OOP)的关键机制,它基于原型继承,使得对象可以从其他对象那里获得属性和方法。在这个模式下,每个函数都有一个`prototype`属性,这个属性是一个对象,用于共享属性...

    instanceof 和 prototype 关系

    `instanceof`通过查找对象的原型链来确定对象与构造函数之间的实例关系,而`prototype`则用来设置和访问对象的原型属性,从而实现对象间的共享属性和方法。了解和掌握这两个概念,对于理解和使用JavaScript的面向...

    【JavaScript源代码】五句话帮你轻松搞定js原型链.docx

    5. 根据JavaScript的规定,`Object.prototype.__proto__`等于`null`,这是原型链的终点。 理解这些基础概念后,我们可以结合实例来描绘原型链。例如,创建一个名为`Game`的构造函数,然后通过`new Game()`创建一个...

    javascript中类和继承(代码示例+prototype.js)

    `prototype.js`文件可能包含了对JavaScript原型链和继承的进一步封装和扩展。通常,这样的库可能会提供更方便的方式来创建类和实现继承,比如使用类语法糖,以及提供一些额外的功能,如方法重载、私有属性等。 例如...

    prototype.js

    Prototype.js与jQuery、Dojo等其他JavaScript库相比,虽然在某些方面功能可能稍显逊色,但它更注重于提高代码的可读性和可维护性,特别是对于熟悉JavaScript原型机制的开发者来说,Prototype.js的API设计更为直观。...

    【技术分享】从浅入深 Javascript 原型链与原型链污染 .pdf

    原型链污染(Prototype Pollution)是一种安全漏洞,它利用了JavaScript允许修改任何对象的原型这一特性。攻击者可以通过构造特定的输入,修改原型链上的属性,从而影响程序的正常行为,甚至获取敏感信息。例如,...

Global site tag (gtag.js) - Google Analytics