论原型与原型链

文章目录


前言

原型是JavaScript中难以理解的一个知识点,为了更好的理解它,我就想到写一些东西来理解一下。


一、原型是什么?

1.在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含一个‘[[Prototype]]’内部属性,这个属性所对应的就是该对象的原型。

2.利用原型特点和概念,可以提取共有属性

3.对象如何查看对象的构造函数-->constructor

4.对象如何查看原型-->隐式属性__proto__

5.函数的原型对象

function Person () {

}

let person1 = new Person()

声明一个函数,则这个函数默认会有一个属性叫 prototype 。而且浏览器会自动按照一定的规则创建一个对象,这个对象就是这个函数的原型对象,prototype属性指向这个原型对象。这个原型对象有一个属性叫constructor 执行了这个函数

6.使用构造函数创建对象

function Person(){
}
//利用构造函数创建一个对象,则这个对象会自动添加一个不可见的属性 __proto__而且这个属性指向了构造函数的原型对象。
let person1 = new Person();

  • 从上面的图示中可以看到,创建p1对象虽然使用的是Person构造函数,但是对象创建出来之后,这个p1对象其实已经与Person构造函数没有任何关系了,p1对象的[[ prototype ]]属性指向的是Person构造函数的原型对象。
  • 如果使用new Person()创建多个对象,则多个对象都会同时指向Person构造函数的原型对象。
  • 我们可以手动给这个原型对象添加属性和方法,那么p1,p2,p3…这些对象就会共享这些在原型中添加的属性和方法。
  • 如果我们访问p1中的一个属性name,如果在p1对象中找到,则直接返回。如果p1对象中没有找到,则直接去p1对象的[[prototype]]属性指向的原型对象中查找,如果查找到则返回。如果原型中也没有找到,则继续向上找原型的原型—原型链。 
  • 如果通过p1对象添加了一个属性name,则p1对象来说就屏蔽了原型中的属性name。 换句话说:在p1中就没有办法访问到原型的属性name了。
  • 通过p1对象只能读取原型中的属性name的值,而不能修改原型中的属性name的值。 p1.name = “李四”; 并不是修改了原型中的值,而是在p1对象中给添加了一个属性name。
<script>
    function Person () {        
    }
    // 可以使用Person.prototype 直接访问到原型对象
    //给Person函数的原型对象中添加一个属性 name并且值是 "张三"
    Person.prototype.name = "张三";
    Person.prototype.age = 20;

    var p1 = new Person();
    /*
        访问p1对象的属性name,虽然在p1对象中我们并没有明确的添加属性name,但是
        p1的 [[prototype]] 属性指向的原型中有name属性,所以这个地方可以访问到属性name就值。
        注意:这个时候不能通过p1对象删除name属性,因为只能删除在p1中删除的对象。
    */
    alert(p1.name);  

    var p2 = new Person();
    alert(p2.name);  

    alert(p1.name === p2.name);  

    // 由于不能修改原型中的值,则这种方法就直接在p1中添加了一个新的属性name,然后在p1中无法再访问到原型中的属性。
    p1.name = "李四";
    alert("p1:" + p1.name);
    // 由于p2中没有name属性,则对p2来说仍然是访问的原型中的属性。    
    alert("p2:" + p2.name);   
</script>

二、原型链

1.每一个对象都从原型继承属性,知道null结束

2.所有的内置构造函数都有一个继承自Object.prototype的原型,我们可以看下原型链:

var arr1 = new Array(1,2,3);
//arr1.__proto__-->Array.prototype的原型__proto__-->Object.prototype的原型__proto__
//-->null; 形成链,到null结束,完美;
var date1 = new Date();
//date1.__proto__-->Date.prototype的原型__proto__-->Object.prototype的原型__proto__
//-->null; 形成链,到null结束,完美;

3.构造函数、原型和实例的关系
    a,构造函数都有一个属性prototype,这个属性是一个对象,是Object的实例;
    b,原型对象prototype里有一个constructor属性,该属性指向原型对象所属的构造函数;
    c,实例对象都有一个__proto__属性,该属性指向构造函数的原型对象;
      obj.__proto__===Object.prototype

4.prototype与_proto_的关系
    a,prototype是构造函数的属性;
    b,__proto__是实例对象的属性;
    c,两者都指向同一个对象;

5.如果让原型对象等于另一个类型的实例,那么原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。

class Animal {
	eat() {
		console.log("eat()...")
	}
}
class Person extends Animal {
	work() {
		console.log("work()...")
	}
}
let p1 = new Person();
p1.work();
p1.eat();

console.log(p1 instanceof Person);//true
console.log(p1 instanceof Animal);//true

总结:

  1. 所有的原型对象都是由Object函数对象创建的

  2. Function函数对象由自己Function,Function.proto == Function.prototype

  3. 所有的函数都是由Function函数对象创建

  4. 构造函数创建的对象,对象的proto指向构造函数的prototype

  5. 不是构造函数创建的对象,对象的proto指向Object函数对象的prototype

  6. 对象访问某个属性,如果自己身上有这个属性 优先访问自己的 如果没有再访问原型链上的 沿着原型链依次往上层链找

function Person() {
        this.name = "qwer";
      }
      //Person是一个函数 Person是一个对象


//1.所有函数都是Function函数对象构造的
      console.log(Person.__proto__ === Function.prototype);
      console.log(Function.prototype.__proto__ === Object.prototype);
      console.log(Object.prototype.__proto__ === null);

//2.Function顶层没有人构造 自己构造自己
      console.log(Function.__proto__ === Function.prototype); //true
      console.log(Function.prototype.__proto__ === Object.prototype);
      console.log(Object.prototype.__proto__ === null);

//3.Object函数
      console.log(Object.__proto__ === Function.prototype);
      console.log(Function.prototype.__proto__ === Object.prototype);
      console.log(Object.prototype.__proto__ === null);

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值