⭐️ 有关JavaScript的学习总结



JavaScript

> JavaScript 是一种广泛应用于网页开发的脚本语言,它为网页添加了动态交互和丰富的功能。

> JavaScript 用于在网页中添加交互性和动态功能。它可以控制网页的行为,处理用户输入,并与服务器进行通信,以实现各种功能。

> JavaScript 的语法类似于其他编程语言,它是一种动态类型语言,允许变量在运行时更改类型。JavaScript 中的语句以分号结尾,而代码块使用大括号来定义。

> JavaScript、HTML和CSS一起构成了现代网页的核心。HTML 负责结构,CSS 负责样式,JavaScript 则负责交互和动态功能。


流程控制

>流程控制语句可以用来改变程序执行的顺序

  • 条件判断语句

  • 条件分支语句

  • 循环语句

>代码块

使用 {} 来创建代码块,代码块可以用来对代码进行分组。

	- 同一个代码中的代码,要么都执行要么都不执行

let 和 var

 	- 在JS中,使用let声明的变量具有块作用域
	在代码块中声明的变量无法在代码块的外部访问

	{
		let a = 10
		console.log(a)
    }

  	- 使用var声明的变量,不具有块作用域

	{
        var a = 10
    }
		console.log(a)

>if 语句

条件判断语句 -->if语句

	- 语法:
    if(条件表达式){
       语句...
    }

  	if(false){
   		alert('哈哈哈')
	}
                    
    - 执行流程
    if语句在执行会先对if后的条件表达式进行求值判断,
    如果结果为true,则执行if后的语句
    如果为false则不执行

	let a = 20
	if(a > 10){
		alert('a比10大')
	}
	

    if语句只会控制紧随其后其后的那一行代码,如果希望可以控制多行代码,可以使用{}将语句扩起来
    最佳实践:即使if后只有1行代码,我们也应该编写代码块,这样结构会更加的清晰

	// if(100){
   	//     alert('你猜我执行吗?')
   	// }

    如果if后的添加表达式不是布尔值,会转换为布尔值然后再运算

     if(a == 10){
         alert('a的值是10!')
     }

>if-else

条件分支语句 -->if-else语句

	- 语法:
    if(条件表达式){
       语句...
    }else{
       语句...
    }

    - 执行流程
	if-else执行时,先对条件表达式进行求值判断,
    如果结果为true 则执行if后的语句
    如果结果为false 则执行else后的语句


	let age = 10

	if(age >= 60){
		alert('你已经退休了!')
	}else{
		alert('你还没有退休!')
	}
条件分支语句 -->if-else if-else语句:

    - 语法:
    if(条件表达式){
       语句...
    }else if(条件表达式){
       语句...
    }else if(条件表达式){
       语句...
    }else if(条件表达式){
       语句...
    }else{
       语句...
    }

 	- 执行流程:
    if-else if-else语句,会自上向下依次对if后的条件表达式进行求值判断,
    如果条件表达式结果为true,则执行当前if后的语句,执行完毕语句结束
    如果条件表达式结果为false,则继续向下判断,直到找到true为止
    如果所有的条件表达式都是false,则执行else后的语句

    let age = 102

    if(age >= 100){
		alert('你真是一个长寿的人!')
    }else if(age >= 80){
        alert('你比楼上那位还年轻不小!')
    }else if(age >= 60 ){
        alert('你已经退休了!')
    }else if(age >= 30){
        alert('你已经步入中年了!')
    }else if(age >= 18){
        alert('你已经成年了!')
    }else{
        alert('你还未成年!')
    }

	注意:
    if-else if-else语句中只会有一个代码块被执行,
    一旦有执行的代码块,下边的条件都不会在继续判断,所以一定要注意,条件的编写顺序。

	age = 68

    if(age >= 18){
		alert('你已经步入中年了!')
    }else if(age >= 30){
        alert('你已经步入中年了!')
    }else if(age >= 60 ){
        alert('你已经退休了!')
    }


	if(age >= 18 && age < 30){
		alert('你已经成年了!')
	}else if(age >= 30 && age < 60){
		alert('你已经步入中年了!')
	}else if(age >= 60){
		alert('你已经退休了!')
	}

>> if 语句小练习:「立即前往

>switch语句

witch语句

	- 语法:
		switch(表达式){
         case 表达式/值:
              代码...
        	  break
         case 表达式/值:
              代码...
              break
         case 表达式/值:
              代码...
              break
         case 表达式/值:
              代码...
         	  break
         default:
              代码...
              break
         }

	- 执行的流程
	switch语句在执行时,会依次将switch后的表达式和case后的表达式进行全等比较
	如果比较结果为true,则自当前case处开始执行代码
	如果比较结果为false,则继续比较其他case后的表达式,直到找到true为止
	如果所有的比较都是false,则执行default后的语句

	let num = +prompt(`请输入一个数字`)

	switch(num) {
		case 1;
			alert(`壹`)
			break
		case 2;
			alert(`貮`)
			break
		case 3;
			alert(`叁`)
			break
		default:
			alert(`我是default`)
			break
	}	

	- 注意:
	当比较结果为true时,会从当前case处开始执行代码,也就是case是代码执行的起始位置
	这就意味着只要是当前case后的代码,都会执行
	可以使用break来避免执行其他的case

 	- 总结
	switch语句和if语句的功能是重复,switch能做的事if也能做,反之亦然
	它们最大的不同在于,switch在多个全等判断时,结构比较清晰

>循环语句

通过循环语句可以使指定的代码反复执行

>while语句
while语句

	- 语法:
    while(条件表达式){
        语句...
    }

	- 执行流程:
    while语句在执行时,会先对条件表达式进行判断,
    如果结果为true,则执行循环体,执行完毕,继续判断
    如果为true,则再次执行循环体,执行完毕,继续判断,如此重复
    直到条件表达式结果为false时,循环结束	

	//当一个循环的表达式的恒为true时,这个循环就是一个死循环,会一直执行(慎用)
    // while(true){
    //     alert('哈哈')
    // }

	通常编写一个循环,有三个要件:
	1.初始化表达式(初始化变量)
	// let a = 0
	2.条件表达式(设置循环运行的条件)
	// while(a < 3){
	// console.log(a)
	3.更新表达式(修改初始化变量)
	// a++
	// }

	let i = 0

	while(1){
		console.log(i)
		i++
		if(i >= 5){
		break
		}
	}

>> while语句小练习:「立即前往

>do-while语句
do-while语句

	- 语法:
	 do{
	   语句...
	 }while(条件表达式)

	- 执行顺序:
	do-while语句在执行时,会先执行do后的循环体,
	执行完毕后,会对while后的条件表达式进行判断
	如果为false,则循环终止
	如果为true,则继续执行循环体,以此类推

	let i = 0

	do{
		console.log(i)
		i++
	}while(i < 5)

	和while的区别:
	while语句是先判断再执行
	do-while语句是先执行再判断

	/* 
	while(i < 5){
		console.log(i)
		i++
	}while(i < 5)
	*/

	实质的区别:
	do-while语句可以确保循环至少执行一次
>for语句
- for循环和while没有本质区别,都是用来反复执行代码
- 不同点就是语法结构,for循环更加清晰
for语句

	- 语法
	for(①初始化表达式; ②条件表达式; ④更新表达式){
     	③语句...
     }

	- 执行流程:
	    ① 执行初始化表达式,初始化变量
        ② 执行条件表达式,判断循环是否执行(true执行,false终止)
        ③ 判断结果为true,则执行循环体
        ④ 执行更新表达式,对初始化变量进行修改
        ⑤ 重复②,知道判断为false为止

	for(let i = 0; i < 5; i++){
		console.log(i)
	}

	- 初始化表达式,在循环的整个的生命周期中只会执行1次
	- for循环中的三个表达式都可以省略
	- 使用let在for循环的()中声明的变量是局部变量,只能在for循环内部访问
	  使用var在for循环的()中声明的变量可以在for循环的外部访问

	- 创建死循环的方式:
	// while(1){}
    // for(;;){}

>> for语句小练习:「立即前往

>嵌套循环

嵌套循环

	- 在循环中也可以嵌套其他的循环,
	- 例如希望在网页中打印出如下图形:
		*****
		*****
		*****
		*****
		*****

  	//当循环发生嵌套时,外层循环每执行一次,内层循环就会执行一个完整的周期

	// 这个for循环,可以用来控制图形的高度
	for (let i = 0; i < 5; i++) {
		// 创建一个内层循环来控制图形的宽度
   		for (let j = 0; j < 5; j++) {
        document.write("*&nbsp;&nbsp;")
    	}
    	document.write("<br>")
	}

	- 例如希望在网页中打印出如下图形:
		*		j<1		i=0
		**		j<2		i=1	
		***		j<3		i=2
		****	j<4		i=3
		*****	j<5		i=4

	for (let i = 0; i < 5; i++) {
   		for (let j = 0; j < i + 1; j++) {
        document.write("*&nbsp;&nbsp;")
    	}
    	document.write("<br>")
	}

>> 嵌套循环小练习:「立即前往

>break和continue

- break
	- break用来终止switch和循环语句
    - break执行后,当前的switch或循环会立刻停止
    - break会终止离他最近的循环

- continue
     - continue用来跳过当次循环
	
	// for (let i = 0; i < 5; i++) {
	//     if (i === 3) {
	//         continue
	//     }
	//     console.log(i)
	// }
	
	// for (let i = 0; i < 5; i++) {
	//     console.log(i)
	
	//     for(let j=0; j<5; j++){
	//         if(j === 1) break
	//         console.log('内层循环--->', j)
	//     }
	// }
	
	// for (let i = 0; i < 5; i++) {
	//     if(i === 3){
	//         break
	//     }
	//     console.log(i)
	// }

 	for (let i = 0; i < 5; i++) {
    	console.log(i)

    for (let j = 0; j < 5; j++) {
    	if (j === 1) continue
        console.log("内层循环--->", j)
	    }
	}

>> 优化代码小练习:「立即前往


对象

  • 对象是JS中的一种复合数据类型, 它相当于一个容器,在对象中可以存储各种不同类型数据。

  • 原始值只能用来表示一些简单的数据,不能表示复杂数据;比如:现在需要在程序中表示一个人的信息。

	// 创建对象
	let obj = Object()

	/*
   	let name = "孙悟空"
    let age = 18
    let gender = "男"
	*/

    // 对象中可以存储多个各种类型的数据
    // 对象中存储的数据,我们称为属性
    
    向对象中添加属性:
       - 对象.属性名 = 属性

	obj.name = "孙悟空"
	obj.age = 18
	obj.gender = "男"

    读取对象中的属性
       - 对象.属性名
       - 如果读取的是一个对象中没有的属性,不会报错而是返回undefined

	// 修改属性
	obj.name = "Tom sun"
	// 删除属性
	delete obj.nam
	console.log(obj.name)

>对象的属性

	let obj = Object()

    
    属性名
    	- 通常属性名就是一个字符串,所以属性名可以是任何值,没有什么特殊要求
          但是如果你的属性名太特殊了,不能直接使用,需要使用[]来设置
          虽然如此,但是我们还是强烈建议属性名也按照标识符的规范命名

    	obj.name = "孙悟空"

    	// obj.if = "哈哈" // 不建议
    	// obj.let = "嘻嘻"// 不建议
    	// obj["1231312@#@!#!#!"] = "呵呵"// 不建议

        - 也可以使用符号(symbol)作为属性名,来添加属性
          获取这种属性时,也必须使用symbol
          使用symbol添加的属性,通常是那些不希望被外界访问的属性

   		 let mySymbol = Symbol()
    	 let newSymbol = Symbol()

    	- 使用symbol作为属性名

		- 使用[]去操作属性时,可以使用变量

    	obj[mySymbol] = "通过symbol添加的属性"

   		// console.log(obj[mySymbol])

        


    属性值
         - 对象的属性值可以是任意的数据类型,也可以是一个对象
		   使用typeof检查一个对象时,会返回object
    

        obj.age = 18
        obj["gender"] = "男"

        let str = "address"

        obj[str] = "花果山" // 等价于 obj["address"] = "花果山"

        obj.str = "哈哈" // 使用.的形式添加属性时,不能使用变量

        obj.a = 123
        obj.b = 'hello'
        obj.c = true
        obj.d = 123n
        obj.f = Object()
        obj.f.name = "猪八戒"
        obj.f.age = 28

        // console.log(obj.f.name)
        

        // console.log(obj.gender)
        // console.log(obj["gender"])
        
        // console.log(typeof obj)

      
     in 运算符
        - 用来检查对象中是否含有某个属性
        - 语法 属性名 in obj
        - 如果有返回true,没有返回false
        
        console.log("name" in obj)

>对象字面量

对象字面量
	- 可以直接使用{} 来创建对象

    - 使用{}所创建的对象,可以直接向对象中添加属性

    - 语法:
         {
          	属性名:属性值,
            [属性名]:属性值,
         }
   
    let mySymbol = Symbol()

    let obj2 = {
        name:"孙悟空", 
        age:18,
        ["gender"]:"男",
        [mySymbol]:"特殊的属性",
        hello:{
            a:1,
            b:true
        }
    }

    console.log(obj)
    console.log(obj2)

>枚举属性

枚举属性
	- 将对象中的所有的属性全部获取

for-in语句

	- 语法:
		for(let propName in 对象){
			 语句
		}

	- for-in的循环体会执行多次,有几个属性就会执行几次,
	  每次执行时,都会将一个属性名赋值给我们所定义的变量

	- 注意:并不是所有的属性都可以枚举,比如 使用符号添加的属性


	

	let obj = {
		name:`孙悟空`
		age:`18`
		gender:`男`
		address:`花果山`
  		[Symbol()]:"测试的属性" // 符号添加的属性是不能枚举
	}
	
	for(let propName in obj){
		console.log(propName,obj[propName])
	}

>可变类型

	- 原始值都属于不可变类型,一旦创建就无法修改
	- 在内存中不会创建重复的原始值

	let a = 10 
	let b = 10
		a = 12 // 当我们为一个变量重新赋值时,绝对不会影响其他变量

	- 对象属于可变类型
	- 对象创建完成后,可以任意的添加删除修改对象中的属性
	let obj = Object()
	obj.name = "孙悟空"
	obj.age = 18


	- 注意:
	    - 当对两个对象进行相等或全等比较时,比较的是对象的内存地址	

	let obj2 = Object()
   	let obj3 = Object()
	// console.log(obj2 == obj3) // false

	    - 如果有两个变量同时指向一个对象,通过一个变量修改对象时,对另外一个变量也会产生影响

	let obj4 = obj
	obj4.name = "猪八戒" // 当修改一个对象时,所有指向该对象的变量都会收到影响

>改变量&改对象

修改对象
	- 修改对象时,如果有其他变量指向该对象,则所有指向该对象的变量都会受到影响

	let obj = {
		name:"孙悟空" 
	}
	
	let obj2 = obj 
	obj2.name = "猪八戒" // 修改对象

修改变量
	- 修改变量时,只会影响当前的变量

	obj2 = null // 修改变量

	// console.log(obj)
    // console.log(obj2)

	在使用变量存储对象时,很容易因为改变变量指向的对象,提高代码的复杂度
	- 所以通常情况下,声明存储对象的变量时会使用const

	const obj = {
		name:"孙悟空" 

	注意:
   	 - const只是禁止变量被重新赋值,对对象的修改没有任何影响

	const obj3 = {
          name:"猪八戒"
    }

    obj3.name = "沙和尚"

    console.log(obj3)	

>方法(method)

- 补充内容 方法(method) - 基于函数 =>作用域链后

	- 当一个对象的属性指向一个函数,
		- 那么我们称这个函数是该对象的方法
		- 调用函数称为调用对象的方法
	
	let obj = {}
	
	obj.name = "孙悟空"
	obj.age = 18

	// 函数也可以成为一个对象的属性
	obj.sayHello = function(){  // obj 的 sayhello 方法
		alert("hello")
	}
	
	console.log(obj) // 调用对象内容
	
	obj.sayHello() //调用obj的sayhello方法
	
	String() //函数

函数

函数(Function)

	- 函数也是一个对象
    - 它具有其他对象所有的功能
    - 函数中可以存储代码,且可以在需要时调用这些代码

语法:
	function 函数名(){
        	 语句...
    }

	function QQ(){
		console.log("你好!")
        console.log("Hello!")
	}

调用函数:
    - 调用函数就是执行函数中存储的代码
    - 语法:
         函数对象() // QQ()


    - 使用typeof检查函数对象时会返回function

	console.log(typeof QQ)

>函数的创建

函数声明
	    function 函数名(){
	        语句...
	    }
		

		function qq(){
		    console.log("函数声明所定义的函数~")
		}	
函数表达式
	    const 变量 = function(){
	        语句...
	    }
		
		
		const qq2 = function(){
		    console.log("函数表达式")
		}	
箭头函数
        () => {
            语句...
        }
		
		const qq3 = () => {
		    console.log("箭头函数")
		}
		
		const qq4 = () => console.log("箭头函数")	

>函数的参数

定义一个可以求任意两个数和的函数

	function sum(){
		let a = 1
		let b = 1
		console.log(a + b)
	}

	function sum(a,b){
		console.log(a + b)
	}

	sum(123,456)
形式参数
	- 在定义函数时,可以在函数中指定数量不等的形式参数(形参)

	  function 函数名([参数]){
	       语句...
	  }

	  const 变量 = function([参数]){
	        语句...
	  }

	  ([参数]) => {
            语句...
      }

	- 在函数中定义形参,就相当于在函数内部中声明了对应的变量,但是没有赋值

实际参数
	- 在动用函数时,可以在函数的()传递数量不等的实参

	function fn(a,b){
		console.log("a = ",a)
		console.log("b = ",b)
	}

	- 实参会赋值给其相对应的形参

	fn(1.10)

	注意:
		- 1、如果实参和形参数量相同,则对应的实参赋值给对应的形参
		- 2、如果实参多余形参,则多余的实参不会使用
		- 3、如果形参多余实参,则多余的形参为undefined

参数的类型

	- JS中不会检查参数的类型,可以传递任何类型的值作为参数

	fn({}."hello") 
	sum("hello","world")

>箭头函数的参数

	const fn = (a,b) => {
		console.log("a = ",a);
		console.log("b = ",b);
	}
	fn(123, 456)

	//当箭头函数中只有一个参数时,可以省略()
	const fn2 = a => {
		console.log("a = ",a);
	}
	fn2(123)

	//定义参数时,可以为参数指定默认值
	//默认值会在没有对应实参时生效
	const fn3 = (a=10,b=20,c=30) => {
		console.log("a = ",a);
		console.log("b = ",b);	
		console.log("c = ",c);	
	}
	fn3(1,2,3 )

>对象作为参数

	function fn(a){
	// console.log("a = ",a);	
		a = {} // 修改变量时,只会影响当前的变量
		a.name = "猪八戒" // 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响
		console.log(a)
	}

	//对象可以做为参数传递
	let obj = [name:"孙悟空"]

	//传递实参时,传递并不是变量本身,而是变量中的存储值
	// fn(obj)
	
	let obj2 = {name:"沙和尚"}

	// 函数每次调用,都会重新创建默认值

	function fn2(a = {name:"沙和尚"}){
    	console.log("a =", a)
    	a.name = "唐僧"
    	console.log("a =", a)
	}

	fn2() // 沙和尚 唐僧

>函数作为参数

	function fn(a){
    	console.log("a =", a)
   		 // a()
	}

	- 在JS中,函数也是一个对象(一等函数),别的对象能做的事情,函数也可以

	let obj = {name:"孙悟空"}

	function fn2(){
    	console.log("我是fn2")
	}

	// fn(fn2)

	// fn(function(){
	//     console.log("我是匿名函数~")
	// }

	fn(()=>console.log("我是箭头函数"))

>函数的返回值


	function sum(a, b) {
   		 // console.log(a + b)
   		 // 计算完成后,将计算的结果返回而不是直接打印
  	  return a + b
	}



    在函数中,可以通过return关键字来指定函数的返回值
    	 - 返回值就是函数的执行结果,函数调用完毕返回值便会作为结果返回
    
    任何值都可以作为返回值使用(包括对象和函数之类)

    // return {name:"孙悟空"}
    // return ()=>alert(123)

    	 - 如果return后不跟任何值,则相当于返回undefined

    	// return

	 	 - 如果不写return,那么函数的返回值依然是undefin

	return一执行函数立即结束

	function fn() {
   		alert(123)
    	return
    	alert(456)
	}

	let result = fn()

	 // result = sum(123, 456)
     // result = sum(10, result)

	console.log("result =", result)

>箭头函数的返回值

第一种写法:		
	const sum(a,b){
		result a + b
	}

第二种写法:
	- 箭头函数的返回值可以直接写在箭头后

	const sum(a,b)=> a + b // 此方法适用于一个语句

	-  如果直接在箭头后设置对象字面量为返回值时,对象字面量必须使用()括起来

	const fn = () =>({name:"孙悟空"})	

	let result = sum(123,456)

	result = fn()

	console.log(result)

>作用域

作用域(scope)
	- 作用域指的是一个变量的可见区域
	
	let a = "变量a"

	{
		let b = "变量b"
	}

	console.log(b) // 只能访问变量a,b则不行

- 作用域有两种:

	- 全局作用域
		- 全局作用域在网页运行时创建,在网页关闭时销毁
		- 所有直接编写到script标签中的代码都位于全局作用域中

		function fn() {
			let b = 10 // 非全局变量
		}

		- 全局作用域中的变量是全局变量,可以在任意位置访问 
		let a = "变量a"
		function fn() {
			let b = 10 // 非全局变量
		}

	- 局部作用域

		- 块作用域
			- 块作用域是一种局部作用域
			- 块作用域在代码执行时创建,代码块执行完毕它就销毁
			- 在块作用域中声明的变量是局部变量,只能在块内部访问,外部无法访问

         let a = "变量a" // a是全局变量

         {
            let b = "变量b"

            {
                {
                    console.log(b)
                }
            }
         }

         {
            console.log(b)
         }

		- 函数作用域
			- 函数作用域也是一种局部作用域
			- 函数作用域在函数调用时产生,调用结束后销毁
			- 函数每次调用,都会产生一个全新的函数作用域

		function fn(){
			let a = "fn中的变量a"
		}
		
		fn() //第一次调用
		fn() //第二次调用
		fn() //第三次调用

			- 在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问
		
		function fn(){
			let a = "fn中的变量a"

			console.log(a) // 函数内部可访问
		}

		fn()
			console.log(a) // 不可访问

>作用域链

作用域链
	- 当我们使用一个变量时,JS 解释器会优先在当前作用域中寻找变量
		- 如果找到了,则直接使用
		- 如果没找到,则去上一层作用域中寻找。找到了则使用,反之以此类推。	
		  如果全局作用域都没找到,则报错 xxx is not defined

	let a = 10

	{
		let a = "第一代码块中的a"
		{
			let a = "第二代码中的a"
			console.log(a)
		}
	}
	let b = 33

	function fn(){
		let b = 44
		
		function f1(){
			let b = 55
			console.log(b)
		}
	
		f1()
	}

	fn()

>window对象

window对象
	- 在浏览器中,浏览器为我们提供了一个window对象,可以直接访问

	alert(window)

	- window代表的是浏览器窗口,通过该对象可以对浏览器窗口进行操作
	  除此之外window对象还负责存储JS中的内置对象和浏览器的宿主对象

	String() //内置对象
	Number() //内置对象

	alert() //宿主对象

	- window对象的属性可以通过window对象访问,也可以直接访问

	window.alert(123)
	window.console.log("哈哈")
	window.a = 10 // 向window对象中添加的属性会自动成为全局变量
	
	- 函数可以认为是window对象的方法

	- var 用来声明变量,作用和let相同,但是var不具有块作用域
		- 在全局中使用var声明的变量,都会作为window对象的属性保存

			var b = 20 // window.b = 20

		- 使用function声明的函数,都会作为window的方法保存

			function fn(){
            	alert('我是fn')
        	}

			window.fn()

		- 使用let声明的变量不会存储在window对象中,而存在一个秘密的小地方(无法访问)

      	  let c = 33

          window.c = 44

		  console.log(c)

		- var虽然没有块作用域,但有函数作用域

        function fn2(){
            // var d = 10 // var虽然没有块作用域,但有函数作用域
            d = 10 // 在局部作用域中,如果没有使用var或let声明变量,
				   // 则变量会自动成为window对象的属性 也就是全局变量
        }

        fn2()
		console.log(d)

>提升

变量的提升
	- 使用var声明的变量,会在所有代码执行前被声明
		所以可以在变量声明前就访问变量

	// var.a 先声明 

	console.log(a) 

	var a = 10 
		a = 10 // window.a = 10

函数的提升
	- 使用函数声明创建的函数,会在其它代码执行前被创建
		所以可以在函数声明前调用函数

	fn()

	function fn(){
		alert(`我是fn函数~`)
	}

let声明的变量实际也会提升,但是在赋值之前解释器禁止对该变量的访问

>debugger

 debugger // 在代码中打了一个断点

 - 在控制台 F12 中 选择源代码 进行调试

>立即执行函数

在开发中应该尽量减少直接在全局作用域中编写代码!
	-所以,我们的代码尽量编写在局部作用域

	{
		let a = 10
	}

	- 如果使用let声明的变量,可以使用{}来创建作用域

	{
		let a = 20
	}

	/*
	function fn(){
		var a = 10
	}
	fn()
	function fn2(){
		var a = 2o
	}
	fn2()
	*/
	
	//我们希望创建一个只执行一次的匿名函数

立即执行函数(IIFE)

	- 立即执行是一个匿名的函数,并它只会调用一次
	- 可以利用IIFE来创建一个一次性的函数作用域,避免变量冲突的问题

	(function(){
		 let a = 10
		 console.log(111)
	 }()); // 注意分号分隔

	(function(){
		 let a = 10
		 console.log(111)
	 }())

>this函数

  • 函数在执行时,JS 解析器每次都会传递一个隐含的函数,这个参数叫做 this 。

  • this 会指向一个对象,所指对象会根据函数的调用方式的不同而不同。

以函数形式调用
	- 以函数调用时,this 指向的是 window

	function fn() {
		// console.log(this === window)
		console.log(”fn打印“,this)

以方法的形式调用
	- 以方法调用时,this 指向的是调用方法的对象
    - 以方法的形式调用时,this指向的是调用方法的对象
    ...

	const obj = {name:"孙悟空"}
	obj.test = fn

	const obj2 = {name:"猪八戒",text:fn}

    // fn()
    // window.fn()
    // obj.test() // {name:"孙悟空"}
    // obj2.test() // {name:"猪八戒", test:fn}
  
    - 通过this可以在方法中引用调用方法的对象

    const obj3 = {
        name: "沙和尚",
        sayHello: function () {
            console.log(this.name)
        },
     }
     const obj4 = { 
         name: "唐僧",
         sayHello: function(){
             console.log(this.name)
         },
     }
    // 为两个对象添加一个方法,可以打印自己的名字
     obj3.sayHello()
     obj4.sayHello()

>箭头函数

  • 箭头函数没有自己的this,它的this有外层作用域作用

  • 箭头函数的this和他的调用方式无关

箭头函数:
    ([参数]) => 返回值

- 举例:

    无参箭头函数:() => 返回值
    一个参数的:a => 返回值
    多个参数的:(a, b) => 返回值

    只有一个语句的函数:() => 返回值
    只返回一个对象的函数:() => ({...})
    有多行语句的函数:() => {
        ....    
        return 返回值
    }

    function fn() {
    console.log("fn -->", this)
    }

    const fn2 = () => {
    console.log("fn2 -->", this) // 总是window
    }

    // fn() // window
    // fn2() // window

    const obj = {
    name:"孙悟空",
    fn, // fn:fn
    fn2,
    sayHello(){
    console.log(this.name)

    // function t(){
    //     console.log("t -->", this)
    // }
    // t()

    const t2 = () => {
        console.log("t2 -->", this)
    }

    t2()
    }
    }

    // obj.fn() // obj
    // obj.fn2() // window

    obj.sayHello()

>严格模式

JS运行代码的模式有两种:

  - 正常模式
  ① 默认情况下代码都运行在正常模式中运行
  ② 在正常模式,语法检查并不严格,尽量不报错的地方尽量不报错
  ③ 这种处理方式导致代码的运行性能较差

  - 严格模式
  ① 在严格模式下,语法检查会变得严格
  ② 禁止了一些语法,更容易报错
  ③ 提升了性能表现

  - 在开发中尽量使用严格模式
    使隐藏的问题消灭在萌芽阶段,也能提升代码的运行性能。


 "use strict" // 全局的严格模式

 let a = 10

 // console.log(a)

 function fn(){
     "use strict" // 函数的严格的模式
 }