深入javascript面向对象,js的原型链、继承

来源:互联网 发布:graphic软件 编辑:程序博客网 时间:2024/06/05 16:48

进阶面向对象——————————————————————–

在JS源码中,系统对象也是基于原型的程序,尽量不要去添加和修改系统对象的方法

包装对象——————————————————————–

基本类型都有自己对应的包装对象比如String Number Boolean基本类型会找到对应的包装对象类型,然后包装对象把所有的属性方法给了基本类型,然后包装对象消失例如
        var str = 'abc';        str.num = 10;        //创建一个包装对象,给包装对象加num属性,然后立刻消失。        //除非设置String.prototype.num = 10;        alert(str.num);        //这时候又创建了一个包装对象,和上面创建的那个没有关联,        //所以显示undefined

原型链————————————————————————-

实例对象与原型之间的连接,叫做原型链在ff中的DOM能查看到:__proto__( 隐式连接 )对于一个对象来说,调用其方法或使用其属性,它会先看自己有没有该方法/属性,如果没找到,再通过__proto__向上查找它的原型,直至最顶层的原型ObjectObject对象类型是原型链的最外层    Object.prototype

面向对象的一些常用属性和方法—————————————————

obj.hasOwnProperty('name') : 查看对象/属性是否是对象本身的。    该方法是 Object.prototype的方法constructor : 查看对象的构造函数    还可以用来判断对象的类型 如: 
            var str = '';            alert(str.constructor===String);//true
    另外,当声明一个构造函数时,系统会自动给xxx.prototype.constructor    赋值,如:        function Person(){        }    系统会自动加上 Person.prototype.constructor=Person;    而且这是面向对象系统自动生成的唯一一段代码    但是如果用JSON    Person.prototype = {        attr1 : 10,        fn1 : function(){}    }    来给Person加对象加属性/方法的话,会覆盖系统自动生成的代码。    导致对象实例化以后,实例化对象.constructor 会通过原型链    (因为本构造函数没有这个属性)找到Object.constructor,从而    得到的值是Object    因此用JSON给对象写原型属性/方法时,要先给对象写construct    属性,并指向本身    For in 的时候有些系统自带属性prototype属性是找不到的    (自己添加的找得到)    避免修改construtor属性instanceof : 对象与构造函数在原型链上是否有关系    用法:    person1 instanceof Person 在原型链上有关系就返回true    也可以用来判断对象是否是指定的属性    var arr = [];    arr instanceof Array //truetoString() :     把对象转为字符串    是Object上的方法    系统对象下面的这个方法都是自带的,而自己写的对象都是通过    原型链找到Object下面的方法    Array对象的toString:返回数组的字符串形式    Number对象的toString(n):返回数字n进制的字符串形式    利用toString做类型的判断(最好)    var arr=[];    alert( Object.prototype.toString.call(arr) );//[Object Array];    Object.prototype.toString.call(arr)==='[Object Array]';    为真则是数组总结判断对象类型的三种方法:
        obj.constructor === Array;        obj instanceof Array;        //以上两个在跨iframe,判断window.frames[i].Array;时不行        Object.prototype.toString.call(obj) === '[object Array]'; 

继承—————————————————————————

概念 : 在原有对象的基础上,略作修改,得到一个新的对象        不影响对象原有功能。好处 : 子类不影响父类,子类可以继承父类的一些功能 (代码复用)写法 :     属性继承:调用父类的的构造函数.call():
        function Person(name,sex){            this.name = name;            this.sex = sex;        }        function Star(name,sex,job){            Person.call(this,name,sex);            //如果不改变this指向,function下的Person中的this指向window            this.job = job;        }
    原型方法/属性的继承:    【拷贝继承】    父类的原型拷贝一份赋给子类,    这样就不会因为JS的引用机制,子类修改的原型属性方法影响父类    Star.prototype = deepCopy(Person.prototype);    【类式继承】      JS中没有类的概念,可以把构造函数等价于java中的类    类式继承写法:
        function Father(){            this.name = '大明';        };        Father.prototype.callname = function(){            alert(this.name);         };        function Child(){};        Child.prototype = new Father();//核心        var c1 = new Child();        c1.callname();//大明
    原理:c1本身没有callname方法,于是找Child上的callname方法    Child.prototype上面也没有callname方法,于是找到new Father()    这个匿名对象上,这个实例对象本身也没有该方法,要通过原型链找到    Father.prototype上的callname方法,然后再调用    问题:    Child.prototype = new Father();一句话覆盖了Child所有的prototype    ,就连Child.prototype.constructor也被覆盖了,所以    c1.constructor也找不到了,要通过原型链找到其父级的constructor,    所以c1.constructor的值是Father。    因此为避免这个问题要手动修正Child.prtotype.constructor=Child;    此外,把this.name改为数组[1,2,3];    创建一个实例对象对其进行操作    var c1 = new Child();    c1.name.push(4);    var c2 = new Child();    alert(c2.name);//1,2,3,4    由此发现两个不同的实例对象居然会相互之间产生影响    原因是无论是c1还是c2,他们在读取name属性时都是在本身找不到,    而要通过原型链到匿名实例对象new Father()上找。所以操作的    是同一个地址。进而产生影响。    要避免这个问题,就要做到属性和方法分开继承。    function F(){};//1    F.prototype = Father.prototype;//2    Child.prototype = new F();//3    Child.prototype.constructor = Child;//4    //以上是类式继承的4句话    1句中声明的F构造函数没有属性。2句中F只继承了Father的原型方法,    自己并没有属性。3句中把一个F的实例对象赋值给Child的原型。    这样,如果实例化Child->c1调用c1.name,只能向上找F的实例对象上    有没有name这个属性,而由2句可知,F的实例对象是没有name这个属性    的,所以系统只会返回undefined    而如果c1调用方法callname,系统会通过原型链一直找到Father.prototype    从而调用Father.prototype上的callname方法。所以属性和方法继承    被分开了。    而继承属性的方法还是在Child构造函数中调用Father.call(this);    【原型继承】
        function Father(){            this.name = '父亲';         }        var f1 = new Father();        var c1 = cloneObj(f1);        c1.name = '小米'        //alert(c1.name)//小米        //alert(f1.name)//父亲        var a = {            name : 'a'        };        var b = cloneObj(a);        b.name = 'b';        alert(b.name);        alert(a.name);        function cloneObj(obj){            function F(){};            F.prototype = obj;            return new F();        }
    【三种继承方式总结】    拷贝继承:通用型的 有new或无new的时候都可以使用    类式继承:适合new 构造函数    原型继承:适合无new的形式
0 0
原创粉丝点击