JavaScript-原型&原型链&原型继承&组合函数

Posted 素而安然

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript-原型&原型链&原型继承&组合函数相关的知识,希望对你有一定的参考价值。

小小的芝麻之旅:

今天学习了js的原型,要说原型,我们先简单说一下函数创建过程。

原型

每个函数在创建的时候js都自动添加了prototype属性,这就是函数的原型,原型就是函数的一个属性,类似一个指针。原型在函数的创建过程中由js编译器自动添加。

<script type="text/javascript">
        function Flower(name,area) {
            this.name=name;
            this.area=area;
            this.showName=myName;
        }
        //全局对象,浏览器 解析器 代码
        function myName() {
            alert(this.name);
        };
        //创建出一个flower对象
        var f1=new Flower("好季节","待机时间苦咖啡");
         f1.showName();
        var f2=new Flower("接电话","你的那份你看到");
        f2.showName();
        if(f1.showName==f2.showName){
             alert("==");
        }else{
            alert("!=");
        }
    <
/script>

 

原型链

在JavaScript中,每个对象都有一个[[Prototype]]属性,其保存着的地址就构成了对象的原型链
[[Prototype]]属性是js编译器在对象被创建时自动添加的,其取值由new运算符的右侧参数决定。字面量的方式可转化为new Obejct();

var x =new Flower();
vae o = {};  //var o = new Obejct();

通过对象的[[Prototype]]保存对另一个对象的引用,通过这个引用往上进行属性的查找,这就是原型链查找机制

对象在查找某个属性的时候,会首先遍历自身的属性,如果没有则会继续查找[[Prototype]]引用的对象,如果再没有则继续查找[[Prototype]].[[Prototype]]引用的对象,依次类推,直到[[Prototype]].….[[Prototype]]undefined

 

prototype本身是一个Object对象的实例,所以其原型链指向的是Object的原型。

 

<script type="text/javascript">

        function HUmens(){
            this.foot=2;
        }
//写一个关于Humens的一个原型上的方法,获取到foot
        HUmens.prototype.getFoot=function () {
            return this.foot;
        };
        //写一个子类Man
        function Man() {
            this.head=1;
        }
         Man.prototype=new HUmens();
        Man.prototype,getHead=function () {
            return this.head;
        };
        var man1=new Man();
        alert(man1.foot);

    </script>

 

基于原型链的继承

继承属性

JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

prototype 和 Object.getPrototypeOf

对于从 Java 或 C++ 转过来的开发人员来说 JavaScript 会有点让人困惑,因为它全部都是动态的,都是运行时,而且不存在类(classes)。所有的都是实例(对象)。即使我们模拟出的 “类(classes)”,也只是一个函数对象。

你可能已经注意到,我们的函数 A 有一个特殊的属性叫做原型。这个特殊的属性与 JavaScript 的 new 运算符一起工作。对原型对象的引用会复制到新实例内部的 __proto__ 属性。例如,当你这样: var a1 = new A(), JavaScript 就会设置:a1.__proto__ = A.prototype(在内存中创建对象后,并在运行 this 绑定的函数 A()之前)。然后在你访问实例的属性时,JavaScript 首先检查它们是否直接存在于该对象中(即是否是该对象的自身属性),如果不是,它会在 __proto__ 中查找。也就是说,你在原型中定义的元素将被所有实例共享,甚至可以在稍后对原型进行修改,这种变更将影响到所有现存实例。

像上面的例子中,如果你执行 var a1 = new A(); var a2 = new A(); 那么 a1.doSomething 事实上会指向Object.getPrototypeOf(a1).doSomething,它就是你在 A.prototype.doSomething 中定义的内容。比如:Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething。

简而言之, prototype 是用于类型的,而 Object.getPrototypeOf() 是用于实例的(instances),两者功能一致。

__proto__ 看起来就像递归引用, 如a1.doSomethingObject.getPrototypeOf(a1).doSomethingObject.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething 等等等, 直到它找到 doSomething 这个属性或者 Object.getPrototypeOf 返回 null。

关于javascript中apply()和call()方法的区别

如果没接触过动态语言,以编译型语言的思维方式去理解javaScript将会有种神奇而怪异的感觉,因为意识上往往不可能的事偏偏就发生了,甚至觉得不可理喻.如果在学JavaScript,先理解JavaScrtipt动态变换运行时上下文特性,这种特性主要就体现在applycall两个方法的运用上.

区分apply,call就一句话,

foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

 call, apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例,也就是每个方法都有call, apply属性.既然作为方法的属性,那它们的使用就当然是针对方法的了.这两个方法是容易混淆的,因为它们的作用一样,只是使用方式不同.

相同点:两个方法产生的作用是完全一样的

不同点:方法传递的参数不同

 javascript继承有几种继承方式,现在来说说其中的组合继承。

    组合继承是结合了原型借用构造函数这两种技术的继承方式,分别利用它们的长处,避免了短处。

原型链 

        原型链就是实例与原型之间的链条。

         子类型构造函数     超类型构造函数  之间没有关联,只需将   子类型构造函数的原型  作为  超类型构造函数的实例。这样,子类型构造函数的实例   就可以共享    超类型构造函数原型的方法  以及  超类型构造函数的属性。              

  如:

var subType.prototype = new superType();

原型链的短处在于:当subType.prototype作为实例时拥有的superType构造函数里的属性,在它作为subType的原型时,这些属性就作为原型的属性被subType的实例共享;还有,因为两个类型的构造函数之间没有关联,在创建subType的实例时,不能向superType构造函数传递参数。

借用构造函数

             在  子类型构造函数里  调用  超类型构造函数,使用   call()      或   apply()  方法。

如:

superType.call(this);   或   superType.call(this,参数);

 通过这样可以将superType构造函数里的属性作为特定的,即subType的实例调用时,这些属性也是特属于每一个实例,而不是共享的。同时,还可以向superType构造函数传递参数。

         然而,定义在superType.prototype里的方法,对subType是不可见的。

         这两个方法都有其所长,也有其所短。所以将它们组合起来,这就有了组合继承。了解了原型链与借用构造函数就不难理解组合继承了。

 组合继承

         组合继承是通过原型链继承原型的方法,通过借用构造函数继承属性。这样就可以将属性与方法分开继承,方法被所有实例共享,而属性则是特属于每一个实例。

当然,组合继承也有其缺点,那就是超类型的属性被继承了两次,一次是子类型原型继承,另一次是子类型实例继承,只是实例继承的属性屏蔽了原型继承的属性。

加例子:

    <script type="text/javascript">
        function  Flower() {
            //空模板
        }
        Flower.prototype.name="大开杀戒";
        Flower.prototype.area="服抗生素世界世界";
        Flower.prototype.showName=function () {
            alert(this.name);
        };
        var flag=Flower.prototype.constructor==Flower;
        alert(flag);
        var flower1=new Flower();
        if(flower1.__proto__==flower1.prototype) {
            alert("---===---");
        }
    </script>

 

 

                                                                                                                                                                             地狱里的镰刀====欣欣

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于JavaScript-原型&原型链&原型继承&组合函数的主要内容,如果未能解决你的问题,请参考以下文章

_proto_ && prototype (原型 && 原型链)

深入浅出JavaScript之原型链&继承

JavaScript难点系列:原型链与继承

JavaScript 原型继承原型链

# nodejs原理&源码赏析欣赏手术级的原型链加工艺术

原型&&原型链一语道破梦中人