javascript之原型、原型链

一、原型:
1. 任何函数都有prototype属性(对象才有属性,函数也是对象);
2. 函数的prototype属性的值是个对象,这个对象就是原型(对象);
3. 作用:通过构造函数创建出来的对象可以直接去访问这个构造函数的prototype属性上的任意成员;
function Person(){}
        /*function fn(){}
        console.dir(Person); // 以对象形式打印
        console.dir(fn); */
        // 给原型对象添加color属性
        Person.prototype.color = "red";
        Person.prototype.legs = 2;
        
        // sayHi方法在内存中只有一份,在Person.prototype原型对象中
        // 内存浪费问题
        Person.prototype.sayHi = function () {
            console.log("hello is me");
        }
        console.log( Person.prototype );
        var p1 = new Person();
        console.log(p1.color); // lime
        p1.sayHi();
        var p2 = new Person();
        console.log(p2.legs); // 2
        p2.sayHi();
        // p1的sayHi和p2 的sayHi方法是同一个,地址是相同的
        //  这个sayHi方法在 原型对象中
        console.log(p1.sayHi == p2.sayHi); // true
小结:
原型:函数的prototype属性的值(对象)
作用:通过构造函数创建出来的实例对象可以直接去访问这个构造函数的prototype属性上的任意成员;
           可以使用原型对象来解决构造函数创建对象造成的内存浪费问题;
           把需要的方法添加到原型对象中;
           原型对象是函数自带的;
二、构造函数 原型对象 实例对象 三者关系
// 构造函数
        function Person(){}
        // Person.prototype 原型对象
        Person.prototype.color = "red";
        Person.prototype.legs = 2;
        Person.prototype.sayHi = function () {
            console.log("hello is me");
        }
 // 实例对象
        var p1 = new Person();
        console.log(p1.color); // red
        console.log(p1.legs); // 2
        p1.sayHi();
        // Person创建的实例
        var p2 = new Person();
        console.log( p2.color );
        console.log( p2.legs );
        p2.sayHi();
        console.log(p1.sayHi === p2.sayHi);
拟人化理解:
拟人化理解原型三角关系
构造函数 和 原型对象来说:配偶关系
1. 构造函数 通过 prototype属性来访问到原型对象
2. 原型对象 通过 constructor属性来访问到构造函数
构造函数 和 实例对象的关系: 母子关系
1. 构造函数通过new创建出来实例对象
2. 实例对象不能去直接访问到构造函数
原型对象 和 实例对象的关系: 父子关系
1. 实例对象通过__proto__属性访问原型对象上的任意成员
2. 实例对象通过原型对象的constructor属性可以间接的访问构造函数
三、__proto__属性
1. 任何对象都有__proto__属性;
2. 对象的__proto__属性的值是指向了当前构造函数的原型对象;
function Person(){}
        var p = new Person();
        console.log(p);
        console.log( p.__proto__ ); // 原型对象
        console.log( p.__proto__ == Person.prototype  ); // true
要想访问原型对象,有两种途径:
1. 对于构造函数来说,通过prototype属性可以来访问到原型对象
2. 对象实例对象来说,通过__proto__属性可以来访问到原型对象
该属性的注意点:
 __proto__属性 私有属性,不是个标准属性(存有兼容问题,IE678不识别该属性)
不推荐这么去操作原型对象
 // p.__proto__.color = "lime";
 // 推荐方式:
        Person.prototype.color = "red";
        console.log( Person.prototype );

四、constructor属性

1. 该属性是原型对象自带的;
2. 原型对象的constructor属性的值指向了当前的构造函数;
function Person(){}
        console.log( Person.prototype );
        console.log( Person.prototype.constructor ); // Person
练习题:
function Person(){}
        var p = new Person();
        console.log( p.constructor == Person ); // true
        // p Person的实例对象
        // p.constructor ==> p实例对象去原型对象上拿到constructor属性去用的
        //   ==> Person
        console.log( p.constructor == Person.prototype.constructor ); // true
        // Person.prototype.constructor ==> Person
        // p.constructor ==> Person

五、原型链

// 问题:
        function Person(){}
        var p = new Person();
        // 问:p实例对象去调用toString方法,这个toString方法在哪?
        console.log( p.toString() );
        // 原型链:对象有 __proto__ 属性, 指向了当前的原型对象,原型对象也是对象,原型对象有__proto__属性,指向了原型对象的原型对象,这样一环套一环形成的链式结构,叫做原型链。
        //  形象理解: 孩子有自己的爸爸,自己的爸爸也有爸爸,族谱(原型链)
        function Person(){}
        var p = new Person();
        console.log( Person.prototype.__proto__ ); // 找爸爸
        console.log( Person.prototype.__proto__.constructor );// 找妈妈


        console.log( Person.prototype.__proto__ == Object.prototype );
        console.log( Object.prototype.__proto__ ); // null
        // 实例对象p的原型链:
        //  p ==> Person.prototype ==> Object.prototype ==> null;

六、内置对象的原型链

// Array
        var arr = new Array();
        // 实例对象arr的原型链:
        //   arr ==> Array.prototype ==> Object.prototype ==> null;
        // console.log( Array.prototype.__proto__ );
        // console.log( Array.prototype.__proto__.constructor );

        // Date
        var d = new Date();
        // 实例对象d原型链:
        //  d ==> Date.prototype ==> Object.prototype ==> null;

        // Math 本身就是个对象(孩子),不是个构造函数,所以不能new
        /*var m = new Math(); // error
        m ==> */
        // Math ==> Object.prototype ==> null;
        // 规律: 任何对象的原型链上都有Object.prototype

七、属性查找原则

 // 1. 查找对象的属性的时候,首先会在对象自身上来查找是否有该属性,如果有,就返回属性的值
 // 2. 如果没有,去原型对象上去查找,如果有,就返回属性的值
 // 3. 如果没有,就会沿着对象的原型链继续在往上找,直到Object.prototype,如果有,就返回属性的值
 // 4. 如果还没有,返回undefined
 // 简单记忆:沿着对象的原型链往上查找
 // 注意点:关键看对象身上是否有该属性,而不在乎其值
        function Person(name, age){
            this.color = "red";
            this.name = name;
            this.age = age;
        }
        Person.prototype.name = "lw";
        Person.prototype.color = "lime";
        Object.prototype.gender = "male";
        var p = new Person("xm", 20);
        console.log(p);
        // p的原型链:
        //  p ==> Person.prototype ==> Object.prototype ==> null;
        console.log( p.color );
        console.log( p.name ); // xm
        console.log( p.age );  // 20
        console.log( p.gender ); // male
        console.log( p.sex ); // undefined

案例:

/*function Person(name, age){
            this.name = name;
            this.age = age;
        }
        Person.prototype.name = "lw";
        Object.prototype.gender = "male";
        var p = new Person(0, 0);
        console.log(p);
        // p的原型链:
        //  p ==> Person.prototype ==> Object.prototype ==> null;
        
        console.log( p.name ); // undefined
        console.log( p.age );  // undefined   
        console.log( p.gender ); // male
        console.log( p.sex ); // undefined*/
    // 2.
    function Person(name) {
        // 有形参,无实参,形参的值undefined
        if (name) {
            // if没有执行
            this.name = name
        }
    }
    Person.prototype.name = 'ls'
    Person.prototype.money = 100
    var p = new Person()
    console.log(p.name)
    console.log(p.money)

八、属性设置原则

//  1. 如果对象有该属性,在设置的时候,其实就是把原来的值给覆盖掉,不会影响到原型上的属性
//  2. 如果对象没有该属性。在设置的时候,其实就是在添加该属性,不会影响到原型上的属性
        // 简化理解: 有就覆盖,没有就添加。
        function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.name = "lw";
        Object.prototype.gender = "male";
        var p = new Person("xm", 20);
        // 修改name属性 ==> 因为p自身有
        // p.name = "ww";
        // 给p添加gender属性,自身本来没有
        p.gender = "不清楚";
        console.log(p.gender); // 不清楚
        console.log(Person.prototype.gender); // male
        console.log(Object.prototype.gender); // male
        /*console.log(p.name); // ww
        console.log(Person.prototype.name); // lw
        console.log(Object.prototype.name); // undefined*/

 

posted @ 2020-09-15 20:13  大熊在这里  阅读(125)  评论(0)    收藏  举报