1.原型和原型链-作用域和作用域链
一、请谈谈原型和原型链
原型
js中每个函数都有一个属性,prototype,这个属性的属性值是一个对象,这个对象被称为原型对象。每个对象都可以看做是由构造函数生成的实例,原型对象就是这些实例的原型。原型中保存了这些实例间共享的属性和方法,当访问对象的某个属性时,如果这个属性不存在,就会从原型上去找
原型链
上面说了对象都有原型,原型也是一个对象,那原型对象也有它的原型。这样就行成了:对象->原型->原型->原型...,这样原型层层链接在一起,就形成了原型链。如:
[] -> Array.prototype -> Object.prototype -> null,
原型链的为什么一定要有个终点呢?如果没有终点的话,访问对象上某个不存在的属性,就会在原型链上无休止地一直找下去。所以规定Object.prototype 的原型是 null,js中null的意思是 “没有对象”
二、请谈谈作用域和作用域链
1.作用域
通常开发者们口中说作用域包含两次意思:
- 说某个变量的作用域时,指的是这个变量的可被访问范围
- 说某个函数的作用域时,指的是在某函数内部能被访问,且能被函数内部所有地方访问的变量,称之为局部变量
我尝试给作用域下了一个定义:具有相同可被访问范围的一组变量的集合
2.作用域链
一段代码的执行环境又被称作执行期上下文。一段可执行代码在执行时,引擎会创建一个对象保存这个这段代码的环境信息。这个对象叫做执行期上下文对象。执行期上下文上有个属性叫变量对象,保存了当前执行环境的参数、函数、变量。作用域链就是一个数组,第一项到最后一项依次保存了当前执行环境的变量对象,父级环境的变量对象,一直到全局环境的变量对象。当检索变量时,就会从作用域中依次查找。
作用域链中,被保存了变量对象的父级环境,是指词法上的父级环境,还是运行时的父级环境呢?
如果是词法上的父级环境,也就是(函数)声明时的父级环境。这种作用域链的设计方式叫做词法作用域,又称静态作用域
如果是运行时的父级环境,也就是(函数)调用时的父级环境。这种方式叫做动态作用域
js中是采用静态作用域
举个例子:
var x = 1;
function f1() {
console.log(x)
}
function f2() {
var x = 2;
f1()
}
f2()
函数f1是在全局声明的,在f2内调用的。其作用域链[[scope]]的第一项始终是其当前执行环境的变量对象,第二项是其词法上的父级环境的变量对象,也就是全局环境的变量对象,globalContext.VO。
[[scope]] = [f1Context.VO, globalContext.VO],当执行console.log(x)时,依次检索变量x,f1Context.VO中没有叫x的参数、变量、函数,globalContext.VO中有变量x,所以最终打印结果是1。
变量对象VO是一个抽象概念,是语言规范内规定的抽象概念。全局上下文的变量对象是全局对象,函数上下文变量对象是活动对象。globalContext.VO 是global object,fnContext.VO是fnContext.AO
Variable object is an abstrat thing,which can be either of those:
- global object (in global context)
- activation object (in funtion context)