JavaScript原型链
什么是原型链?
是一种关系,实例对象和原型对象之间的关系,关系是通过原型来联系的
或者是原型链就是创建一个构造函数,它会默认生成一个prototype属性并指向原型对象。使用下一个构造函数的原型对象作为这个构造函数的实例。
1 //构造函数 2 function Person(name,age) { 3 //属性 4 this.name=name; 5 this.age=age; 6 //在构造函数中的方法 7 this.eat=function () { 8 console.log("吃好吃的"); 9 }; 10 } 11 //添加共享的属性 12 Person.prototype.sex="男"; 13 //添加共享的方法 14 Person.prototype.sayHi=function () { 15 console.log("您好啊,怎么这么帅,就是这么帅"); 16 }; 17 //实例化对象,并初始化 18 var per=new Person("小明",20); 19 per.sayHi(); 20 //如果想要使用一些属性和方法,并且属性的值在每个对象中都是一样的,方法在每个对象中的操作也都是一样,那么,为了共享数据,节省内存空间,是可以把属性和方法通过原型的方式进行赋值 21 22 console.dir(per);//实例对象的结构 23 console.dir(Person);//构造函数的结构 24 25 //实例对象的原型__proto__和构造函数的原型prototype指向是相同的 26 27 //实例对象中的__proto__原型指向的是构造函数中的原型prototype 28 console.log(per.__proto__==Person.prototype); 29 //实例对象中__proto__是原型,浏览器使用的 30 //构造函数中的prototype是原型,程序员使用的
原型的指向是否可以改变
1 //人的构造函数 2 function Person(age) { 3 this.age=10; 4 } 5 //人的原型对象方法 6 Person.prototype.eat=function () { 7 console.log("人的吃"); 8 }; 9 //学生的构造函数 10 function Student() { 11 12 } 13 Student.prototype.sayHi=function () { 14 console.log("嗨,小苏你好帅哦"); 15 }; 16 //学生的原型,指向了一个人的实例对象 17 Student.prototype=new Person(10); 18 var stu=new Student(); 19 stu.eat(); // 人的吃 20 stu.sayHi(); //Uncaught TypeError: stu.sayHi is not a function
从上面代码可以看得出来:
-
原型指向可以改变
实例对象的原型proto指向的是该对象所在的构造函数的原型对象
构造函数的原型对象(prototype)指向如果改变了,实例对象的原型(proto)指向也会发生改变
实例对象和原型对象之间的关系是通过proto原型来联系起来的,这个关系就是原型链
原型最终指向了哪里?
function Person() { } Person.prototype.eat=function () { console.log("吃东西"); }; var per=new Person(); console.dir(per); console.dir(Person); //实例对象中有__proto__原型 //构造函数中有prototype原型 //prototype是对象 //所以,prototype这个对象中也有__proto__,那么指向了哪里 //实例对象中的__proto__指向的是构造函数的prototype //所以,prototype这个对象中__proto__指向的应该是某个构造函数的原型prototype //Person的prototype中的__proto__的指向 //console.log(Person.prototype.__proto__); //per实例对象的__proto__------->Person.prototype的__proto__---->Object.prototype的__proto__是null console.log(per.__proto__==Person.prototype);//true console.log(per.__proto__.__proto__==Person.prototype.__proto__);//true console.log(Person.prototype.__proto__==Object.prototype);//true console.log(Object.prototype.__proto__);//null
原型指向改变如何添加方法和访问
如果原型指向改变了,那么就应该在原型改变指向之后添加原型方法
1 //人的构造函数 2 function Person(age) { 3 this.age=age; 4 } 5 //人的原型中添加方法 6 Person.prototype.eat=function () { 7 console.log("人正在吃东西"); 8 }; 9 //学生构造函数 10 function Student(sex) { 11 this.sex=sex; 12 } 13 14 //改变了原型对象的指向 15 Student.prototype=new Person(10); 16 //学生的原型中添加方法----先在原型中添加方法 17 Student.prototype.sayHi=function () { 18 console.log("您好哦"); 19 }; 20 var stu=new Student("男"); 21 stu.eat();//人正在吃东西 22 stu.sayHi();//您好哦
或者是这样
1 //指向改变了 2 Person.prototype = { 3 eat: function () { 4 console.log("吃"); 5 } 6 }; 7 //先添加原型方法 8 Person.prototype.sayHi = function () { 9 console.log("您好"); 10 }; 11 var per = new Person(10); 12 per.sayHi();//您好
实例对象的属性和原型对象那个中的属性重名
- 没有这个属相的情况下
1 function Person(age,sex) { 2 this.age=age; 3 this.sex=sex; 4 } 5 Person.prototype.sex="女"; 6 var per=new Person(10,"男"); 7 console.log(per.sex); 8 console.log(per.fdsfdsfsdfds);
因为JS是一门动态类型的语言,对象没有什么,只要点了,那么这个对象就有了这个东西,没有这个属性,只要对象.属性名字,对象就有这个属性了,但是,该属性没有赋值,所以,结果是:undefined
- 重名属性这个问题就相当于想改变原型对象中属性的值。
直接通过原型对象:属性=值,就可以改变
1 Person.prototype.sex="哦唛嘎的"; 2 per.sex="人"; 3 console.log(per.sex);//人
最后来看一个很神奇的原型链
原型链:实例对象和原型对象之间的关系,通过proto来联系
1 <div id="dv"></div> 2 <script> 3 var divObj=document.getElementById("dv"); 4 console.dir(divObj); 5 6 //divObj.__proto__---->HTMLDivElement.prototype的__proto__--->HTMLElement.prototype的__proto__---->Element.prototype的__proto__---->Node.prototype的__proto__---->EventTarget.prototype的__proto__---->Object.prototype没有__proto__,所以,Object.prototype中的__proto__是null 7 8 </script>