javascript——原型、原型链

695 阅读2分钟

原型

js的每一个函数都带有一个prototype的属性,这个属性指向一个对象,就叫做原型对象。

对于构造函数来说,可以通过new实例化一个对象,每一个实例化对象都有一个隐含的属性__proto__,这个属性也指向构造函数的原型对象。

原型对象就是一个公共区域,可以被每一个实例化的对象所共用,而不会产生全局变量的污染。

原型的作用就是给实例化的对象提供共享的方法和属性。

//构造函数
 function Person(name,age,sex){
     this.name = name;
     this.age = age;
     this.sex = sex;
 }
 //给原型增加方法
 Person.prototype.sayHi = function(){
     console.log("你好!我是" + this.name + "今年" + age + "岁了");
 }
 Person.prototype.eat = function(){
     console.log("我最喜欢吃西瓜");
 }

//实例化对象
let p1 = new Person('Tom',12,'男');
let p2 = new Person('Lili',23,'女');

console.log(Person);
/*
ƒ Person(name,age,sex){
     this.name = name;
     this.age = age;
     this.sex = sex;
 }
*/
console.log(p1);
/*
Person {name: "Tom", age: 12, sex: "男"}
    age: 12
    name: "Tom"
    sex: "男"
    __proto__:
        eat: ƒ ()
        sayHi: ƒ ()
        constructor: ƒ Person(name,age,sex)
        __proto__: Object
*/
console.log(Person.prototype);
/*
{sayHi: ƒ, eat: ƒ, constructor: ƒ}
    eat: ƒ ()
    sayHi: ƒ ()
    constructor: ƒ Person(name,age,sex)
    __proto__: Object
*/
// A instanceof B 判断A是否是B的实例
console.log(p1 instanceof Person);//true
console.log(p1 instanceof Object);//true 顺着原型链可以找到
console.log(p1 instanceof Array);//false

//A.isPrototypeof(B)  B是否是A的实例
console.log(Person.prototype.isPrototypeof(p1));//true

//A.hasOwnProperty(B) A是否有本地属性 B
console.log(p1.hasOwnProperty("name"));//true 是本地属性,通过构造函数
console.log(p1.hasOwnProperty("eat"));//false eat是原型对象上的属性(通过原型添加)

//判断属性是否属于实例  不管是本地还是非本地的属性
console.log('name' in p1);//true
console.log('eat' in p1);//true

原型链

每一个对象都有原型对象,一个原型对象也是一个对象,所以它也有原型对象

当一个对象调用某个方法或者属性的时候,先在自身查找,如果找到就调用,如果没有就顺着__proto__到原型对象中查找,如果还没有就继续取原型的原型中查找,这样形成一条链叫做原型链。

原型链的终点是Object原型,如果还没有找到就返回undefined。

综合上图可以概括出:

1.所有的实例化对象的__proto__指向 其构造函数的prototype。

2.所有普通的对象 和 构造函数的prototype 的__proto__ 都指向 object.prototype。

3.所有函数(包括构造函数)都是function的实例,所以__propo__都指向 function.prototype。

    function Fn() {
        this.x = 100;
        this.y = 200;
        this.getX = function () {
            console.log(this.x)
        }
    }
    Fn.prototype = {
        y:400,
        getX: function (){
            console.log(this.x)
        },
        getY: function (){
            console.log(this.y)
        },
        sum:function () {
            console.log(this.x + this.y)
        }
    }
    var f1 = new Fn();
    var f2 = new Fn();
    console.log(f1.getX === f2.getX) // false 先查到了本地属性
    console.log(f1.getY === f2.getY) // true 原型上的公共属性
    console.log(f1.__proto__.getY === Fn.prototype.getY)// true
    console.log(f1.__proto__.getX === f2.getX) // false
    console.log(f1.getX === Fn.prototype.getX)// false
    
    console.log(f1.constructor)//ƒ Object() { [native code] }
    console.log(Fn.prototype.__proto__.constructor)//ƒ Object() { [native code] }
    f1.getX();// 100
    f1.__proto__.getX(); // undefined
    f2.getY(); //200
    Fn.prototype.getY();// 400
    f1.sum(); // 300
    Fn.prototype.sum();// NaN