原型&&原型链&&执行上下文

原型&&原型链

原型

​ 1.函数的prototype属性

​ |每个函数都有一个prototype属性,默认指向一个Object空对象(原型对象)

​ |原型对象中有一个constructor属性,指向函数对象

在这里插入图片描述

function Fun(){//ctrl+shift+L 重命名所有的Fun都被修改
    
}
console.log(Fun.prototype)  //object

console.log(Fun.prototype.consructor===fun) //true

​ 2.给原型函数添加属性(一般都是方法)

​ |作用:函数所有的实例对象自动拥有原型的属性(方法)

Fun.prototype.test = function(){
	console.log('test()')
}
var fun = new Fun()
fun.test()  //会输出test()

显式原型和隐式原型

​ 1.每个函数都有一个prototype属性=>显式原型(构造函数时添加的)

​ 2.每一个实例对象都有一个 proto =>隐式原型(创建对象时添加的)

​ 3.对象的隐式原型的值为对应构造函数显式原型的值

​ 定义构造函数 -> 创建实例对象 ->给原型添加方法 -> 通过实例调用(程序员能直接操作显式原型,不能直接操作隐式原型 ES6之前

function Fun(){
    
}
console.log(Fun.prototype)// Object 显式
var fun = new Fun()
console.log(fun.__proto__) //Object 隐式
console.log(Fun.prototype===fun.__prototype__)//true

原型&&原型链&&执行上下文_第1张图片

原型链

​ |访问一个对象属性时,先在自身属性查找,若没有再沿着__proto__向上查找,原型链的尽头 -> Object的原型对象

​ |所有函数都是Function的实例,包括自身

function Fun(){
    this.test1 = function(){
        console.log('test1()') //给fun添加方法-> fun = Fun()
    }
}
Fun.prototype.test2 = function(){
    console.log('text2()')  //给Fun添加方法->直接Fun.prototype
}
var fun = new Fun()
fun.test1()//可输出
fun.test2()//可输出
console.log(fun.toString())//可输出 Object的原型对象有这个方法
fun.test3() //报错 未被定义

console.log(Object.prototype.__proto__) //null

原型&&原型链&&执行上下文_第2张图片

​ |原型链的属性问题:读取对象的属性值:会自动到原型链中查找;设置对象的属性值:不会查找原型链,如果当前对象没有此属性,直接添加并赋值

​ |方法一般定义在原型中,属性一般通过构造函数定义在对象本身

function Fun(){
    
}
Fun.prototype.a = 'xxx'
var fun1 = new Fun()
cosole.log(fun1.a)// xxx

var fun2 = new Fun()
fun2.a = 'yyy'
console.log(fun2.a,fun1.a) //yyy  xxx

instanceof

​ |表达式:A instanceof B 如果B函数的显式原型链对象在A对象的原型链上,返回true,否则为false

function Foo(){ }
var f1 = new Foo()
console.log(f1 instanceof Foo) //true
console.log(f1 instanceof Object) //true

测试题

//测试题1
function A(){}
A.prototype.n = 1

var b = new A()
A.prototype = {
    n:2,
    m:3
} //创建一个新的对象赋值给A的prototype 但b还指向原来A的prototype

var c = new A() //指向新的A的prototype
console.log(b.n,b.m,c.n,c.m)  // 1 undefined 2 3
//测试题2
var F = function F(){}
Object.prototype.a = function(){
    console.log('a()')
}
Function.prototype.b = function(){
    console.log('b()')
}
var f = new F() //原型对象Object
f.a() //原型对象Object  Object里有a方法 ->输出aa(
f.b() //报错 undefined b方法在Function的prototype里 不能通过f->Function
F.a() //F看成实例对象 终点都为Object -> a()
F.b() //b()  可以通过F -> Function 找到b方法

变量提升与函数提升

变量提升

​ 通过var定义的变量,在定义语句前就可以访问,只不过值为undefined

函数提升

​ 通过function声明的函数,创建函数语句前就可以调用,值为函数定义对象

执行上下文

全局执行上下文

​ 1.在执行代码前将window确定为全局执行上下文

​ 2.对全局数据进行预处理

​ | var定义的全局变量=>undefined,添加为window的属性

​ | function声明的全局函数=>赋值(fun),添加为window的方法

​ | this=>赋值window

​ 3.开始执行代码

console.log(a1) //相当于window.a1 undefined
a2()  //a2()
console.log(this)  //window

var a1 = 3 //执行代码时 会直接从该行跳到console.log(a1) funtion a2()已经执行过了
function a2(){
    console.log('a2()')
}
console.log(a1) //3

函数执行上下文

每当调用一个函数时,一个新的执行上下文就会被创建出来

​ 1.在调用函数执行函数体前,创建对应的函数执行上下文对象( 虚拟的,存在栈中,保存了函数中的所有形参,实参,局部变量,this指针等函数执行时的函数内部的数据情况 )

​ 2.对局部数据进行预处理(封闭的区域

​ |形参变量 =>赋值(实参)=>添加为执行上下文的属性

​ |arguments =>赋值(实参列表)=>添加为执行上下文的属性

​ | var定义的全局变量=>undefined,添加为执行上下文的属性

​ | function声明的全局函数=>赋值(fun),添加为执行上下文的属性

​ |this =>赋值为调用函数的对象

3.开始执行函数体代码

function fn(a1){
    console.log(a1) //2
    console.log(a2) //undefined  此时a2还未被赋值
    a3() //a3()
    console.log(this) //window
    console.log(arguments) //伪数组  Arguments(2) [0]:2;[1]:3

	var a2 = 3 
	function a3(){
    	console.log('a3()') 
	}
}
fn(2,3)

执行上下文栈

1.在全局代码执行前,JS引擎会创建一个栈来储存管理所有的执行上下文对象

2.在全局执行上下文(window)确定后,将其添加到栈中(压栈)

3.在函数执行上下文创建后,将其压栈

4.当前函数执行完后,将栈顶对象移除

5.所有代码执行完,栈中只剩window

var a = 10 	               //1.进入全局执行上下文
var bar = function(x){
    var b = 5
    foo(x+b)              //3.进入foo函数执行上下文
}
var foo = function(y){
    var c = 5
    console.log(a+c+y)   //最后输出30
}
bar(10)	                   //2.进入bar函数执行上下文 
console.log('globle begin' + i)  //undefined
var i=1      
foo(1)
function foo(i){
    if(i==4){
        return;
    }
    console.log('foo() begin:'+i)
    foo(i+1) //递归
    console.log('foo() end:'+i)
}
console.log('globle end:'+i)
/*依次输出: 1.globle begin:undefined 2.foo() begin:1   3.foo() begin:2  4.foo() begin:3   5.foo() end:3    6.foo() end:2   7.foo() end:1  8.globle end:1

注意:先执行变量提升 后执行函数提升

function a(){}
var a
console.log(typeof a) //function
var c=1
function c(c){
    console.log(c)
}
c(2)  //会报错:c is not a function

//实际上代码是这样执行的
var c
function c(c){
    console.log(c)
}
c = 1  //此时c是一个变量,所以报错
c(2) 

执行函数提升

function a(){}
var a
console.log(typeof a) //function
var c=1
function c(c){
    console.log(c)
}
c(2)  //会报错:c is not a function

//实际上代码是这样执行的
var c
function c(c){
    console.log(c)
}
c = 1  //此时c是一个变量,所以报错
c(2) 

你可能感兴趣的:(原型&&原型链&&执行上下文)