从数据结构链表,栈,队列 再去看原型链(原型链篇)
再去学习,理解之前,我们要先了解什么是链表,什么是栈结构,什么是队列结构,下面我们用最简单最快捷的方式去给大家讲解下什么是链表、栈、队列,在对这三个基础理解明白后再去看原型链,作用域链,闭包,将会发现用一句成语来表达就是 殊途同归
链表
什么是链表,我们看下下面的一张图 从这张图可以看出来,链表就是一个指向另一个,最后一个指向null,我们称之为单链表, 我们用代码如何表示呢,看下面
function NodeList(val){
this.value = val;
this.next = null
}
let a = new NodeList('A')
let b = new NodeList('B')
let c = new NodeList('C')
let d = new NodeList('D')
a.next = b;
b.next = c;
c.next = d
console.dir(a)
栈
栈 你就把他想象成一个箱子,然后我需要把A,B,C,D依次放入到这个栈(箱子)里面去,然后,我下次要使用这个栈(箱子)里面的任何一个的时候,是不是得先把D,C,B,A按顺序取出来,这边大家可别想当然说什么,我把箱子底打穿,我箱子够大,从旁边抽出来,哈哈哈。。。开个玩笑,我们说回来,下面我们给个总结:先入后出 我们从代码层面来写个简单的栈结构
//模拟栈
var arr = new Array(0)
function Stack(){
this.arr = [];
this.push = function(a) {
this.arr.push(a)
console.log(this.arr)
}
this.pop = function () {
return arr.pop()
}
}
let a = new Stack()
a.push('A')
a.push('B')
a.push('C')
a.push('D')
console.dir(a)
通过Array的api pop() 模拟栈取出的现象(其实reduceRight()不清楚这个api的可以去 MDN 查找,也可以模拟出这个)
console.dir(a.pop()) // D
console.dir(a.pop()) // C
console.dir(a.pop()) // B
console.dir(a.pop()) // A
//最后 a.arr = []
队列
队列结构,跟栈相比,基本上可以这么说,就是逻辑相反的 栈 ,刚刚上面不是我们开玩笑说,把栈的底部打穿就是 队列,让他变成一个前后漏风的管道,谁先进来,谁就先出去。 我们看图对队列结构有个大概的理解,一个管道,ABCD,进去,然后ABCD 依然按照顺序出来,总结:先进先出 我们继续用代码来表达下
//模拟队列
var arr = new Array(0)
function Queue(){
this.arr = [];
this.push = function(a) {
this.arr.push(a)
}
this.shift = function () {
return arr.shift()
}
}
let a = new Queue()
a.push('A')
a.push('B')
a.push('C')
a.push('D')
console.dir(a)
a.shift() // A
a.shift() // B
a.shift() // C
a.shift() // D
console.log(a.arr)
好三种结构我们就先讲到这,详细深入理解可以去看关于单个的文章,提高对此深度了解,接下来我们开始讲第一个原型链
原型链
原型链从名字来看就可以知道,他是由多个原型组成的链表的结构,由多个原型组成的链表结构的数据,接下来我看一个手画图
从图中我们能够看到__proto__隐式原型一层一层指向他的构造他的原型上,然后最终的Object的
//我们写个简单例子
var a = new Object()
// a是不是通过Object构造函数创建的
// a的__proto__ 按照图指向Object的prototype
//我们可以这么验证
console.log(a.__proto__ == Object.prototype)
// true
//但是我们会发现一个有趣的例子
const person = {
isHuman: false,
printIntroduction: function() {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const b = Object.create(person);
console.log(b.__proto__ == Object.prototype)
// 大家自行测试结果,如果不清楚,可以去看MDN
到这里我们就清楚,原型链,就是创造的各个对象的隐式原型进行一层一层指向形成一个链式结构 那生成这个原型链有什么意义,作用呢,我接下来从代码的角度来看
function a (){
var c = 1
function b(){
console.log('hello world')
}
}
console.dir(a)
var d = new a()
console.log(d.c)
我们写一个函数 a , 然后基于 a new 一个 d,然后我打印a.c 会怎么样,是undefined 还是 1呢,毋庸置疑,他打印 是undefined ,因为当这个对象d的里面没有这个属性c的时候他的隐式原型指向a的原型,他会去a的原型里面查找有木有c这个属性,c不在a的原型上,然后在a的__proto__上指向Function原型上也没有,Function的__proto__指向Object的原型,最后发现并没有c,最后undefined
Function.prototype.c = 1
function a (){
var c = 1
function b(){
console.log('hello world')
}
}
console.dir(a)
var d = new a()
console.log(d.c)
这是后打印出来就是 1 因为早Function的原型上有c这个属性
总结
发现没有,通过原型链来获取是否含有这个属性值,因为链表结构是一层指向下一层,去查询,是不是跟栈结构的一些行为很像,最先在里面的肯定在最后面,新的再上面,第一个新取出来,才能取下面一个,首先没有说链表跟栈一样,只是他的一些行为类似。 因为我这边只是按个单链表进行类比的,链表的的种类很多,可以去查阅一些深入讲解数据结构的链表一些文章,以方便深入理解链表。
转载自:https://juejin.cn/post/7236668895867912229