JS原型链
注:理解原型链对于小白属实有点绕,这里分几个章节来讲解
一.对象
众所周知,JS是面向对象编程的弱类型语言,对象几乎涵盖了JS的所有----------万物皆对象。
那么创建对象的方式有哪些呢?
1.方法一
通常object的代码表现形式是{},所以我们可以直接如下,定义一个对象
var obj={
name:'龙儿哥哥',
age:26,
SayHi:function(){
console.log('龙儿哥哥向你打了一个招呼!');
}
}
obj.age;//26
obj.Say();//龙儿哥哥向你打了一个招呼
2.方法二
我们知道,创建一个日期对象,数组等使用的是new关键字进行创建,同样,普通对象也能使用new关键字创建。
var obj=new Object();
obj.name="龙儿哥哥";
obj.age=26;
obj.SayHi=function(){
console.log('龙儿哥哥向你打了一个招呼!');
}
3.方法三
区别于传统意义上的对象,这里我们要使用一个函数创建一个对象-------------构造函数,这也是这一章节的重点。
function person(){
this.name = '龙儿哥哥'
}
let pers = new person()
console.log(pers.name);//龙儿哥哥
二.什么是原型
注:
对象的常见访问形式:obj.name, obj['name']
常见的浏览器解析引擎的内置方法__proto__
,访问的是当前对象的原型(项目中不建议使用__proto__
访问原型)
1.为了便于理解给出以下例子
function Person(){
this.name = '龙儿哥哥'
}
let pers = new Person()
console.log(pers);
console.log(pers.__proto__);
打印结果如下图所示
(1)通过打印pers,可以清晰的看到pers是一个对象,其下有一个name属性,值为'龙儿哥哥',pers就是一个实例对象,name则为这个实例对象pers的实例属性。
(2)通过第二条,我们打印了pers.proto ,所以打印结果指向的是pers这个实例对象的原型。通过以上代码和打印结果我们知道红色框内的是一摸一样的数据,也就是说这两个红色框内的东东就是pers实例对象的原型(访问对象原型时不建议使用__proto__,这里打印单纯为了讲解,项目中请使用getPrototypeOf(obj)
访问对象原型)
(3)可以看到这个原型中存在两个属性:
一个是construtor,其值为Person这个函数,由此可见这个construtor指向的就是这个构造函数本身。
第二个使用 [[]] 包裹的Prototype属性,其值为Object,这个prototype就是pers这个实例对象的原型对象。
三.原型对象
1.第二章我们知道了什么是实例对象,什么是原型, 什么是原型对象以及 proto 的指向问题,这一章我们就深入理解实例对象,原型对象以及他们的关系。
function Person(){
this.name = '龙儿哥哥'
}
let obj = {
age:18
}
let pers = new Person()
Person.prototype.age = 18 //此方法给默认的原型设置属性,当存在Object.setPrototypeOf时此操作不生效,按需设置
// Object.setPrototypeOf(pers,obj) //为对象设置原型,替换原有原型对象,原对象原型将不生效
console.log('实例对象',pers)
console.log('属性值',pers.age)
console.log('原型',pers.__proto__) // 一般浏览器内置方法,项目中不建议使用
console.log('原型',Object.getPrototypeOf(pers)) // 项目中采用此方法访问对象原型
打印结果如下
从打印结果看
(1).实例通过__proto__
或Object.getPrototypeOf()
访问的就是一个对象的原型,原型也是一个对象。
(2).通过第二个打印,我们访问了实例对象pers的age
属性,打印的结果是实例对象的原型中的属性,当一个实例对象中不存在某个属性时,JS解析引擎(浏览器)会自动向原型中查找该属性。
(3).__proto
不作为公开的API,避免在项目中使用。应当使用基于ES6规范的Object.getPrototypeOf()
进行访问对象的原型
(4).实例对象的属性优先级高于原型中属性,如上例子:如果实例pers
和pers
的原型中都存在age
属性,打印pers.age
访问的将是实例中的age属性
(5).打印一个对象,可以看到当中有[[ProtoType]]:Object
,展开后可以发现当中存在很多方法,这些方法其实是JS引擎自动提供的原型方法
,这使得我们可以正常的使用字符串
,数组
,对象
,日期
的一些API。
2.什么是构造函数
function Person(){
this.name = '龙儿哥哥'
}
let pers = new Person()
let animal = {
type:'泰哥'
}
console.log('实例对象',pers)
console.log('实例对象',animal)
打印结果如下
从打印结果看
(1)打印的内容中有constructor
函数,这个函数就是构造函数
。
(2)通过构造函数创建的对象,其构造函数为当前函数;通过new Object
或{}
创建的对象,其构造函数是JS引擎自动创建的,其中有很多方法可通过示例进行调用。
(3) 构造函数的主要作用是在创建对象时初始化对象,即为对象的成员变量赋初始值
四.原型链
1.通过以上三章,我们能能大体了解到什么是对象
,实例
,原型
,原型对象
,构造函数
;
对象:在JS中万物皆“对象”,除了null
,undefined
等空值。(可以创建一个变量,然后通过访问其__proto__
属性),这里所说的“对象”只作为举例参考,并不作为变量类型判断依据。
实例:将一个对象赋值给一个变量后,这个变量就是实例,let obj = {}
,let obj1 = new Object()
,let obj2 = new function(){}
,这里的obj1,obj2,obj3
都是实例。
原型:实例通过__proto__
或Object.getProtoTypeOf()
访问到的就是原型,原型包含原型对象和构造函数
构造函数:跟普通函数一样,是创建对象的基本函数,但是普通函数不一定是构造函数。
原型对象:如果通过Object.setProtoTypeOf(obj1,obj2)
,那么obj2
就是原型对象,也可以说原型中除去构造函数部分就是原型对象。
参见上图:就是这几者之间的关系
2.理解了实例,原型,构造函数,我们再来探讨一下原型
function Person(){
this.name = '龙儿哥哥'
}
let pers = new Person()
console.log('pers',pers) //当前实例
console.log('pers',pers.__proto__) //原型
console.log('pers',pers.__proto__.__proto__) // null
(1)我们知道实例
通过__proto__
访问到的是原型
,继续链式调用__proto__
访问的则是原型的原型,直至最终值为null
;
let pers = new function Person(){
this.name = '龙儿哥哥'
}
let obj1 = {
age:18
}
let obj2 = {
sex:'男'
}
Object.setPrototypeOf(obj1,obj2)
Object.setPrototypeOf(pers,obj1)
console.log('pers',pers) //实例pers
console.log('pers',pers.__proto__) // obj1
console.log('pers',pers.__proto__.__proto__) // obj2
console.log('pers',pers.__proto__.__proto__.__proto__) // obj2的原型
console.log('pers',pers.__proto__.__proto__.__proto__.__proto__) // null
不理解代码可以参考下图:
(2)我们可以知道通过 new
关键字创建实例对象,通过__proto__
或Object.getPorotoTypeOf()
访问原型,通过Object.setProtoTypeOf()
来设置原型。
总结:揭开原型链
的面纱,原型链就是实例
,构造函数
,原型
以及__proto__
之间的指向关系。
补充:最后一张图是面试重点,也是会写javascript
的入门条件喔,一定要记牢。
转载自:https://juejin.cn/post/7376527773946118184