js原型和原型链,以及__proto__、prototype属性
__proto__和prototype属性:
1、__proto__属性:
在JS里,万物皆对象(函数是对象、原型也是对象...)。对象都具有属性__proto__,这个属性会指向该对象的原型。
2、prototype属性:
除此之外,函数(Function)也是对象,而且函数除了上面说的__proto__这个属性外,还有额外的一个prototype属性。函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是下面例子中的 person1 和 person2 的原型。
那什么是原型呢?你可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。
原型链:
1、函数和原型关系:
我们先使用构造函数创建一个对象,Person 就是一个构造函数(注:首字母大写只是约定俗成,不大写照样可以),我们使用 new 创建了两个实例对象 person1和persion2。
function Person() { } // prototype是函数才会有的属性 Person.prototype.name = 'Kevin'; var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // Kevin console.log(person2.name) // Kevin
让我们用一张图表示构造函数和实例原型之间的关系:
在这张图中我们用 Object.prototype 表示实例原型。(构造)函数有一个prototype属性,指向了实例原型。
2、实例和原型关系:
那么我们该怎么表示实例与实例原型,也就是 person 和 Person.prototype 之间的关系呢?很自然,我们知道没有对象都有__proto__属性,而且他指向的就是对象的原型。
function Person() { } var person = new Person(); console.log(person.__proto__ === Person.prototype); // true
3、构造函数:
既然实例对象和构造函数都可以指向原型,那么原型是否有属性指向构造函数或者实例呢?指向实例倒是没有,因为一个构造函数可以生成多个实例,但是原型指向构造函数倒是有的,如下代码可以验证
function Person() { } console.log(Person === Person.prototype.constructor); // true
讲到这里,我们知道了函数、对象实例和原型之间的关系了,他们是通过prototype和__proto__两个属性联系起来的。如下图
4、原型链:
原型链就是依托__proto__和prototype连接起来的一个原型链条,我们先看个例子
function Person() { } // 原型属性 Person.prototype.name = ‘Jiang’ var person1 = new Person() // 实例属性 person1.name = ‘J’ console.log(person1.name) // J
上面代码中在实例属性和原型属性都有一个名为name的属性,但是最后输出来的是实例属性上的值。
当我们读取一个属性的时候,如果在实例属性上找到了,就读取它,不会管原型属性上是否还有相同的属性,这其实就是属性屏蔽,即当实例属性和原型属性拥有相同名字的时候,实例属性会屏蔽原型属性,记住只是屏蔽,不会修改,原型属性那个值还在;但是如果在实例属性上没有找到的话,就会在实例的原型上去找,如果原型上还没有,就继续到原型的原型上去找,直到尽头。
这个尽头是啥?由于原型也是对象,所以也会有__proto__属性,也就是原型的原型;最后就可以找到Object.prototype这个大boss,所有原型对象都是Object构造函数生成的(Object.prototype值为null)。正是因为所有的原型最终都会指向Object.prototype,所以对象的很多方法其实都是继承于此,比如toString()、valueOf(),前面用到的hasOwnProperty,甚至是.constructor、proto
补充:一些常用方法:
1)检查对象是否有该属性:
function Person() { } var person1 = new Person() // 实例属性 person1.name = ‘J’ person1.hasOwnProperty(‘name’) // true
注:hasOwnProperty属性只有存在于实例中才会返回true
2)in则会遍历所有属性,不管是实例上的,还是原型上的:
function Person() { } Person.prototype.age = ‘100’ var person1 = new Person() person1.name = ‘J’ 'name' in person1 // true 'age' in person1 // true for (var prop in person1) { console.log(prop) // name age }
---------------------
作者:赶路人儿
来源:CSDN
原文:https://blog.csdn.net/liuxiao723846/article/details/81984357