原型链与声明提升(预解析)


原型链

显示原型与隐式原型

显示原型prototype

隐式原型[[prototype]] (__proto__已被弃用,现在用[[prototype]]代替)

原型链

当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的[[prototype]]隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的[[prototype]]中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。

注意: __proto__已被[[prototype]]代替,[[prototype]]通过Object.getPrototypeOf(实例对象)获取

实例对象.__proto__===Object.getPrototypeOf(实例对象)

构造函数的显示原型(prototype)等于实例对象的隐式原型([[prototype]])

构造函数.prototype===实例对象.__proto__

所有构造函数都是Function的实例,包括Function自身,

构造函数.__proto__===Function.prototype

所有显式原型都是Object的实例,包括Object自身

prototype.__proto__===Object.prototype

Function因为是自身的实例,因此Function既可以通过prototype访问自身的原型对象,也可以通过__proto__访问自身的原型对象

Function.__proto__===Function.prototype
Function.__proto__.__proto__===Function.prototype.__proto__

Object的原型对象的__proto__指向null(原型链的终点)

因为如果Object.prototype===Object.prototype.__proto__(所有原型对象都是Object的实例)原型链最终将一直访问Object.prototype没有尽头,因此设定Object.prototype.__proto__===null

Object.prototype.__proto__===null

声明提升(预解析)及其优先级

函数的声明和变量的声明都会提升到其所在作用域最顶端(函数体内提升到函数体最顶部,全局提升到全局最顶部)

函数首先被提升,然后才是变量。(函数是一等公民,优先编译)

函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。

典型例子:

console.log(foo);
foo();
var foo = "变量";
function foo(){
    if(false){
    	var foo=1;
    }
    console.log(foo);
}
console.log(foo);

代码预解析为:
function foo(){
    var foo;
    if(false){
    	foo=1;
    }
    console.log(foo)
}
var foo;
foo();					//控制台打印undefiend
console.log(foo);   	//foo函数体
foo = "变量";
console.log(foo); 		//变量

注意:

1.函数表达式声明时,只有前面的变量会发生声明提升,后面的函数并不会发生声明提升
2.变量只赋值不声明js引擎会自动在全局中声明(但是只在这个变量赋值之后的位置有效)严格模式下会报错

函数表达式声明例子

  console.log(fn);      //undefined
  var fn=function(){
  }

  //预解析为:
  var fn;
  console.log(fn);
  fn=function(){
  }

变量值赋值不声明例子

  b=10;
  console.log(b);   //10
  console.log(a);   //Error:a is not defined
  a=10;

变量值赋值不声明例子之a=b=10

  a=b=10;
  (function(){
      var a=b=20;
  })();
  console.log(a,b); //10,20

  //预解析
  a=10;
  b=10;
  (function(){
    var a=20;
    b=20;
  })
  console.log(a,b);

相关