zl程序教程

您现在的位置是:首页 >  前端

当前栏目

Javascript原型链您了解多少

JavaScript 了解 多少 原型
2023-06-13 09:12:14 时间

JS面向对象中的原型 每一个函数都有一个属性 即原型对象(显式原型:prototype)这个原型对象默认指向一个Object空对象,同时每一个原型对象(prototype)都有一个属性(constructor)又指向构造函数(构造函数和它的原型对象相互引用),同时每一个实例对象又有一个__proto__属性(隐式原型),这个属性指向其构造函数的原型对象 (Fn.prototype===fn.__proto__)。

需要注意的是每个函数也有一个隐式属性__proto__,因为函数是Function的实例

理解上面概念,引入“原型链” 如下新建一个构造函数

function Student(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

打印这个构造函数,发现其具有prototype属性,这个属性就是构造函数的原型对象,同时这个原型对象有具有一个属性constructor属性,这个属性指向构造函数

实例化构造函数

var stu1 = new Student('te','m',12);
 console.dir(stu1);

打印结果,印证上面所说的每一个对象又有一个__proto__属性,这个属性是指向构造函数的原型对象的所以proto ==构造函数的prototype

 console.log(stu1.__proto__ === Student.prototype)
 //返回true

综上我们可以得出 构造函数 原型对象 以及对象之间的关系 如图

方便理解为每个步骤列图 1.当创建构造函数时 此时在栈区创建了一个函数名(Student)存储的是地址值(0x123)指向堆区的Function对象,这个对象会有一个prototype属性,指向默认的空Object对象

2.当实例化构造函数时 在栈取创建了一个stu1存储的是地址值(0x345)执行堆区的Student实例对象,这个对象会生成一个隐式原型__proto__属性,这个属性也执行prototype指向的对象(__proto__=Student.prototype)

3.当为原型对象添加方法时

对象通过构造函数创建,而每一个对象有一个__proto__属性,这个属性是指向原型对象的,而每一个原型对象又有一个constructor属性,这个属性指向构造函数,上面说到每一个构造函数具有一个prototype属性,这个属性就是原型对象 由此可以得到一个简单得三角关系。 如果你仔细观察可以发现原型对象也有一个__proto__属性,这并不奇怪,因为每一个对象都有一个__proto__属性这个属性是指向他构造函数的原型对象。 查看原型对象的指向

可以看到原型对象的__proto__属性(这个属性指向Object的原型对象)里面的constructor属性指向其构造函数Object 那么原型对象也是由构造函数创建,这个构造函数就是Object。上面说到只要是对象就会有一个__proto__属性,这个属性指向构造函数的的原型对象,那么Object的原型对象的原型对象又是什么呢?

 var stu1 = new Student('te','m',12);
 var o = stu1.__proto__;
 console.log(o);//构造函数的原型对象
 console.log(o.__proto__.__proto__);//Object的原型对象的原型对象

可以看到Object的原型对象的原型对象为空null那么null有原型对象吗,会不会一直循环下去?

   console.log(o.__proto__.__proto__.__proto__);//null的原型对象

抛出异常,说明最顶层的原型对象就是null,因此我们可以得出一个简单的原型链图

我们通过构造函数创建一个对象,因为每一个对象有一个__proto__属性,这个属性就指向该对象构造函数的原型对象,由于原型对象也有一个__proto__属性,这个属性指向原型对象的原型对象,我们可以看到原型对象的原型对象的构造函数为Object而原型对象是具有__proto__属性的,而Object的原型对象的原型对象指向null所以我们说最顶层的原型对象为null

说了那么多根据原型链我们可以得出对象查找/设置属性和方法的规则

结论

查找:对象在调用属性或方法时,会先在当前对象查找是否有相关属性或方法 如果没有就在当前对象的构造函数的原型对象上查找,如果还是没有则继续在原型对象的原型对象上查找直到指向null这就是我们所说的原型链。 如下

function Student(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.method = function(){
            console.log(123)
        }
    }//构造函数
    Student.prototype.method=function(){
        console.log(321)
    }

   var stu1 = new Student('te','m',12);
   stu1.method()

我们分别在原型对象和构造函数中写入了相同的方法,结果输出123 如果我们将构造函数中的method方法去掉则会调用原型对象上的方法输出321 同时我们可以原型链的查找规则使用Object中的属性或方法,以toString为例

 console.log(stu1.toString());
 //返回[object Object]字符串

设置:对象在设置属性/方法时,如果当前对象没有该属性或方法,则重新在当前对象创建一个同名属性/方法,并不会影响原型链上具有的属性或方法

function Student(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }//构造函数
    Student.prototype.method=function(){
        console.log(123);
    }

   var stu1 = new Student('te','m',12);
   stu1.method=function(){
       console.log(321)
   }
  
   var stu2 = new Student('w','w',13);
   stu1.method();
   stu2.method()
   // console.dir(

可以看到stu1并没有修改原型链上的方法

instanceof是如何判断的

表达式 A instanceof B 如果B函数的显示原型对象在A对象的原型链上,返回true,否在返回false