重新巩固JS(四)——JavaScript函数

重新巩固JS系列,都是比较基础的东西,可以进行查漏补缺,很快看完,这是第四篇。
其他JS重新巩固系列

1. 函数概述

在编程领域中,子程序是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。不同语言中,子程序的叫法:
子程序叫法
在JS中,子程序成为函数(function)。如果函数挂载在一个对象上,就称它为对象的方法。例子:

// 两数求和函数
function sum(numA, numB) {
	return numA + numB;
}

// 对象的方法
const person = {
	//person对象的方法
	getName: function() {
		return this.name;
	}
}

JS中,函数也是对象,程序可以随意操控它们,比如赋值给变量、作为参数传递给其他函数、可以给它们设置属性和方法。

2. 函数定义

使用关键字 function定义,通常有2种方式: 函数声明语句和函数表达式。

// 函数声明语句: sum为函数名,numA、num为形参。
function sum(numA, numB) {
	return numA + numB;
}

// 函数表达式
const sum = function(numA, numB) {
	return numA + numB;
}

函数返回值使用return关键字, 没有return语句则默认返回undefined
第三种定义的方式是使用Function构造函数。最后一个参数是函数体,之前的都是函数的形参。

const sum = new Function('numA', 'numB', 'return numA + numB');

备注:一般不使用Function构造函数的形式(使用的场景:比如将一段字符串转化为可执行的代码时)。

3. 函数调用

函数名称加一对括号就可以调用函数。括号中可以传入实参,和形参一一对应。

function sum(sumA, sumB) {
	return numA + numB;
}
const result = sum(1, 2);
console.log(result); // 3

4. 函数参数

定义函数时,形参不需要指定类型,调用函数时也不会检查实参的类型和个数。

function sum() {
	return '?';
}
const result = sum(1, 2);
console.log(result); // 正常执行,输出:?

4.1 默认值

函数参数可以指定默认值,如果调用时没有传入对应的值,则会使用默认值。

function sum(numA, numB = 2) {
	return numA + numB;
}
console.log(sum(1)); // 3

4.2 剩余参数

ES6新增:如果函数的最后一个命名参数以...为前缀,则它是包含剩余参数的数组

function sum(numA, ...nums) {
	if (nums) {
		for(let i = 0; i < nums.length; i++) {
			numA += nums[i]
		}
	}
	return numA;
}
console.log(sum(1)); // 1
console.log(sum(1, 2, 3)); // 6

5. 函数内部属性

在函数内部,有2个特殊对象: argumentsthis

5.1 arguments对象

在函数体内,arguments表示实参列表对象,它是一个类数组对象(类数组中的“类”字表示像的意思,就是说arguments对象像数组),可以通过下标访问对应的实参值,也有length属性,但是没有数组的一些方法。

function sum() {
	return arguments[0] + arguments[1];
}
console.log(sum(1, 2)); // 3

5.2 this对象

在函数体内,this是指函数执行的环境对象(也叫context,即函数上下文)。一般来说,this指向调用函数的对象,如果没有,就是全局对象,在浏览器中即为Window对象(Node环境中为Global对象)。

const sum = function () {
	console.log(this);
}
// 严格模式下是 undefined, 非严格模式下是 Window(Node环境为Global)
sum();


const obj = {
	sum: function () {
		console.log(this);
	}
};
// this 为 obj 对象
obj.sum();

6. 函数是特殊对象

函数是特殊的对象,意味着它也是一种值。所以函数可以: 当作参数传递、赋值给变量、作为数组的元素中等。

function callSomeFunction (func, arg) {
	return func(arg);
}
function sum(sum) {
	return 1 + sum;
}

console.log(callSomeFunction(sum, 2)); // 3

函数具有的属性:lengthname。 方法: callapplybind

6.1 函数的属性:length 和 name

6.1.1 length属性

函数的length是该函数期望参数的个数(第一个有默认参数前的参数),不包括有默认值参数和剩余参数。

function sum(numA, numB = 1, ...nums) { }
console.log(sum.length); // 1

function sum(numA, numB = 1, numC, ...nums) { }
console.log(sum.length); // 1

6.1.2 name属性

函数的name属性是该函数的名称。

const sum1 = function () {}
const obj = {
	sum2: function () {}
}
const sum3 = new Function();

console.log(sum1.name); // sum1
console.log(obj.sum2.name); // sum2
console.log(sum3.name); // anonymous

6.2 函数的方法: call、apply、bind

6.2.1 call方法

调用函数,可以指定函数中this和传入参数列表

const obj = {
	name: 'cc',
	say: function (content) {
		const speak = function () {
			console.log(`${this.name} say ${content}`)
		};
		speak();
	}
};

obj.say('welcome'); //  say welcome

以上示例中,在say方法中调用speak,由于speak方法是直接单独调用的,所以函数体内的this指向的是全局变量window,而全局变量window的name属性值为空(''),所以输出'' say welcome

提问:①函数speak中的this.name如何取到cc这个值? ②函数speak如何接收更多参数?
解决方法
① speak() -----> speak.call(this) ,即可。
② speak() -----> speak.call(this, ‘one’, ‘two’) ,在call函数第一个参数后面依次添加参数即可。

6.2.2 apply方法

调用函数,可以指定函数中的 this 和传入 参数数组 ,作用其实和call方法一样,只是后面的参数是以数组的形式传入。助记方法: apply----->首字母a,数组array的首字母也是a------->apply方法传参是以数组的形式。

6.2.3 bind方法

生成一个新的函数,可以指定函数调用时的this对象和传入参数列表
6.2.1中同样的两个问题的解法:
① 因为bind方法是生成一个新的方法,我们需要再调用这个新方法才能得到执行结果:

const obj = {
	name: 'cc',
	say: function (content) {
		const speak = function () {
			console.log(`${this.name} say ${content}`)
		};
		const speak1 = speak.bind(this);
		speak1()
	}
};

obj.say('welcome'); // cc say welcome

② 传参的话,直接在bind函数中的第一个参数后面以参数列表的形式传入即可。

const  speak1 = speak.bind(this, 'one', 'two')

7. 变量作用域简介

JS引擎查找变量的过程,从局部作用域向外层查找,一直到全局作用域为止。
JS引擎查找变量的过程
变量作用域
局部变量的名字可以和全局变量相同,但两者互不影响。

const name = 'cc1';
function outerFunc() {
	const name = 'cc2';
	function innerFunc() {
		const name = 'cc3';
		console.log(name); // 'cc3'
	}
	innerFunc()
	console.log(name); // 'cc2'
}
outerFunc();
console.log(name); // 'cc1'

ES6块级作用域:ES6引入了letconst,它们声明的是块级作用域变量,块由{...}构成。

let x = 10;
var y = 10;
{
	let x = 5;
	var y = 5;
	{
		let x = 2;
		var y = 2;
		console.log(x, y) // 2 2
	}
	console.log(x, y) // 5 2
}
console.log(x, y) // 10 2

原型相关感兴趣的可以看看这篇文章:帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

8. 箭头函数(arrow function)

箭头函数表达式的语法比函数表达式更短,并且不绑定自己的this、arguments、super或new.target。这些函数表达式最适合用于非方法函数,并且它们不能用作构造函数。

const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];
materials.map(function (material) {
	return material.length;
});  // [8, 6, 7, 9]

materials.map((material) => {
	return material.length;
});  // [8, 6, 7, 9]

materials.map(material => material.length );  // [8, 6, 7, 9]

若对你有帮助,可以支持一下作者创作更多好文章哦~
赞赏码

发布了69 篇原创文章 · 获赞 542 · 访问量 32万+

猜你喜欢

转载自blog.csdn.net/cc18868876837/article/details/95366731