首页 > 代码库 > 原型链
原型链
一、函数和对象的关系是怎样的?
函数是一种对象,但是函数和数组不同,你可以说数组是对象的一个子集,但是函数与对象之间,却不仅仅是一种包含和被包含的关系,函数和对象之间的关系比较复杂,类似鸡生蛋,蛋生鸡。为何这般复杂呢?先看看JavaScript的内置对象。
1、对象“生”函数,函数是对象的一种
function Func(){ this.name = ‘camille‘; this.age = 2020;}var func1 = new Func();console.log(func1 instanceof Func); //trueconsole.log(func1 instanceof Object); //这里为true
instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。
instanceof的判断规则是:沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点,还未重合,则返回false。
//于是可以理解console.log(Object instanceof Function); //trueconsole.log(Function instanceof Function); //trueconsole.log(Function instanceof Object); //trueconsole.log(Object instanceof Object); //true
2、函数“生”对象
function Func() { this.name = ‘camille‘; this.age = 2020;}var func1 = new Func();
上例说明,函数可以创建对象,如果说对象都是通过函数来创建的,有没有人反对?有人会迅速搬出下列代码来反驳。
var obj = { a: 10, b: 20 };var arr = [5, ‘c‘, true];
哈哈,其实这是一种创建对象的快捷方式,编程语言里面的语法糖。它的本质是:
var obj = new Object();obj.a = 10;obj.b = 20;var arr = new Array();arr[0] = 5;arr[1] = ‘c‘;arr[2] = true;
其中的Object和Array都是函数,
console.log(typeof(Object)); //functionconsole.log(typeof(Array)); //function
二、原型链
function Func(){}var func1 = new Func();func1.a = 10;Func.prototype.a = 100;Func.prototype.b = 200;console.log(func1.a); //10console.log(func1.b); //200
1、如果要访问func1.a,它的寻找路线是怎样的呢?
Func.prototype.constructor === Func;func1.constructor === Func;func1.__proto__ === Func.prototype;Func.__proto__ === Function.prototype;Func.prototype.__proto__ === Object.prototype;Function.prototype.__proto__ === Object.prototype;Object.prototype.__proto__ === null;
一切原型链的终点都是Object.prototype,所以Func.prototype.__proto__和 Function.prototype.__proto__均指向它。Object.prototype也是对象,Object.prototype.__proto__的值为null,意味着Object.prototype没有原型。
2、总结归纳
A、所有的原型对象都有constructor属性,该属性指向关联的构造函数。
B、所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的实例的__proto__属性;
C、所有的对象都有__proto__属性,该属性指向该对象的原型。
__proto__是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持这个属性值。
D、原型链的形成真正是靠__proto__而非prototype。
E、读操作
当我们访问对象的一个属性时,会先从对象自身找,如果自身没有,就会顺着__proto__这条链一直往上找,直至Object的原型为止。如果最后没找到,就返回undefined。
F、写操作
如果一个对象没有属性a,为该对象的a属性赋值会直接写在该对象上,而不是先在原型链上找到该属性然后修改值,写操作不会影响原型值。
三、如何判断某实例和某原型是否是继承关系?
1、使用instanceof操作符
childins instanceof Parent
2、使用isPrototypeOf()方法
Parent.prototype.isPrototypeOf(childins)
四、属性是自身的吗?区别hasOwnProperty和in
function Func(){}var func1 = new Func();func1.sex = ‘male‘;Func.prototype.name = ‘camille‘;Func.prototype.age = 20;func1.hasOwnProperty(‘sex‘); // truefunc1.hasOwnProperty(‘name‘); // false‘name‘ in func1; // true
只有属性是直接在对象上,hasOwnProperty才会返回true,因此,hasOwnProperty可以区分一个属性到底是自身的还是从原型中找到的。
而in会把对象及其原型链都查找一遍,只要其中一个有该属性,就会返回true。
五、如何获取对象的原型?
Firefox、Safari和Chrome浏览器的每个对象上都有__proto__属性,而在其他浏览器中是完全不可见的,所以为了兼容各个浏览器,这里建议不要直接使用__proto__属性,可以采用ES5写法来获取对象的原型。
Object.getPrototypeOf(childins) === Parent.prototype
原型链