闭包
函数执行空间
当js引擎解析到fn函数定义时,在堆区域开辟一块存储空间,将函数体内代码以字符串形式存储到堆区域,在栈区域存储fn函数变量,并将堆区域存储空间地址赋值给fn
function fn(){
let num = 100
console.log( 'fn函数' ,num)
}
fun()
当执行函数调用语句fn()时,根据fn找到堆区域函数体代码,复制一份到调用栈区域,执行调用栈函数体代码,执行完毕销毁调用栈区域
不摧毁函数执行空间
当执行函数调用语句fn()时,根据fn找到堆区域函数体代码,复制一份到调用栈区域,执行调用栈函数体代码,函数体代码返回一个复杂数据类型,赋值给变量f,f引用函数体复杂数据类型对象,调用栈空间不会销毁
概念
1.有一个A函数,在A函数内部返回一个B函数
2.在B函数内部,访间A函数私有变量
3.在A函数外部,有一个变量引用返回的B函数
function A(){
let num = 100
//1.A函数内部返回一个B函数(显示)
return function B(){
console. log(num) //2.B函数内部,访间A函数私有变量num
}
}
let f = A()// 3.变量f引用返回的B函数
闭包形成后:生成一个不会被销毁的函数执行空间,内部函数叫做外部函数的闭包函数
形成条件
- 有函数嵌套,内层函数被返回
- 内层函数访问外层函数私有变量
- 返回的内层函数被引用
三种写法
-
显示写法
function A(){ let num = 100 //1.A函数内部返回一个B函数(显示) return function B(){ console.log(num) //2.B函数内部,访间A函数私有变量num } } let f = A() // 3.变量f引用返回的B函数 -
隐示写法
let B //3.在A函数外部,有一个变量引用返回的B函数 function A(){ let num = 200 //1.A函数内部返回一个B函数(隐示)B= function ( { console.log(num)//2.B函数内部,访问A函数私有变量num } } A() B() -
自调用函数
let x= (function () { let num = 300 return function B() { console. log(num) } })()
特点
- 作用域空间不销毁
优点: 因为不销毁,变量不会销毁,增加了变量的生命周期
缺点: 因为不销毁,会一直占用内存,多了以后就会导致内存溢出 - 可以利用闭包,在一个函数外部,访问函数内部的变量
优点: 可以在函数外部访问内部数据
缺点: 必须要时刻保持引用,导致函数执行栈不被销毁 - 保护私有变量
优点: 可以把一些变量放在函数里面,不会污染全局
缺点: 要利用闭包函数才能访问,不是很方便
柯理化函数
柯里化介绍
柯里化(Currying)是一种关于函数的高阶技术。它不仅被用于 JavaScript,还被用于其他编程语言。
柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。
柯里化不会调用函数。它只是对函数进行转换。
理解柯里化
创建辅助函数 currySum(f)
该函数将对两个参数的函数 f 执行柯里化。换句话说,对于两个参数的函数 f(a, b) 执行 currySum(f) 会将其转换为以 f(a)(b) 形式运行的函数
function sum(a,b){
return a + b
}
//柯理化转换
function currysum(s){
return function(a){
return function(b){
return s(a,b)
}
}
}
const f = currySum(sum)// f为转换后的柯里化函数
const s = f(10)(20) // f(10)(20)<=> f1 = f(10),f1(20)
console.log(s)
高级柯里化实现
function curry (func) {
return function curried(...args) {
if (args.length >= func.length){
return func.apply(this,args);
} else {
return function(...args2){
return curried.apply(this, args.concat(args2));
}
}
};
}
继承
继承是类与类之间的关系,子类继承父类子类就拥有父类的属性和方法。JS中没有类,但是可以通过构造函数模拟类,然后通过原型来实现继承
继承方式
-
构造函数继承
//学生-子类 function Student() { Person.call(this) //构造函数继承,继承父类构造函数属性和方法 this.num = 1001 //学生学号 } -
原型拷贝继承
//拷贝继承,继承父类原型对象上公共的属性和方法 for(let key in Person.prototype){ Student-prototype[key] = Person.prototype[key] } -
原型继承
改变原型指向 -
组合继承
就是把原型继承和借用构造函数继承两个方式组合在一起function student() { Person.call(this) } student.prototype = new Person
示例
/**
*代参继承
*/
//人类-父类
function Person(){
this.name = 'jack'
this.age = 20
}
Person. prototype = {
constructor: Person,//手动设置constructor指向构造函数
say:function() {
console.log('说话')
}
}
//学生-子类
function Student() {
Person.call(this)//构造函数继承
this.num = 1001 //学生学号
}
Student.prototype = {
constructor: Student,
//读书
readBook:function() {
console.log('学生读书')
}
}
//原型拷贝继承
for(let key in Person.prototype){
Student.prototype[key] = Person.prototype[key]
}
//测试-子类访间父类属性和方法
s1.readBook()
s1.say()
console.log(s1.name,s1.age,s1.num)
ES6的类与继承
-
class
class类名{ //构造函数 constructor(name){ this.name=name } //方法 say() {} } -
语法
//下面表示创造一个Student类,继承自Person类 class Student extends Person { constructor () { //必须在constructor里面执行一下super()完成继承 super() } }