关于原型和原型链是很多人学习或面试时遇到的问题,可能部分不懂,部分懂但不会说,下面关于原型和原型链进行简单的整理总结,希望可以帮助到大家。
一、JS中的原型和原型链
1、原型说明
所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外)。
所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。
所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。
所有引用类型,它的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性。
当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。
2、什么是构造函数
对于上面的信息,唯一有疑问的问题可能就是什么是构造函数?
构造函数:在JavaScript中,用new关键字来调用的函数,称为构造函数,构造函数一般首字母大写。
构造函数的作用:对重复代码进行处理,通过构造函数创建对象。提高代码复用率。
构造函数的执行过程:
1.当以 new 关键字调用时,会创建一个新的内存空间,标记为 Animal 的实例。
2.函数体内部的 this 指向该内存,可以通过this.xxx=函数接收的参数,进行赋值
3.执行函数体内的代码,给this添加属性等于给实例添加属性
4.默认返回this,由于函数体内部的this指向新创建的内存空间,默认返回this相当于默认返回了该内存空间
构造函数的返回值:如果返回基本类型,最终还是返回this。如果返回复杂数据类型,则最终返回该对象。
3、原型举例说明
//创建一个Blogger函数
function Blogger(name,age){
this.name=name,
this.age=age
}
//函数有一个prototype属性是一个普通对象
Blogger.prototype.speak=function(){
console.log('大家好!');
}
//通过构造函数创建一个实例对象
const xc = new Blogger('勇敢小陈','25')
console.log(xc);//{ name: '勇敢小陈', age: '25' }
console.log(xc.name);//勇敢小陈
//引用类型的__proto__属性指向他的构造函数的prototype属性
console.log(xc.__proto__===Blogger.prototype);//true
//当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去他的__proto__属性上去找也就是构造函数的prototype属性中寻找
xc.speak()//大家好!
//找不到的时候报错undefined
console.log(xc.speak1());//xc.speak1 is not a function
应该可以理解哈,如果有问题欢迎留言。
关于为什么要使用原型呢?很简单,为了提交代码的复用率,如果我们要创建多个博主的信息,不能每次都去创建一个对象,然后定义其name、age、speak,所以通过构造函数和原型可以共用构造函数的方法,通过构造函数创建多个对象。
4、原型链
原型链其实也不难理解,但首先要理解什么是原型,如果对上面还不太懂得话,可以先去看下上面。
示例代码:
//创建一个Blogger函数
function Blogger(name,age){
this.name=name,
this.age=age
}
//函数有一个prototype属性是一个普通对象
Blogger.prototype.speak=function(){
console.log('大家好!');
}
//通过构造函数创建一个实例对象
const xc = new Blogger('勇敢小陈','25')
console.log(xc);//{ name: '勇敢小陈', age: '25' }
console.log(xc.name);//勇敢小陈
//引用类型的__proto__属性指向他的构造函数的prototype属性
console.log(xc.__proto__===Blogger.prototype);//true
//当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去他的__proto__属性上去找也就是构造函数的prototype属性中寻找
xc.speak()//大家好!
//找不到的时候报错undefined
// console.log(xc.speak1());//xc.speak1 is not a function
//当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。那又因为’prototype’属性是一个对象,所以它也有一个’_ _ proto_ _'属性。
console.log(Blogger.prototype.__proto__===Object.prototype);//true
console.log(Object.prototype);//{}
console.log(Object.prototype.__proto__===null);//true
这是找的网上的图,我自己画的图太丑了,哈哈哈。然后图中的Foo就是我们代码中的Blogger。
然后一起梳理一下一个图(图好像有问题,配合下面文字进行理解,以文字为准):
首先我们通过new Blogger创建了xc,然后xc的__proto__指向Blogger.prototype,而Blogger.prototype又是一个对象,对象通过构造函数Object创建,也就是Blogger.prototype.__proto__执行Object.prototype,然后Object又是一个对象,他也有__proto__指向其构造函数的prototype,但Object是原始对象,没有构造函数,也就是null,也就是Object.__proto__===null。总而言之,当你获取对象是属性时,当他找不到时,会通过他的__proto__找他的构造函数有没有,他的构造函数也是对象,如果没有又会继续按照__proto__进行寻找知道找到Object,如果没有则报错XXX是undefined。
这样的链式调用成为原型链。
5、总结
有问题欢迎留言,然后我们会进行补充,或者文章改错。