zoukankan      html  css  js  c++  java
  • JavaScript的原型链继承__propt__、prototype、constructor的理解、以及他们之间相互的关系。

    回想自己已经工作了有一段时间了,但是自己对JavaScript的原型链、和继承的理解能力没有到位,最近他们彻底的整理并且复习了一遍。

    本案例中部分文案来自网络和书籍,如有侵权请联系我,我只是把我的理解和想法告诉大家。

    本着互联网分享精神、现在我就将我的学习以及理解分享给大家。如果那里又说的不对的地方请私信我,我会及时回复。

    创建一个构造函数- 案例一

    讲解:很多人见到了久违的new操作符,于是就叫Person为“类”,可是又没有关键字class的出现,觉得叫“类”有点勉强。于是退而求其次叫Person为类的构造函数。这些概念好像都没有错,之所以出现这样的情况,可能是因为大家都学习了传统的面向对象语言(c++,c#,Java等),还有一种思维定势吧。为了让javascript也面向对象,要在javascript中找到与传统面向对象语言的影子。可是按照javascript的说法,function定义的这个Person就是一个Object(对象),而且还是一个很特殊的对象,这个使用function定义的对象与使用new操作符生成的对象之间有一个重要的区别。这个区别就是function定义的对象有一个prototype属性,使用new生成的对象就没有这个prototype属性。

    function Person(name) {
        this.name = name;
        this.showMe = function () {
            console.log(this.name);
        }
    };
    
    var per= new Person('铅笔')  //实例化这个构造函数
    
    per.showMe()   //执行函数内部的方法

     prototype讲解- 案例二

    讲解:在上面的案例中已经说到了,function定义的函数是一个特殊对象,他拥有prototype属性。prototype属性可以在对象的原型中添加原型方法。

    请看代码

    function Person(name) {
        this.name = name;
        this.showMe = function () {
            console.log(this.name);
        }
    };
    Person.prototype.user = function (user) {  // 向原型中添加原型方法
        return user
    };
    Person.prototype.age = 23;    // 像原型中添加属性,并且赋值,
    var one = new Person('js');  // 实例化方法。
    
    console.log(one.user('这是原型对象'));  //调用实例化方法的方法
    console.log(one.age);  //调用实例化方法的属性

    案例二的代码中,为什么可以调用Person的pertotype方法呢。这就要讲到Peron在实例化时候发生的事情。

    第一件事情:建立了一个one对象。(可以理解为 var one={})

    第二件事情:将one对象的内置原型对象(__proto__)设置为构造函数person的prototype属性所引用的那个原型对象。(可以理解为:one.__proto__ = Person.prototype; 这个__proto__稍后再讲)

    第三件事:将one对象作为this参数调用构造函数person(可以理解为var one={ Person.call(this}; 也就相当于当前对象拥有了Person中所有的属性和方法)

    这样就可以理解为什么one可以直接调用proson的pertotype方法了。

    constructor讲解-案例三

    在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身(Person)。

    function Person(name) {
        this.name = name;
        this.showMe = function () {
            alert(this.name);
        }
    };
    
    var one = new Person('js');
    alert(one.prototype)//undefined  
    alert(typeof Person.prototype);//object  
    alert(Person.prototype.constructor);//function Person(name) {...};  

    以上三案例是不是看着有点晕了,其实没那么复杂,直接上图。

    __proto__原型链讲解-案例四

    在案列二中讲到每一个函数都有一个protytype属性,而对象却没有,但是对象有一个__propt__内置属性,并且这个属性是包含对指定对象的内部原型的引用。原型链上的对象正是依靠这个__proto__属性连结在一起的。注意函数本质也是对象而且是特殊对象,所以函数也有__propt__属性。

    function Person(name) {
        this.name = name;
        this.showMe = function () {
            console.log(this.name);
        }
    };
    
    Person.prototype.from = function () {
        console.log('I come from prototype.');
    }
    
    var per = new Person('js');
    console.log(per.__proto__)  //输出 Person { from: [Function] }

     在举一个原型链的例子

    var Person = function() {};
    Person.prototype.say = function() {
        console.log("Person say");
    };
    Person.prototype.salary = 50000;
    
    var Programmer = function() {};
    Programmer.prototype = new Person();
    Programmer.prototype.writeCode = function() {
        console.log("Programmer writes code");
    };
    
    var p = new Programmer();
    p.say(); // Person say
    p.writeCode(); // Programmer writes code
    console.log(p.salary); // 50000
    console.log(p.__proto__)  // Person { writeCode: [Function] }
    console.log(p.__proto__.__proto__)  //Person { say: [Function], salary: 50000 }   看沒看到,这里才有salary和say方法  这就是原型链,直到找到这个方法为止。
    console.log(p.__proto__.__proto__.__proto__)  // {}   __proto__会一直向上查找,直到{}才会停止,此刻就会证明没有找到方法或属性。到头了呀亲、

    原型链上图。唉图画的好累啊。

     

    在举一个修改__proto__指向的例子

    function Person(name) {
        this.name = name;
        this.showMe = function () {
            console.log(this.name);
        }
    }
    Person.prototype.from = function () {
        console.log('I come from prototype.');
    };
    function SubPer() {
        this.tests = function () {
            console.log('tst')
        }
    }
    var son = new SubPer();
    console.log(son.__proto__);  //SubPer {}
    son.tests();
    // son.from()   //此刻会报错
    son.__proto__ = new Person('name');  //修改son实例对象的prototype原型对象的引用
    console.log(son.__proto__);  // Person { name: undefined, showMe: [Function] }
    son.showMe()      //name
    son.tests();   //此方法会被调用,因为SubPer函数内自身就有 tests 函数。
    son.from();   //此刻会调用Person原型对象方法,因为更改了son实例对象的prototype原型对象的引用。

     使用hasOwnProperty判断属性是自身的还是原型链上的。

    在JavaScript的对象中有这样一个神奇的方法hasOwnProperty,他可以判断该方法或属性是对象自身的还是原型链上的,废话不多说直接上代码。

    function a(name) {
        this.name = name;
        this.showName = function () {
            console.log(this.name)
        }
    }
    function b(name) {
        this.name = name;
        this.showName = function () {
            console.log(this.name)
        }
    }
    b.prototype.say = function () {
        return 'say'
    };
    var cat = new b('123456');
    cat.user = '铅笔';
    cat.showName();
    console.log(cat.hasOwnProperty('showName'));  //true      showName方法是构造函数b内的方法,cat对象是通过实例化b得到的。在实例化b的时候会有这么一步 b.call(cat,'123456'); 所以返回true
    console.log(cat.hasOwnProperty('say'));       //false     say属于cat内置原型对象(__propo__)指向原型链的方法,不算自身的方法,
    console.log(cat.hasOwnProperty('user'));     //true   虽然属性是在new 后加的,但是也算是对象的属性呀,所以返回的ture

    那么如果对象中包含haoOwnProperty怎么办。-终极方案

    function a(name) {
        this.name = name;
        this.showName = function () {
            console.log(this.name)
        }
    }
    function b(name) {
        this.name = name;
        this.showName = function () {
            console.log(this.name)
        }
    }
    b.prototype.say = function () {
        return 'say'
    };
    var cat = new b('123456');
    cat.hasOwnProperty = function () {
        return true
    };
    cat.user = '铅笔';
    cat.showName();
    console.log(cat.hasOwnProperty('啦啦啦')) // true
    console.log(({}).hasOwnProperty.call(cat, ('啦啦啦')));  // false   此刻只能采用终极方案,
  • 相关阅读:
    当我说要做大数据工程师时他们都笑我,直到三个月后……转
    体系化认识RPC--转
    jsoup HTML parser hello world examples--转
    数组指针和指针数组的区别
    什么是计算机科学
    HTML图片热区map area的用法
    九宫八卦--易学基础
    初探Net框架下的XML编程技术
    百度网盘学习资料
    遍历json 对象的属性并且动态添加属性
  • 原文地址:https://www.cnblogs.com/waitforyou/p/6882663.html
Copyright © 2011-2022 走看看