• 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>

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

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    从Java小白到收获BAT等offer,分享我这两年的经验和感悟
    我的Java秋招面经大合集
    从零基础到拿到网易Java实习offer,我做对了哪些事
    设计模式常见面试知识点总结(Java版)
    如何才能够系统地学习Java并发技术?
    这些喜闻乐见的Java面试知识点,你都掌握了吗?
    Java集合类常见面试知识点总结
    用大白话告诉你 :Java 后端到底是在做什么?
    16-使用Selenium模拟浏览器抓取淘宝商品美食信息
    15-分析Ajax请求并抓取今日头条街拍美图
  • 原文地址:https://www.cnblogs.com/chengzixin/p/7061682.html
Copyright © 2020-2023  润新知