感激相遇,你好,我是阿ken??
版权声明:本文为CSDN博主「」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
另外,博文中某些图片或内容可能出自网络,如有侵权或问题,请及时私信我
有学妹想以后做前端,就会问到 JavaScript怎么学的问题,在多次百般盘问下,阿ken?? 决定贡献出自己之前学习 JavaScript时的笔记。
安全感这个东西对于大多数人而言
是靠很多次坚持不懈去努力争取的
不要因为没怎么努力过
到头来连一件值得回忆的事情都没有
这不是为了向别人证明自己了不起
这只不过是把本该属于自己的东西夺回来
???
function 函数名() {
//函数体代码
}
function 是声明函数的关键字,必须全部使用小写字母。
当函数声明后,里面的代码不会执行,只有调用函数的时候才会执行。
调用函数的语法为“函数名( )”。
案例:
//声明函数
function sayHello() {
console.log ('Hello');
}
//调用函数
sayHello();
函数的参数分为形参和实参。
在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参。
当函数调用的时候,同样也需要传递相应的参数,这些参数称为实参。
函数的形参是形式上的参数,因为当函数声明的时候,这个函数还没有被调用,这些参数具体会传过来什么样的值是不确定的。而实参是实际上的参数,在函数被调用的时候。它的值就被确定下来了。
案例:
function 函数名 (形参1, 形参2, ...) {
// 函数体代码
}
函数名 (实参1, 实参2, ...);
JavaScript 函数参数的使用非常灵活,它允许函数的形参和实参个数不同。当实参数量多于形参数量时,函数可以正常执行,多余的实参由于没有形参接收,会被忽略,除非用其他方式(例如后面学到的 arguments )才能获得多余的实参。当实参数量小于形参数量时,多出来的形参类似一个已声明未赋值的变量,其值为 undefined。
function getSum (num1, num2) {
console.log (num1, num2);
}
getSum (1, 2, 3); // 实参数量大于形参数量,输出结果为 1,2
getSum (1); // 实参数量小于形参数量,输出结果为 1,undefined
例如,一个人去餐厅吃饭,我们将餐厅的厨师看成一个函数,顾客通过函数的参数来告诉厨师要做什么菜。当厨师将饭菜做好以后,这个饭菜最终应该是传给顾客。但我们在前面编写的函数都是直接将结果输出,这就像厨师自己把饭菜吃了,没有将函数的执行结果返回给调用者。
格式:
function 函数名() {
return 要返回的值; //利用 return 返回一个值给调用者
}
案例:
function getResult() {
return 666;
}
// 通过变量接收返回值
var result = getResult();
console.log (result); // 输出结果:666
// 直接将函数的返回值输出
console.log ( getResult() );// 输出结果:666
console.log (getResult);// 输出结果:输出函数(见下图)
反例:
function getResult() {
console.log (1);
// 该函数没有return
}
getResult(); // 输出结果: 1
console.log ( getResult() ); // 输出结果: 1 undefined
function getMax (num1, num2) {
if (num1 > num2) {
return num1;
} else {
return num2;
}
}
console.log ( getMax(1, 3) ); // 输出结果: 3
或者
function getMax (num1, num2) {
return num1 > num2 ? num1 : num2;
}
console.log ( getMax(1, 3) ); // 输出结果:3
回顾一下如何创建数组:
【熬夜猛肝万字博文】学妹问我怎么入门 Javascript,百般盘问下我终于决定贡献出自己的 JavaScript入门笔记(三)
function getArrMax(arr) {
var max = arr[0];
for(var i = 1; i <= arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
return max;
}
var arr = getArrMax([5, 2, 99, 101, 67, 77]);
console.log(arr); // 输出结果: 101
或者
function getArrMax(arr){
var max = arr[0];
for(var i = 1; i <= arr.length-1; i++) {
if(arr[i] > max){
max = arr[i];
}
}
return max;
}
console.log( getArrMax( [5, 2, 99, 101, 67, 77]) );
// 输出结果:101
return 语句之后的代码不会被执行。
例如:在 getMax() 函数中判断两个参数是否都是数字型,只要其中一个不是数字型,则提前返回 NaN。
function getMax(num1,num2){
if(typeof num1 != 'number' || typeof num2 != 'number'){
return NaN;
}
return num1 > num2 ? num1 : num2;
}
console.log( getMax(1, '3') ); // 输出结果:NaN
NaN( Not a Number,非数),是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。
null(空型)、undefined(未定义型)、number(数字型) 为基本数据类型。
在函数中使用 return 时,应注意 return 只能返回一个值。即使使用多个逗号隔开多个值,也只有最后一个值被返回。
function fn(num1, num2){
return num1, num2;
}
console.log( fn(1, 2) ); // 输出结果:2
在开发中,当需要返回多个值的时候,可以用数组来实现,也就是将要返回的多个值写在数组中,作为一个整体来返回。
function getResult(num1, num2){
return [num1 + num2, num1 - num2, num1 * num2, num1 / num2];
}
console.log( getResult(1,2) ); // 输出结果: (4)[ 3, -1, 2, 0.5 ]
function getMax(){
var max = arguments[0];
for(var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
console.log( getMax(1,2,3) );// 输出结果:3
console.log( getMax(1,2,3,4,5) );// 输出结果:5
console.log( getMax(11,2,34,666,5,100) );// 输出结果:666
function reverse(arr){
var newArr = [];
for(var i = arr.length - 1; i >= 0; i--){
newArr[newArr.length] = arr[i];
}
return newArr;
}
var arr1 = reverse( [1, 3, 4, 6, 9] );
console.log(arr1);// 输出结果:(5)[9,6,4,3,1]
function isLeapYear(year){
var flag = false;
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0){
flag = true;
}
return flag;
}
console.log( isLeapYear(2020) ? '2020是闰年' : '2020不是闰年' );// 2020是闰年
console.log( isLeapYear(2021) ? '2021是闰年' : '2021不是闰年' );// 2021不是闰年
//该题目答案要加上4.3.3的代码
function fn(){
var year = prompt('请输入年份');
if ( isLeapYear(year) ){
alert('当前月份是闰年,2月份有29天')
}else{
alert('当前月份是平年,2月份有28天')
}
}
function isLeapYear(year){
var flag = false;
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0){
flag = true;
}
return flag;
}
fn();
函数表达式是将声明的函数赋值给一个变量,通过变量完成函数的调用和参数的传递。
//函数声明
function funcName() {
// 函数体
}
var sum = function (num1, num2) {
// 函数表达式
return num1 + num2;
};
console.log ( sum(1,2) ); // 3
函数表达式与函数声明的定义方式几乎相同,不同的是函数表达式的定义必须在调用前,而函数声明的方式则不限制声明与调用的顺序。由于 sum 是一个变量名,给这个变量赋值的函数没有函数名,所以这个函数也叫匿名函数。
将匿名函数赋值给了变量 sum 后,变量 sum 就能像函数一样调用。
项目开发中,若想要函数体中某部分功能由调用者决定,此时可以使用回调函数。所谓回调函数指的就是一个函数A作为参数传递给一个函数B,然后在B的函数体内调用函数A。此时,我们称函数A为回调函数。其中,匿名函数常用作函数的参数传递,实现回调函数。
function cal(num1,num2,fn){
return fn(num1,num2);
}
console.log( cal(45,55,function(a,b){
return a+b; })
);
console.log(cal(10,20,function(a,b){
return a*b; })
);
回调函数和递归调用好好理解一下
递归调用是函数嵌套调用中一种特殊的调用。
它指的是一个函数在其他函数体内调用自身的过程,这种函数成为递归函数。
递归函数和回调函数的区别,这是你需要思考的
需要注意的是,递归函数只可在特定的情况下使用,如计算阶乘。
function factorial(n){ //定义回调函数
if( n == 1 ){
return 1;
}
return n * factorial(n - 1);
}
var n = prompt('求n的阶乘
n是大于等于1的正整数,如2表示求2!。');
n = parseInt(n);
if(isNaN(n)){
console.log('输入的n值不合法');
}else{
console.log(n + '的阶乘为:'+factorial(n));
}
自己想办法搞一搞,对于刚学小白来说,有点难
变量需要先定义后使用,但声明变量后并不是就可以在任意位置使用该变量。
function info() {
var age = 18; //此处age为局部变量
}
info();
console.log (age);
//报错,提示age is not defined(age未定义)
//该处只能调用全局变量
从上述代码中可以看出,变量需要在它的作用范围内才可以被使用,这个作用范围称为变量的作用域。JavaScript 根据作用域使用范围的不同,将其划分为全局作用域、函数作用域和块级作用域(ES 6提供的)
//全局作用域
var num = 10; //全局变量
function fn() {
//局部作用域
var num = 20; //局部变量
console.log (num); //输出局部变量num的值,输出结果:20
}
fn();
console.log (num);
//输出全局变量10的值,输出结果:10
在上述代码中,全局变量num和局部变量num虽然名称相同,但是它们互不影响。
需要注意的是,函数中的变量如果省略var关键字,它会自动向上级作用域查找变量,一直找到全局作用域为止。
function fn() {
num2 = 20; // 局部变量
}
fn();
// 如果不调用函数,下面的输出语句会报错
console.log (num2);// 输出结果:20;
从以上可以看出,在全局作用域下,添加或省略var关键字都可以声明全局变量;
而在函数中,添加var关键字声明的变量是局部变量,省略var关键字时,如果变量在当前作用域下不存在,会自动向上级作用域查找变量。
局部变量只能在函数内部使用,函数的形参也属于局部变量。
从执行效率来说,全局变量在浏览器关闭页面的时候才会销毁,比较占用内存资源;而局部变量在函数执行完成后就会销毁,比较节约内存资源。
当在一个函数内部声明另一个函数时,就会出现函数嵌套的效果。
当函数嵌套时,内层函数只能在外层函数作用域内执行,在内层函数执行的过程中,若需要引入某个变量,首先会在当前作用域中寻找,若未找到,则继续向上一层级的作用域中寻找,直到全局作用域。称这种链式的查询关系为作用域链。
var num = 10;
function fn(){ //外部函数
var num = 20;
function fun(){ //内部函数
console.log(num);//输出结果:20
//如果省略 var num = 20; 则输出结果为10
}
fun();
}
fn();
所谓"闭包"指的就是有权访问另一函数作用域内变量(局部变量)的函数。
其主要用途:
① 可以在函数外部读取函数内部的变量。
② 可以让变量的值始终保存在内存中。
注意:由于闭包会使得函数中的变量一直被保存在内存中,内存消耗很大,所以滥用闭包可能会降低程序的处理速度,造成内存消耗等问题。
常见的闭包函数创建方式就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量。
function fn() {
var times = 0;
var c = function() {
return ++times;
};
return c;
}
var count = fn(); //保存fn()返回的函数,此时count就是一个闭包
//访问测试
console.log( count() ); // 输出结果::1
console.log( count() ); // 输出结果::2
console.log( count() ); // 输出结果::3
console.log( count() ); // 输出结果::4
console.log( count() ); // 输出结果::5
// 闭包函数就会这样一直循环,不会重新定义
仔细思考:闭包函数到底是什么
JavaScript 代码是由浏览器中的 JavaScript 解析器来运行的,在运行其代码时会进行预解析,即对 var 变量声明和 function 函数声明进行了解析。
console.log (num); // 输出结果: undefined
var num = 10;
// 以下代码由于不存在 var num2, 所以会报错
console.log (num2); // 报错,提示 num2 is not defined(num2 未定义)
运行结果:
以上代码中 第 2 行在变量 num 声明前就访问了变量 num,却没有像第 5 行的 num2 一样报错,这是因为第 3 行代码中的 var num 会被预解析,例如:
var num; // num 的变量声明由于预解析而提升到前面
console.log (num); // 输出结果: undefined
num = 10;
// 由于 num的变量声明会被预解析,所以 console.log (num)不会报错,并且由于赋值操作 num = 10 不会被预解析,所以此时 num 的值为 undefined
运行结果:
预解析能解析 var 变量声明,但不能解析 var 变量声明后面的变量赋值语句
fn();
function fn(){
console.log('fn'); // 该函数最后会被成功调用
}
运行结果:
以上代码中 fn() 函数调用的代码写在了函数声明的前面,但函数仍然可以正确调用,这是因为 function 函数声明操作会被预解析。
再例如:
console.log(fun);
fun(); // 报错,提示fun is not a function (fun 不是一个函数)
var fun = function(){
console.log('fn');
}
运行结果:
上述代码中 fun 不是一个函数,这是因为 var fun 变量声明会被预解析,预解析后,fun 的值为 undefined,此时的 fun 还不是一个函数,所以无法调用。
只有第 2 ~ 4 行代码执行后,才可以通过 fun() 来调用函数
即预解析能解析 函数声明 和 var 变量声明,但不能解析 var 变量声明后的赋值语句
阿ken??在此求观众老爷来个三连支持一下!!!
如果你还想继续跟阿ken??学习 JavaScript 的话,请看下文:
【熬夜猛肝万字博文】学妹问我怎么入门 Javascript,百般盘问下我终于决定贡献出自己的 JavaScript入门笔记(一)
【熬夜猛肝万字博文】学妹问我怎么入门 Javascript,百般盘问下我终于决定贡献出自己的 JavaScript入门笔记(二)
【熬夜猛肝万字博文】学妹问我怎么入门 Javascript,百般盘问下我终于决定贡献出自己的 JavaScript入门笔记(三)