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
|访问一个对象属性时,先在自身属性查找,若没有再沿着__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
|原型链的属性问题:读取对象的属性值:会自动到原型链中查找;设置对象的属性值:不会查找原型链,如果当前对象没有此属性,直接添加并赋值
|方法一般定义在原型中,属性一般通过构造函数定义在对象本身
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
|表达式: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)