JS-原型链

定义与实例化

    function Person(){
    }
    // 定义原型链上的属性
    Person.prototype.name = "Nicholas";
    Person.prototype.age = 29;
    Person.prototype.job = "Software Engineer";
    Person.prototype.sayName = function(){
        console.log(this.name);
    };
    // 两个实例,都是调用的原型链上的函数
    var person1 = new Person();
    person1.sayName();   //"Nicholas"
    var person2 = new Person();
    person2.sayName();   //"Nicholas"

    console.log(person1.sayName == person2.sayName);  //true
    console.log(Person.prototype.isPrototypeOf(person1));  //true
    console.log(Person.prototype.isPrototypeOf(person2));  //true
    // only works if Object.getPrototypeOf() is available
    if (Object.getPrototypeOf){
        console.log(Object.getPrototypeOf(person1) == Person.prototype);  //true
        console.log(Object.getPrototypeOf(person1).name);  //"Nicholas"
    }

实例属性与原型链属性

    person1.name = "Greg"; // 实例上定义了属性
    alert(person1.name);   //"Greg"  从实例上的属性获取
    alert(person2.name);   //"Nicholas"  从实例的原型链上获取

delete 操作

    // 两个实例-测试 delete 操作
    var person1 = new Person();
    var person2 = new Person();
    person1.name = "Greg";
    console.log(person1.name);   //"Greg" – from instance
    console.log(person2.name);   //"Nicholas" – from prototype
    delete person1.name; // 删除的是实例上的,但还有 prototype 上的
    delete person1.name; // delete 只会删除实例上的属性,不会删除原型链上的
    console.log(person1.name);   //"Nicholas" - from the prototype

判断属性是实例上的还是原型链上的

    var person1 = new Person();
    var person2 = new Person();
    console.log(person1.hasOwnProperty("name"));  //false
    // in 方法会同时判断 实例 和 原型链 上
    console.log("name" in person1);  //true
    //
    person1.name = "Greg";
    console.log(person1.name);   //"Greg" – from instance
    // hasOwnProperty 判断实例上是否有指定的属性
    console.log(person1.hasOwnProperty("name"));  //true
    console.log("name" in person1);  //true
    //
    console.log(person2.name);   //"Nicholas" – from prototype
    console.log(person2.hasOwnProperty("name"));  //false
    console.log("name" in person2);  //true
    // delete 会删除实例上的属性,不会删除原型链上的
    delete person1.name;
    console.log(person1.name);   //"Nicholas" - from the prototype
    console.log(person1.hasOwnProperty("name"));  //false
    console.log("name" in person1);  //true
    // 定义函数实现
    // 判断 实例的原型链上是否存在指定的属性
    function hasPrototypeProperty(object, name){
       return !object.hasOwnProperty(name) && (name in object);
    }

实例类型判断

    var friend = new Person();
    // 判断实例的类型
    console.log(friend instanceof Object);  //true
    console.log(friend instanceof Person);  //true
    // 构造函数默认的定义为 objects
    console.log(friend.constructor == Person);  //false
    console.log(friend.constructor == Object);  //true

指定构造函数,导致上面类型判断不一样

    Person.prototype = {
        // 构造原型定义 - 如果不指定,则默认是 object
        constructor : Person,
        name : "Nicholas",
        age : 29,
        job: "Software Engineer",
        sayName : function () {
            alert(this.name);
        }
    };
    alert(friend.constructor == Person);  //true
    alert(friend.constructor == Object);  //false

实例化之后添加原型链函数

    function Person(){}
    Person.prototype = {
        constructor: Person,
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        sayName : function () {
            console.log(this.name);
        }
    };
    var friend = new Person();
    // 在实例化之后,原型链上添加新的函数,实例上可直接调用
    Person.prototype.sayHi = function(){
        console.log("hi");
    };
    friend.sayHi();   //"hi" – works!

实例化之后,再定义 原型链属性

    function Person(){}
    var friend = new Person();
    // 在实例化之后,重新定义 原型链属性、构造、函数,则实例无法调用相关函数
    Person.prototype = {
        constructor: Person,
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        sayName : function () {
            alert(this.name);
        }
    };
    console.log(friend.name); //undefined
    friend.sayName();   //error

无法理解的原型链

    function Person(){}
    Person.prototype = {
        constructor: Person,
        name : "Nicholas",
        age : 29,
        job : "Software Engineer",
        friends : ["Shelby", "Court"],
        sayName : function () {
            console.log(this.name);
        }
    };
    var person1 = new Person();
    var person2 = new Person();
    person1.friends.push("Van");
    // 正常的理解应该是互不相关的两个实例,但他们原型链上的数组却一样了
    // 无法理解!!!
    console.log(person1.friends);    //"Shelby,Court,Van"
    console.log(person2.friends);    //"Shelby,Court,Van"
    console.log(person1.friends === person2.friends);  //true