SOURCE

/**
 * 顺带一提运算符
 * + - * / 加减乘除
 * % 取余 (5 % 2 结果为 1)
 * 
 * = 赋值运算符,把右边的值给左边,这玩意儿可不是等于
 * 
 * 逻辑运算符(运用在条件判断时)
 * == 近似等 ("1" == 1 为true,虽然一个字符一个数值,但近似相等)
 * === 等于 (类型相同且值相同 "1" === 1 为false)
 * != 近似不等
 * !== 不等
 * > < >= <= 大于 小于 大于等于 小于等于
 * || 或者
 * && 且
 * ! 非
 * 
 * 位运算符 硬核且90%的程序不用,先不讲
 */

/**
 * 顺带一提条件语句
 * 都不需要解释,你肯定能看懂
 */
let a1 = 3
let a2 = 2
if(a1 > a2) {
    console.log("a1 > a2")
}else if(a1 < a2) {
    console.log("a1 < a2")
}else {
    console.log("a1 === a2")
}

/**
 * 一些常用的条件达成形式
 * a //a为真
 * !a //a为假
 * a || b //一个为真
 * a && b //a b都为真
 */
let a3 = 4
//a1 > a2 并且 a1 < a3
if((a1 > a2) && (a1 < a3)) {
    //code
}
//等价于 a1 >= a2
if(!(a1 < a2)) {
    //code
}

//三木(三目)运算符 condition ? code1 : code2
//条件condition达成时执行code1 否则执行code2

let ret = 0
if(a1 > a2) {
    ret = 1
}else {
    ret = 2
}

//用三木运算符简写
ret = a1 > a2 ? 1 : 2

/**
 * 好了开始正题!
 */


//之前说过,程序是为了偷懒,但之前的教学里只有使用循环的时候
//好像才有点偷懒的意思(循环结构里面的逻辑可以多次执行)
//现在介绍另一个可以偷懒的方式
//函数
//简单理解为一段代码有了简称,通过简称来调用这一整段代码而不需要每次都去写这么大一段代码

//函数定义
function add(a, b) {
    let sum = a + b
    return sum
}
//字面量function表示定义一个函数,这个函数的名称为add,这个函数有俩参数
//a 和 b, 花括号里面的内容为函数体,也就是函数执行的逻辑,这个花括号里面单独为一个作用域
//可以理解为这个函数自己的空间,在这里面声明的变量(参数也是变量)只能自己以及这个函数内部的函数
//才能访问
//return 后面的表示函数的返回值
//这个函数的意思就是计算a 和 b 的和 并返回

//调用
let num1 = 5
let num2 = 4
let num3 = add(num1, num2)
console.log(num3)  //打印9
/**
 * 很简单,数值变量num1为5,num2为4,我们传入函数add,那么函数的参数a为num1的值5,b为num2的值4
 * sum = 5 + 4 返回sum并复制给num3,所以num3就等于函数里面sum的值,所以为9
 */

/**
 * 函数的参数和返回值 名字不是必须的
 * 这也是一种常用的声明函数的方式
 * =右边使用函数字面量声明了一个没有名字的函数(匿名函数)
 * 然后将这个匿名函数赋值给了变量add2,这不代表这个函数的名字为add2,二是变量add2为一个函数类型的变量
 * 并且引用了这个匿名函数(通过add2调用这个匿名函数)
 * 而且这个函数其实啥也没干,但并不影响它是一个函数
 */
const add2 = function() {

}

add2() //调用它无事发生

/**
 * 函数嵌套
 * 一个js脚本是按书写顺序一行行执行的,遇到函数执行就会进入函数(即进入了这个函数的作用域,在函数
 * 内容也是一行行执行的,这个过程和之前并无区别,函数体的书写和脚本书写亦如此。所以你在函数里面
 * 也能定义函数,也能调用其他函数
 */

const logHello = function() {
    console.log("hello")
}

const fakeAdd = function(a, b) {
    logHello() //调用外部的函数 
    //定义内部函数 这个函数只有内部才能访问噢,这是函数作用域自己的变量
    const realAdd = function() {
        return a + b
    }
    return realAdd()
}

console.log(fakeAdd(1, 2))
console.log("================分割线======================")
/**
 * 闭包函数
 * 这是函数作用域的一种奇妙用法
 * 很多时候,为了安全,我们的函数或者接口(一种对外的功能,调用者提供规定的数据,接口返回其需要的数据
 * )只需提供返回数据的可读性,而函数内部的变量是不能够让外部访问的,这就需要用到闭包
 */

/**
 * 假如我们有一个函数需要实现计数的功能,每次执行这个函数计数+1,我们可能会这样实现
 */
let _count = 0
let counter = function() {
    _count++ //_count = _count + 1 的意思
    return _count
}

console.log(counter()) //1
console.log(counter()) //2
console.log(counter()) //3

/**
 * 好像没问题,但如果我不小心修改到了_count
 */
_count = 0
console.log(counter()) //1
/**
 * 是不是很不安全,因为协作编程时,外部的变量可能会被其他人不小心修改到
 */

/**
 * 奇妙
 */
/**
 * 定义了一个getCounter函数,声明了变量_count并赋值0,
 * 这个函数返回了一个匿名函数!
 * 
 */
const getCounter = function() {
    let _count = 0
    // 这个匿名函数的内容为_count++并返回_count的值
    //_count为外部函数的变量,所以外部函数的外部无法访问!
    return function() {
        _count++
        return _count
    }
}

//调用这个函数会返回内部函数,所以那个内部函数可以通过counter1调用了!
let counter1 = getCounter()
console.log("---------分割线-------------")
console.log(counter1()) //1
console.log(counter1()) //2
console.log(counter1()) //3

_count = 0 //这个_count并不是getCounter内部的那个_count噢
console.log(counter1()) //4
/**
 * 相当安全
 * 闭包可能有点绕,可以多想一想
 * 其实函数也是一种引用类型,通过函数变量加()来执行
 */

/**
 * 闭包虽然安全,但不能乱用,因为内部的变量无法再直接访问到(只能在函数执行时内部访问)
 * 所以无法自动回收这些变量所占的空间,所以闭包开辟的内存空间会一直存在整个程序生命周期
 * 滥用闭包会导致内存泄漏
 */

/**
 * 课堂作业
 * 基本:书写一个函数传入两个数值并返回大的那个数。
 * 进阶:利用闭包实现,如果你传入的两个数值和上次传入的一样就直接返回结果
 */

/**
 * 函数还有很多知识比如箭头函数,构造函数,对象方法等
 * 这些后面讲面向对象编程时再讲!
 * 面向对象编程真的是程序最有趣的地方,如果你准备好了
 * 微信大声告诉我《我准备好了》
 * 我将在下一期带你探索面向对象编程
 */
console 命令行工具 X clear

                    
>
console