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 = ‘100var 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 

 

posted @ 2019-06-10 14:00  ryelqy  阅读(3436)  评论(0编辑  收藏  举报