原型
1. 对原型的理解
-
当我们在 js 中创建一个函数 A(就是用 function 声明一个函数), 那么浏览器会在内存中创建一个对象 B。这个对象 B 就是函数 A 的原型对象,简称函数的原型,要通过 A.prototype 才能访问。
-
【函数 A 中】默认会有一个属性
prototype指向了对象 B-
( 即:prototype 属性的值是对象 B )。
-
【原型对象 B 中】默认会有一个属性
constructor指向了函数 A- ( 即:constructor 属性的值是函数 A )
-
我们可以自己对这个原型对象进行重新选择,赋值替换掉原来的对象 B,相当于手动改变 A 的原型
- 比如:A.prototype = { }
- 但别忘了在 B 中添加 constructor 属性
-
-
当我们用函数 A 去
new一个实例 C 时(当作构造函数来用)- 【实例 C 中】默认会有一个不可访问的属性
[[prototype]]指向了这个对象 B- 在个别浏览器中能用
实例C.__proto__去访问,但注意 ie 不行,所以别在代码中用这玩意儿 - ES5 提供了
Object.getPrototypeOf(实例C)方法返回指定对象的原型(即内部[[prototype]]属性的值)
- 在个别浏览器中能用
- 【实例 C 中】默认会有一个不可访问的属性
-
原型对象的用途是为每个实例对象存储共享的方法和属性,是一个普通对象而已。并且所有的实例是共享同一个原型对象,因此有别于实例方法或属性。原型对象仅有一份,而实例有很多份,且实例属性和方法是独立的。
2. 对原型链的理解
-
每个被 new 出来的实例对象都有一个私有属性(称之为
__proto__) -
这个属性的值,就是它的构造函数(可以从
__proto__.constructor中获得)的原型对象(prototype) -
然后这个原型对象的值,有两种情况
- 若不是
Object.prototype,那就回到第一步,把原型对象当成是被 new 出来的实例,继续向上找 - 若是
Object.prototype,代表追溯快到终点,这时候再走一步,把这个对象当成是被 new 出来的实例,那它的__proto__就是 null,而 null 的出现就是这个原型链中的最后一个环节
- 若不是
-
Object 对象站在几乎所有 JavaScript 对象的原型链顶端
-
对于一个类的实例
- 要用
instanceof判断是否为某一个类 - 不能用
typeof,否则一律返回 function,因为类本质就是函数,只是语法糖而已
- 要用
3. js 对作用域链的理解
-
js 是基于词法作用域的
- 即: 作用域链的查找顺序是按照函数“定义”时的位置决定的,而不是被调用的位置
-
所以下面的代码
var name = "global_name"; var type = "global_type"; function foo() { var name = "foo_name"; console.log(name); console.log(type); } function bar() { var name = "bar_name"; var type = "bar_type"; foo(); } bar();- 将会打印出 foo_name 和 global_type,而不会经过 bar 的作用域
-
词法作用域也叫静态作用域,因为是函数声明时就确定了的
- 与之相对的是动态作用域,它的作用域链查找顺序是按照函数“被调用”时的位置决定的,也就是基于调用栈