# 5.作用域链和原型链
# 针对的对象不同
- 作用域链:针对变量
- 原型链: 针对构造函数(对于对象的属性,方法)
# 形式不同
# 作用域链:
作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。如:
var a = 1;
function b() {
var a = 2;
function c() {
var a = 3;
console.log(a);
}
c();
}
b();
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
最后打印出来的是 3,因为执行函数 c()的时候它在自己的范围内找到了变量 a 所以就不会越上继续查找,如果在函数 c()中没有找到则会继续向上找,一直会找到全局变量 a,这个查找的过程就叫作用域链。
不知道你有没有疑问,函数 c 为什么可以在函数 b 中查找变量 a,因为函数 c 是在函数 b 中创建的,也就是说函数 c 的作用域包括了函数 b 的作用域,当然也包括了全局作用域,但是函数 b 不能向函数 c 中查找变量,因为作用域只会向上查找。
# 原型链
当访问一个对象的属性时, 会在这个对象的属性上去找,如果没有找到就会去这个对象的--proto-- 上去找,即构造函数 prototype 上找,如果没有会一直在--proto-- 上找,直到最顶层,不到即为 undefined 。这样一层一层地向上,就彷佛一条链子串起来,所以就叫原型链。
# 顶层不同
作用域链顶层是 window,原型链顶层是 Object。
# 什么是作用域
# 全局作用域
任何不在函数或者大括号下声明的变量
# 函数作用域
也叫局部作用域。在函数内部声明。
# 块级作用域
let const 和箭头函数里面的。外部不能访问这些变量。比如在全局 if(1){let a = 1}
# 什么是原型链
# 第一、仅留下proto属性
- 一个实例对象可以通过proto 访问他的原型对象(也就是父对象),他可以从原型对象那里继承属性和方法。在访问一个对象的属性的时候,如果内部不存在此对象,就会往原型对象上面找,如果还没找到,就继续往他的proto 属性找,直到找到或者到原型链顶端 null。这个就是原型链
- prototype 是函数特有的,从函数指向一个对象。f1.proto == Foo.prototype 。他的作用就是包含一个类所有实例共享的属性和方法。在实例化对象的时候,他的实例对象都可以继承公用的属性和方法
__ptoto__
和 constructor 是对象独有的,因为 js 中函数也是对象,所以函数也拥有此方法- Foo.prototype 的 constructor 是 Foo(),而 f1 的 constructor 是从 Foo.prototype 中继承过来的。
__proto__、constructor
属性是对象所独有的;prototype
属性是函数独有的;- 上面说过 js 中函数也是对象的一种,那么函数同样也有属性proto、constructor;
# 1. prototype 属性
为了方便举例,我们在这模拟一个场景,父类比作师父,子类比作徒弟。师父收徒弟,
徒弟还可以收徒弟。徒弟可以得到师父传授的武功,然后徒弟再传给自己的徒弟。
师父想要传授给徒弟们的武功就放到“prototype”这个琅琊福地中。徒弟徒孙们就去这里学习武功。
prototype属性可以看成是一块特殊的存储空间,存储了供“徒弟”、“徒孙”们使用的方法和属性。
1
2
3
4
2
3
4
# 2. proto 属性
__proto__属性相当于通往prototype(“琅琊福地”)唯一的路(指针)
让“徒弟”、“徒孙” 们找到自己“师父”、“师父的师父” 提供给自己的方法和属性
1
2
2
我们之前也说过__proto__
属性是对象(包括函数)独有的,那么Parent.prototype
也是对象,那它有隐式原型么?又指向谁?
Parent.prototype.__proto__ === Object.prototype; //true
//可以看到,构造函数的原型对象上的隐式原型对象指向了Object的原型对象。那么Parent的原型对象就继承了Object的原型对象。由此我们可以验证一个结论,万物继承自Object.prototype。这也就是为什么我们可以实例化一个对象,并且可以调用该对象上没有的属性和方法了。
1
2
2
# 3.constructor 属性
constructor属性是让“徒弟”、“徒孙” 们知道是谁创造了自己,这里可不是“师父”啊
而是自己的父母,父母创造了自己,父母又是由上一辈人创造的,……追溯到头就是Function() 【女娲】。
1
2
2
# Function instanceof Object 和 Object instanceof Function
Function.__proto__.__proto__ === Object.prototype; //true
Object.__proto__ === Function.prototype; //true
1
2
2
//①构造器Function的构造器是它自身
Function.constructor === Function; //true
//②构造器Object的构造器是Function(由此可知所有构造器的constructor都指向Function)
Object.constructor === Function; //true
//③构造器Function的__proto__是一个特殊的匿名函数function() {}
console.log(Function.__proto__); //function() {}
//④这个特殊的匿名函数的__proto__指向Object的prototype原型。
Function.__proto__.__proto__ === Object.prototype; //true
//⑤Object的__proto__指向Function的prototype,也就是上面③中所述的特殊匿名函数
Object.__proto__ === Function.prototype; //true
Function.prototype === Function.__proto__; //true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15