美文网首页
this、原型、作用域、执行上下文梳理

this、原型、作用域、执行上下文梳理

作者: AlwaysFy | 来源:发表于2018-03-25 16:32 被阅读0次

本文将this、prototype、Scope Chain、Execution Context放在一起梳理一哈

先看这样一段代码
var b = 'window_b'
var c = 'window_c'
Function.prototype.f = 'f'
Object.prototype.o = 'o'

function foo(a) {
  var b = 'foo_b'
  //var c = 'foo_scope'
  function bar() {
  }
  console.log(b) //foo_b
  console.log(this.b) //window_b
  console.log(c) //window_c
  console.log(foo.f) //f
  console.log(foo.o) //o
}
foo('a')
foo.constructor === Function //true
Function.prototype.constructor === Function //true
foo instanceof Function //true
foo instanceof Object //true
思考:
  • foo函数为什么可以用this关键字
  • foo函数为什么可以访问函数外的变量
  • 函数的constructor属性

首先this只存在于Execution Context(执行上下文)中,而每当调用一个函数时,一个新的执行上下文就会被创建并压栈到call stack(函数调用栈)栈顶栈底为全局执行上下文)。函数执行完从栈顶出栈

执行上下文有两个阶段:
  1. 函数刚被调用时:创建变量对象VO(Variable Object)包括:variables:undefinedfunctions:<函数名:函数引用>arguments:<函数参数:undefined>
    确定this指向:取决于函数被调用的方式(普通自调用、对象方法调用、new...);
    建立Scope chain作用域链从:栈顶指向栈底,指向每个执行上下文中的AO(Activation Object)。这也可以解释闭包,因为函数体内调用函数的话,栈顶为“被调用函数”压住了“原函数”(栈是后进先出的)于是可以访问“原函数”的AO
  2. 函数代码执行时:变量对象VO(属性无法访问)激活为=>活动对象AO(属性可以访问)
根据知识点解释代码:

首先函数被普通自调用foo('a'):

foo_Context = {
  VO: {
    arguments:{
      a:undefined,
    },
  b:undefined,
  bar: bar reference
  },
  this:undefined,
  [[scope]]:Global_Context.AO
}

接下来函数代码要执行了

foo_Context = {
  AO: {
    arguments:{
      a:'a',
    },
  b:'foo_b',
  bar: bar reference
  },
  this:window,//因为没有"use strict"
  [[scope]]:Global_Context.AO
}
 console.log(b)  其实就是在foo_Context.AO.b中取值

 console.log(this.b) 很明显 window.b === 'window_b' (Global_Context.AO.b)

 console.log(c) 因为foo_Context.AO里没有就要顺着作用域链找  foo_Context.[[scope]].c === 'window_c'

原型链与作用域链很像 对象的隐藏属性[[prototype]](浏览器提供了__proto__属性)就是原型链每一段链子
访问一个对象自身没有的属性时,会顺着内部属性[[prototype]]这条链子找。直到Object.prototype.__proto__===null
而[[prototype]]指向构造器的prototype属性的值[].__proto__ === Array.prototype;{}.__proto__ === Object.prototype;...函数的构造器都是FunctionArray.__proto__===Function.prototype;Object.__proto__ === Function.prototype

 console.log(foo.f) //f
 foo.__proto__ = Function.prototype
 foo.__proto__.f = Function.prototype.f === 'f'

 console.log(foo.o) //o
 同理:
 foo.__proto__.__proto__ = Function.prototype.__proto_ = Object.prototype
//原型对象也是对象所以构造器为Object
//而Function.prototype是个例外它既是对象又是函数
 typeof Function.prototype //function
 Function.__proto__ === Function.prototype //Function由自身创建
 foo.constructor === Function //true
 foo.constructor ===  Function.prototype.constructor === Function

当我们修改了默认的原型对象如:

 foo.prototype = {some:some...}
 foo.prototype.constructor === Object //true
 因为{}是function Object创建的
 {}.__proto__.constructor ===Object.prototype.constructor === Object
 所以要重新绑定foo.prototype.constructor = foo

关于instanceof:

A instanceof B 其实就是找A的原型链中是否有B.prototype
A.__proto__ instanceof B
A.__proto__.__proto__ instanceof B

foo instanceof Function //true
foo.__proto__ === Function.prototype 
foo instanceof Object //true
foo.__proto__.__proto__ === Object.prototype 
A一定要是一个对象
console.log(new Number(1) instanceof Number) //true
console.log(new Number(1) instanceof Object) //true
console.log(new Number(1) instanceof Function) //false
基本包装类型1的原型链:
(1).__proto__ === Number.prototype
(1).__proto__.__proto__ === Number.prototype.__proto__ === Object.prototype
(1).__proto__.__proto__.__proto__ === Number.prototype.__proto__.__proto__ === Object.prototype.__proto__ === null

相关文章

网友评论

      本文标题:this、原型、作用域、执行上下文梳理

      本文链接:https://www.haomeiwen.com/subject/quuhcftx.html