【转】原型链

一、函数和对象的关系是怎样的?
函数是一种对象,但是函数和数组不同,你可以说数组是对象的一个子集,但是函数与对象之间,却不仅仅是一种包含和被包含的关系,函数和对象之间的关系比较复杂,类似鸡生蛋,蛋生鸡。为何这般复杂呢?先看看JavaScript的内置对象
1、对象“生”函数,函数是对象的一种

function Func(){
    this.name = 'wzt';
  this.age = 2020;
}
var func1 = new Func();
console.log(func1 instanceof Func); //true
console.log(func1 instanceof Object); //这里为true

instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。
instanceof的判断规则是:沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点,还未重合,则返回false

//于是可以理解
console.log(Object instanceof Function); //true
console.log(Function instanceof Function); //true
console.log(Function instanceof Object); //true
console.log(Object instanceof Object); //true

2、函数“生”对象

function Func() {
  this.name = 'wzt';
  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));  //function
console.log(typeof(Array));  //function

二、原型链

对象属性和方法对象属性和方法2

function Func(){
}
var func1 = new Func();
func1.a = 10;
Func.prototype.a = 100;
Func.prototype.b = 200;
console.log(func1.a);  //10
console.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 = 'wzt';
Func.prototype.age = 20;

func1.hasOwnProperty('sex'); // true
func1.hasOwnProperty('name'); // false
'name' in func1; // true

只有属性是直接在对象上,hasOwnProperty才会返回true,因此,hasOwnProperty可以区分一个属性到底是自身的还是从原型中找到的。
而in会把对象及其原型链都查找一遍,只要其中一个有该属性,就会返回true。

五、如何获取对象的原型?
Firefox、Safari和Chrome浏览器的每个对象上都有__proto__属性,而在其他浏览器中是完全不可见的,所以为了兼容各个浏览器,这里建议不要直接使用__proto__属性,可以采用ES5写法来获取对象的原型。

Object.getPrototypeOf(childins) === Parent.prototype
posted @ 2022-03-12 10:16  威震天1  阅读(26)  评论(0编辑  收藏  举报