递归、递归的练习、数组的方法、可变参数、call和apply、bind——JS数组

28 篇文章 0 订阅
21 篇文章 2 订阅

目录

一、递归

二、递归的练习

三、数组的方法

四、可变参数

五、call 和 apply

六、bind

一、递归

递归

        - 调用自身的函数称为递归函数

        - 递归的作用和循环基本一致

递归的核心思想就是将一个大的问题拆分为一个一个小的问题,小的问题解决了,大的问题也就解决了

编写递归函数,一定要包含两个要件:

        1. 基线条件 —— 递归的终止条件

        2. 递归条件 ——如何对问题进行拆分

递归的作用和循环是一致的,不同点在于,递归的思路比较清晰简洁,但循环的执行性能比较好(因为在递归中,一直在调用自己,但每次调用函数都会产生函数作用域,会占内存同时也会耗费时间)

        在开发中,一般的问题都可以通过循环解决,也就是尽量使用循环,少用递归

        只在一些使用循环解决比较麻烦的场景下,才使用递归。

	<script>	
		// 创建一个函数,可以用来求任意数的阶乘
		// 如果用递归来解决阶乘问题
		function jieCheng(num){
			// 基线条件
			if(num === 1){
				return 1
			}
			// 递归条件
			return num * jieCheng(num-1)			
		}
		let result = jieCheng(5)
		/*
			jieCheng(5)
				-return 5 * jieCheng(4)
				 -return 4 * jieCheng(3)
				  -return 3 * jieCheng(2)
				   -return 2 * jieCheng(1)
				    -return 1
		*/
		console.log(result);
	</script>

二、递归的练习

一对兔子出生后的两个月后,每个月都能生一对小兔子

        编写一个函数,可以用来计算第 n 个月的兔子数量

月份   1        2        3        4        5        6        7         8          9        10        11

对数   1        1        2        3        5        8       13       21        34        55       ......

        - 规律: 当前数等于前两个数之和(斐波那契数列)

        也就是求斐波那契数列中的第 n 个数

	<script>	
		function fib(n){
			// 确定基线条件
			if(n === 1 || n === 2){
				return 2
			}
			// 设置递归条件
			// 第 n 个数 = 第 n-1个数 + 第 n-2个数
			return fib(n-1) + fib(n-2)
		}
		let result = fib(8)
		console.log(result);
	</script>

三、数组的方法

sort( )

        - sort 用来对数组进行排序(会改变原数组,即破坏性方法)

        - sort 默认会将数组升序排列

            注意:sort 默认会按照Unicode 编码进行排序,所以如果直接通过 sort 对数字进行排序     

                     可能会得到一个不正确的结果

        - 参数:

                - 可以传递一个回调函数作为参数,通过回调函数来指定排序规则

                   (a , b)=> a - b 升序排列

                   (a , b)=> b - a 降序排列

	<script>	
		let arr = ['a','c','e','f','d','b']
		console.log(arr);//打印['a', 'c', 'e', 'f', 'd', 'b']
		arr.sort()
		console.log(arr);//打印['a', 'b', 'c', 'd', 'e', 'f']
		arr = [2,4,6,3,1,8,9,0,10]
		arr.sort()
		console.log(arr);//[0, 1, 10, 2, 3, 4, 6, 8, 9]
		arr.sort((a,b)=> a - b)
		console.log(arr);//升序排列[0, 1, 2, 3, 4, 6, 8, 9, 10]
		arr.sort((a,b)=> b - a)
		console.log(arr);//降序排列, [10, 9, 8, 6, 4, 3, 2, 1, 0]
	</script>

forEach( )、filter( )、map( )均需要回调函数,且回调函数中都有三个参数。

forEach( )

        - 用来遍历数组

        - 它需要一个回调函数作为参数,这个回调函数会被调用多次

                数组中有几个元素,回调函数就会调用几次

                每次调用,都会将数组中的元素作为参数

        - 回调函数中有三个参数:

                element 当前的元素,第一个参数

                index 当前元素的索引,第二个参数

                array 被遍历的数组,第三个参数

        - 非破坏性方法,不影响原数组

	<script>	
		let arr = ['孙悟空','猪八戒','沙和尚']
		arr.forEach((element,index,array)=>{
			console.log(element,index,array);
		})
		arr.forEach((element)=>{//只需要元素
			console.log(element);
		})		
	</script>

filter( )

        - 将数组中符合条件的元素保存到一个新数组中(非破坏性方法)

        - 需要一个回调函数作为参数,会为每一个元素去调用回调函数,并根据返回值来决定是否将元素添加到新数组中,返回值为真则添加,否则不添加;注意回调函数中与 forEach( ) 一样也有三个参数

        - 非破坏性方法,不会影响原数组

	<script>	
		let arr = [1,2,3,4,5,6,7,8]
		// 获取数组中的所有偶数
		let result = arr.filter((ele)=>
			// ele > 5
			ele % 2 === 0	
		)
		console.log(result);//[2, 4, 6, 8]
		result = arr.filter((ele)=>{
			return ele > 4
		})
		console.log(result);// [5, 6, 7, 8]
	</script>

map( )

        - 根据当前数组生成一个新数组(非破坏性方法)

        - 需要一个回调函数作为参数,

                回调函数的返回值会成为新数组中的元素

        关键是根据数组的值生成一个新数组

        - 非破坏性方法,不会影响原数组

	<script>	
		let arr = [1,2,3,4,5,6,7,8]
		let result = arr.map((ele)=>123)
		console.log(result);//(8)[123, 123, 123, 123, 123, 123, 123, 123]
		result = arr.map(ele => ele * 2)
		console.log(result);//(8) [2, 4, 6, 8, 10, 12, 14, 16]
		// 想为如下数组加上标签
		arr = ['孙悟空','猪八戒','沙和尚']
		result = arr.map(ele => '<li>' + ele + '</li>')
		console.log(result);//(3) ['<li>孙悟空</li>', '<li>猪八戒</li>', '<li>沙和尚</li>']
	</script>

reduce( )

        - 可以用来将一个数组中的所有元素整合为一个值

        - 也需要使用回调函数作为参数

        -参数:

                1.回调函数,通过回调函数来指定合并的规则,回调函数有两个参数,分别表示第一个值或者返回值,第二个参数表示数组后面的值

                2.可选参数,初始值,在返回值处

        -依次执行”回调函数,并传入前一个元素上的计算返回值。第一次运行回调函数时,没有“前一次计算的返回值”。如果提供,则可以使用初值代替其位置。否则,索引为0的数组元素被用作初始值,迭代从下一个元素开始(索引1而不是索引0)

	<script>	
		let arr = [1,2,3,4,5,6,7,8]
		let result = arr.reduce((a,b)=>{
			/*
				a,b
				1,2
				3,3
				6,4
				10,5
				以此类推
			*/
			console.log(a,b);
			return a + b
		})
		console.log(result);//36
		result = arr.reduce((a,b)=> a+b,10)//10为初始值
        //10 + 1 + 2+ 3+ 4+ 5+ 6+ 7+ 8
		console.log(result);//46
	</script>

四、可变参数

arguments

        -arguments 是函数中又一个隐含参数(另一个隐含参数是this)

        - arguments 是一个类数组对象(伪数组)

                和数组相似,可以使用 .length 得到实参的数量,可以通过索引来读取元素,也可以通过for循环遍历,但它不是一个数组对象,不能调用数组的方法

        - arguments 用来存储函数的实参

                无论用户是否定义形参,实参都会存储到arguments对象中

                可以通过该对象直接访问实参

	<script>	
		function fn(){			
			// console.log(arguments.length);
			// console.log(arguments[0]);
			console.log(Array.isArray(arguments));//false
			for(let i=0;i<arguments.length;i++){//for循环遍历
				console.log(arguments[i]);
			}
			for(let v of arguments){//for- of遍历
				console.log(v);
			}
		}
		fn(10,2,3)
	</script>

如当我们想定义一个函数,求任意个数值的和时,可以通过使用arguments,不受参数数量的限制更加灵活的创建函数。

	<script>	
		//定义一个函数,可以求任意个数值的和
		function sum(){
			let result = 0
			// 通过arguments,可以不受参数数量的限制更加灵活的创建函数
			for(let num of arguments){
				result += num
			}
			return result
		}
		let result = sum(1,3,5)
		console.log(result);//9
	</script>

arguments 缺点:

        1. 有些函数不是我们定义的,以为其是不需要参数的,直接调就行,但其实需要我们传入实参,也就是不知道需不需要传实参

        2. arguments不是一个数组,不能使用数组的方法,如想为实参做一个累加,不能使用reduce( ) 方法,必须遍历

可变参数,在定义函数时可以将参数指定为可变参数。

        - 可变参数使用 ...参数名 定义

        - 可变参数可以接收任意数量的实参,并将它们统一存储到一个数组中返回

        - 可变参数的作用和arguments 基本一致,但是也有一些不同点:

                1.可变参数的名字可以自己指定

                2. 可变参数就是一个数组,可以直接使用数组的方法

                3. 可变参数可以配合其他参数一起使用

                      注意:当可变参数和普通参数一起使用时,需要将可变参数写到最后

	<script>	
		// 可变参数
		function fn(...args){
			console.log(args);
		}
		fn()//[]
		fn(1)//[1]
		fn('hello',123,true)//(3) ['hello', 123, true]
		// 可变参数可以直接使用数组的方法
		function sum(...num){
			return num.reduce((a,b)=> a + b, 0)//直接使用数组方法reduce( )
		}
		let result = sum(2,5,7)
		console.log(result);//14
		// 可变参数可以配合其他参数一起使用
		// 当可变参数和普通参数一起使用时,需要将可变参数写到最后
		function fn2(a,b,...args){
			console.log(args);
		}
		fn2(12,67,'fff','hello')//(2) ['fff', 'hello']
	</script>

五、call 和 apply

根据函数调用方式的不同,this 的值也不同

        1. 以函数形式调用,this 是window

        2. 以方法形式调用,this 是调用方法的对象

        3. 构造函数中,this 是新建的对象

        4. 箭头函数没有自己的this, 由外层作用域决定

        5. 通过call 和 apply 调用函数,它们的第一个参数就是函数的 this

调用函数除了通过 函数( )这种形式外,还可以通过其他的方式来调用函数

        比如,我们可以通过调用函数的call( ) 和 apply( ) 两个方法来调用函数

                函数.call( )

                函数.apply( ) 

                - call 和 apply 除了可以调用函数外,还可以用来指定函数中的 this

                     - call 和 apply 的第一个参数,将会成为函数的 this

	<script>	
		function fn(){''
			console.log('函数执行了~',this);
		}
		fn()//以函数形式调用,this 是window
		const obj = {
			name:'孙悟空',
			fn //把fn 函数设置为obj的属性
		}
		obj.fn()//函数执行了~ {name: '孙悟空', fn: ƒ},因为以方法调用,this 是调用方法的对象
		fn.call()//函数执行了~ Window,this 为window
		fn.call(obj)//函数执行了~ {name: '孙悟空', fn: ƒ},this为对象
		fn.call(console)//函数执行了~ console,this为console
		// fn.apply()
	</script>

        call 和 apply 的区别

                - 通过call 方法调用函数,函数的实参直接在第一个参数后一个一个的列出来                                   - 通过apply 方法调用函数,函数的实参需要通过一个数组传递

	<script>	
		function fn(){''
			console.log('函数执行了~',this);
		}
		const obj = {
			name:'孙悟空',
			fn //把fn 函数设置为obj的属性
		}
		function fn2(a,b){
			console.log('a =', a,'b = ', b, this);
		}
		fn2(12,3)//a = 12 b =  3 Window
        //call调用函数时,实参在第一个参数后一个一个列举出来
		fn2.call(obj,1,2)//a = 1 b =  2 {name: '孙悟空', fn: ƒ}
        //apply调用函数时,实参通过一个数组传递
		fn2.apply(obj,['hello',true])//a = hello b =  true {name: '孙悟空', fn: ƒ}
	</script>

六、bind

bind( ) 是函数的方法,可以用来创建一个新的函数

        - bind可以为新函数绑定 this,绑定就是无论用什么方式调用,都始终是这个this

        - bind 可以为新函数绑定参数

        - bind第一个参数为this,之后为相应的实参

bind为新函数绑定this的例子

	<script>		
		function fn(){
			console.log('fn执行了~~~',this);
		}
		// fn.call()
		const obj = {name:'孙悟空'}
		//bind为新函数绑定this 
		const newFn = fn.bind(obj)
		newFn()//fn执行了~~~ {name: '孙悟空'},this是obj
		newFn.call({})//fn执行了~~~ {name: '孙悟空'},this仍然还是obj
	</script>

bind 为新函数绑定参数的例子:

	<script>		
		function fn(a,b,c){
			console.log('fn执行了~~~',this);
			console.log(a,b,c);
		}
		const obj = {name:'孙悟空'}
		const newFn = fn.bind(obj,1,2,3)
		newFn()//fn执行了~~~ {name: '孙悟空'} 1 2 3
		newFn.call(345,2,3)//fn执行了~~~ {name: '孙悟空'} 1 2 3,this和实参已经绑定了
	</script>

根据函数调用方式的不同,this 的值也不同

        1. 以函数形式调用,this 是window

        2. 以方法形式调用,this 是调用方法的对象

        3. 构造函数中,this 是新建的对象

        4. 箭头函数没有自己的this, 由外层作用域决定

        5. 通过call 和 apply 调用函数,它们的第一个参数就是函数的 this

        6. 通过bind 返回的函数,this 由 bind第一个参数决定(无法修改),与其调用方式无关

箭头函数没有自身的this,它的this由外层作用域决定,

        也无法通过call apply 和 bind 修改它的 this

	<script>		
		function fn(a,b,c){
			console.log('fn执行了~~~',this);
			console.log(a,b,c);
		}
		const obj = {name:'孙悟空'}
		const newFn = fn.bind(obj,1,2,3)
		const arrowFn = ()=>{
			console.log(this);
		}
		arrowFn()//Window,箭头函数的this由外层作用域决定
		arrowFn.apply(obj)//Window,箭头函数的this由外层作用域决定,无法通过apply修改
		const newArrowFn = arrowFn.bind(obj)
		newArrowFn()//Window,箭头函数的this由外层作用域决定,无法通过bind修改

		class MyClass{
			fn = ()=>{
				console.log(this);
			}
		}
		const mc = new MyClass()
		mc.fn()//this是MyClass {fn: ƒ},箭头函数的this由外层作用域决定
	</script>

        箭头函数中没有arguments

	<script>		
		const arrowFn = ()=>{
			console.log(arguments);
		}
		arrowFn()//报错,Uncaught ReferenceError: arguments is not defined
                 // at arrowFn 		
	</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值