闭包
闭包是什么
闭包是javascript语法现象,是函数的高级用法,是函数不被销毁的执行空间
闭包形成条件
1. 函数嵌套- 外层函数 内层函数
2. 外部引用返回的内层函数
3. 内层使用外层函数变量
闭包作用
1. 形成不被销毁的执行空间,延长变量生命周期, 缺点,容易引起内存泄露
2. 外部可以访问内部函数的变量- 变量作用域扩展 - 没有形成闭包,只能内部函数访问外层函数变量
3. 形成块作用域定义私有变量
闭包的三种写法
显示写法
// 1. 函数嵌套外层函数
function fun() {
let num = 100 // 3. 内层使用外层函数变量
// 内层函数
return function(){
console.log('num :',num)
}
}
let f = fun() // 2. 外部引用返回的内层函数
let f1 = fun()
f()
隐示写法
let B
function fun(){
let num = 100
B = function(){
console.log('num ',num)
}
}
fun()
B()
自调用写法
let x = (function(){
let num = 100
return function B(){
console.log('num ',num)
}
})()
x()
闭包应用 点赞
<div>
<ul>
<li>
<h2>明星1</h2>
<button>点赞 0</button>
</li>
<li>
<h2>明星2</h2>
<button>点赞 0</button>
</li>
<li>
<h2>明星3</h2>
<button>点赞 0</button>
</li>
</ul>
</div>
const buttonEles = document.querySelectorAll('button')
//显示方法
for (var i = 0; i < buttonEles.length; i++) {
// 1. 函数嵌套
function fun() {
var num = 0 //点赞数量
// 2. 外部引用内层函数
buttonEles[i].onclick = function () {
num++ // 3. 内层函数使用外层函数变量
this.innerHTML = '点赞 ' + num
}
}
fun()
}
//自调用方法
// for (var i = 0; i < buttonEles.length; i++) {
// (function(k){
// var num = 0 //点赞数量
// // 2. 外部引用内层函数
// buttonEles[k].onclick = function () {
// num++ // 3. 内层函数使用外层函数变量
// this.innerHTML = '点赞 ' + num
// }
// })(i)
// }
//let作为块作用域也是同样的效果
// for (var i = 0; i < buttonEles.length; i++) {
// let num = 0 //点赞数量
// // 2. 外部引用内层函数
// buttonEles[i].onclick = function () {
// num++ // 3. 内层函数使用外层函数变量
// this.innerHTML = '点赞 ' + num
// }
// }
* {
padding: 0;
margin: 0;
}
ul,
li {
list-style: none;
}
ul {
display: flex;
width: 400px;
margin: 100px;
}
li {
width: 100px;
height: 300px;
border: 1px solid rgb(37, 37, 37);
margin-left: 10px;
}
h2 {
padding-bottom: 200px;
}
柯里化函数
柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。柯里化不会调用函数。它只是对函数进行转换。
function sum(a,b){
return a + b
}
let f = curryingSum(sum)
// let s = sum(10,20)
let s = f(10)(20)
// let s = sum(10,20)
// console.log(s)
/*
sum进行柯里化转换 -> f(10)(20) <=> sum(10,20)
let f = curryingSum(sum)
*/
function curryingSum(sum){
return function(a){
return function(b){
return sum(a,b)
}
}
}
console.log('s ',s)
通用柯里化函数
定义可以变长度形参函数
function fn(...args){
console.log(args) // [1,2,3]
}
fn(1,2,3)
定义一个函数,参数也是函数,参数函数的参数个数
function fn(func){
console.log(fn.length)
}
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);
日志工具函数
log 日志工具函数
- * date: 日期时间 14:45 -> new Date()
- * importance: 日志级别 DEBUG(调试日志) INFO(普通日志) WARN(警告日志) ERROR(错误日志)
- * message: 日志信息
- * [14:45]-[INFO] 日志工具函数封装
function log(date, importance, message) { console.log(`[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}]- [${importance}] :${message}`)} // log(new Date(),'DEBUG','日志工具函数封装') // log(new Date(),'ERROR','这是错误信息 typeErrry 类型错误') let curryLog = currying(log) // curryLog(new Date())('INFO')('柯里化函数') // 柯里化日期 let curryDateLog = curryLog(new Date()) curryDateLog('INFO','柯里化日期') // 柯里化日志级别 let curryDebugLog = curryDateLog('DEBUG') curryDebugLog('柯里化日志级别1') curryDebugLog('柯里化日志级别2') function currying(func) { return function curried(...args) { if (args.length >= func.length) { return func.apply(this,args) //sum(10,20,30) } else { return function (...arg2) { let arg = [...args, ...arg2] return curried.apply(this, arg) } } } }
继承
面向对象三大特性
1. 封装 对象属性和方法
2. 继承
3. 多态 一个事物有多种表现形态
- let num = 100 // number
- num = '100' // string
继承
子类继承父类,子类就拥有父的属性和方法
表示类与类之间的关系, 父类和子类关系
ES5 实现继承
1. 构造函数继承
在子类构造函数中调用父类构造函数
// 父类
function Parent() {
this.money = 100000
this.home = '房子'
this.playGame = function () {
console.log('玩游戏')
}
}
Parent.prototype.swiming = function(){
console.log('游泳');
}
// 子类
function Son() {
// 构造函数继承
Parent.call(this) //更改this指向
this.name = 'jack'
}
2. 拷贝继承-实现原型属性和方法继承
// 拷贝继承-实现原型属性和方法继承
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. 原型继承 - 改变原型指向实现 - 将父类实例复制子类原型对象
儿子.prototype = new 父亲()
// 父类
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. 组合继承
构造函数 + 拷贝继承
class 类继承 [ES6]
类与类之间的关系,子类继承父类
语法
// 父类
class Parent{
constructor(){
this.money = 10000
}
playGame(){
}
}
// 子类Son继承父类Parent
class Son extends Parent{
constructor(){
// 先要实例父类再有子类实例
super() // 调用父类构造器实例化父类 语法
this.name = 'jack'
}
}
let parent1 = new Parent()
let s1 = new Son()
事例
// 父类
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);