一、函数内存结构
1、函数声明
(1) 解析到函数声明语句时,相当于创建一个函数对象
(2)函数体中的代码会以字符串的形式存储到堆区域
(3) 将函数体堆区域的地址复制给函数名
2、函数调用
(1)根据函数名找到函数体在堆区域代码
(2)复制函数体代码到调用栈区域执行
(3)执行完毕销毁调用栈
二、函数不被销毁的执行空间
1、函数调用时,函数体代码返回一个复杂数据类型对象,赋值给一个变量,该变量引用函数体复杂数据类型,调用栈空间不会被销毁
三、闭包
1、闭包形成的条件
(1)函数嵌套:外层函数嵌套内层函数
(2)外部引用返回的内层函数
(3)内层函数使用外层函数的变量
function fun(){
let num=100
//内层函数
return function(){
console.log('num',num) //内层使用外层函数变量
}
}
let f=fun() //外部引用返回的内层函数
f()
2、闭包作用
(1)形成不被销毁的执行空间,延长变量生命周期
缺点:容易引起内存泄露
(2)外部可以访问内部函数的变量---变量作用域扩展
(3)形成块级作用域定义私有变量
块级作用域:多次调用,函数体多次复制到调用栈,互不干扰
四、闭包的三种写法
1、显示写法
function A(){
let num=100
return function B(){
console.log(num)
}
}
let f=A()
2、隐式写法
let B
function A(){
let num=100
B=function(){
console.log(num)
}
}
A()
B()
3、自调用函数
let x=(function(){
let num =100
return function B(){
console.log(num)
}
})()
五、柯里化函数
1、定义
将有多个形参的函数转换为多个只有一个形参的函数
f(a,b,c)=>fn(a)(b)(c)
2、通用柯里化函数
function sum(a,b,c,d){
return a + b + c + d
}
function currying(func){ // func -> sum
// ...args 表示可变长度形参
return function curried(...args){
// 判断形参args个数>= 原函数参数个数func
if(args.length >= func.length){
return func.apply(this,args) //sum(10,20,30)
}else{
return function(...arg2){
// 参数拼接
let arg = [...args,...arg2] // -> [10,20,30]
return curried.apply(this,arg)
}
}
}
}
let f = currying(sum) // f(10,20,30)
// let s = sum(10,20,30)
let s = f(10)(20)(30)(40)
console.log('s :',s);
六、继承
1、面向对象三大特性
(1)封装:对象属性和方法
(2)继承:子类继承父类,子类就拥有父类的属性和方法
(3)多态:一个事务有多种表现形态
2、ES5实现继承
(1)构造函数继承(不能继承父类原型对象上的属性和方法)---在子类构造函数中调用父类构造函数
(2)拷贝继承-实现原型属性和方法继承
// 父类
function Parent() {
this.money = 100000
this.home = '房子'
this.playGame = function () {
console.log('玩游戏')
}
}
Parent.prototype.swiming = function(){
console.log('游泳');
}
// 子类
function Son() {
// 构造函数继承
Parent.call(this)
this.name = 'jack'
}
// 拷贝继承-实现原型属性和方法继承
for(const key in Parent.prototype){
Son.prototype[key] = Parent.prototype[key]
}
let parent1 = new Parent() // parent1是有money和房子的父类实例对象
let s1 = new Son() // 名为jack的儿子实例对象
// 测试儿子是否继承到父类属性和方法
s1.playGame()
console.log(s1.money, s1.home);
s1.swiming()
(3)原型继承
// 父类
function Parent() {
this.money = 100000
this.home = '房子'
this.playGame = function () {
console.log('玩游戏')
}
}
Parent.prototype.swiming = function(){
console.log('游泳');
}
// 子类
function Son() {
this.name = 'jack'
}
// 原型继承 - 改变原型指向实现 - 将父类实例复制子类原型对象
Son.prototype = new Parent()
let parent1 = new Parent() // parent1是有money和房子的父类实例对象
let s1 = new Son() // 名为jack的儿子实例对象
// 测试原型继承
s1.swiming()
s1.playGame()
console.log(s1.money, s1.home);
(4)组合继承
构造函数+拷贝继承
3、ES6实现继承
(1)class类继承
(2)语法
// 父类
class Parent {
constructor() {
this.money = 100000
this.home = '房子'
}
playGame(){
console.log('玩游戏');
}
swiming(){
console.log('游泳');
}
}
// 子类Son继承父类Parent
class Son extends Parent{
constructor(name){
// 先实例化父类
super() //super关键字表示父类构造器
this.name = name
}
}
let parent1 = new Parent()
let son1 = new Son('jack')
son1.swiming()
son1.playGame()
console.log(son1.money, son1.home);