目录
1_初识JS函数
1.1_名词foo、bar、baz
foo、bar、baz这些名词:
-
通常被用作函数、变量、文件的名词;已变成计算机编程的术语一部分;
-
但是这些名词本身并没有特别的用途和意义;
-
常被称之为 “伪变量”(metasyntactic variable)
1.2_函数
举例:
-
alert函数: 浏览器弹出一个弹窗
-
prompt函数: 在浏览器弹窗中接收用户的输入
-
console.log函数: 在控制台输入内容
-
String/Number/Boolean函数等……
函数是什么?
-
函数是某段代码的封装,这段代码帮助完成某一个功能;
-
默认情况下JavaScript引擎或者浏览器会提供一些已经实现好的函数;
-
也可编写自己的函数;
2_函数的使用
函数的使用——两个步骤:
-
声明函数 —— 封装 独立的功能
-
调用函数 —— 享受 封装 的成果
2.1_声明函数
声明函数,在JS中也可以称为定义函数:
-
声明函数的过程是对某些功能的封装过程;
-
在开发中,会根据自己的需求定义很多自己的函数;
function 函数名(){
函数封装的代码
……
}
注意:
-
函数名的命名规则和变量名的命名规则相同;
- 第一个字符必须是一个字母、下划线( _ )或一个美元符号( $ )
- 其他字符可以是字母、下划线、美元符号或数字
- 不能使用关键字和保留字命名:
-
函数名尽量做到见名知意(使用动词更多);
-
函数定义完后里面的代码是不会执行的,函数必须调用才会执行;
2.2_调用函数
调用函数,也可以称为函数调用:
-
调用函数是让已存在的为己所用;
-
这些函数可以是刚刚封装好的某个功能函数;
-
也可以使用默认提供的或者其他三方库定义好的函数;
函数的作用:在开发程序时,使用函数可以提高编写的效率以及代码的重用
<script>
// 声明函数
function sayHello() {
console.log("Hello!")
console.log("My name is Coderwhy!")
console.log("how do you do!")
}
// 调用函数。在任何想要使用的时候, 进行调用
sayHello()
</script>
2.3_函数的参数
函数的参数:增加函数通用性,针对 相同的数据处理逻辑
-
在函数定义时,把参数当做 变量 使用,进行需要的数据处理
-
在函数调用时,按照函数定义的参数顺序,把 在函数内部处理的数据,通过参数传递
形参和实参
-
形参:定义函数,小括号中的参数,是用来接收参数用的,在函数内部 作为变量使用
-
实参:调用函数,小括号中的参数,是用来把数据传递到 函数内部用的
<script>
function sum(num1, num2) { //形参
var result = num1 + num2
console.log("result:", result)
}
sum(20, 30) //实参
sum(99, 200) //实参
</script>
2.4_函数的返回值
比如prompt函数:函数需要接受参数,并且会返回用户的输入,这个就是返回值
返回值:
-
使用return关键字来返回结果;
-
函数中执行return操作,当前函数会终止;
-
如果函数中没有使用 return语句 ,有默认的返回值:undefined;
-
如果函数使用 return语句,但是return后面没有任何值,函数的返回值也是:undefined
<script>
// 练习: 传入半径radius, 计算圆形的面积
function getCircleArea(radius) {
return Math.PI * radius * radius
}
var area1 = getCircleArea(10)
var area2= getCircleArea(25)
console.log("area1:", area1)
console.log("area2:", area2)
</script>
arguments参数(JS高级)
-
默认情况下,arguments对象是所有函数中都可用的局部变量(非箭头函数除外);
-
该对象中存放着所有的调用者传入的参数,从0位置开始,依次存放;
-
arguments变量的类型是一个object类型( array-like ),不是一个数组,但是和数组的用法看起来很相似;
-
如果调用者传入的参数多余函数接收的参数,可以通过arguments去获取所有的参数;
<script>
// 1.arguments的认识
function foo(name, age) {
console.log("传入的参数", name, age) // 传入的参数 shy 18
// 在函数中都存在一个变量, 叫arguments。有点像数组,总共传入多少个参数,数组内就有多少个元素。
console.log(arguments) //Arguments(4)
// arguments是一个对象object
console.log(typeof arguments) //object
// 对象内部包含了所有传入的参数
// console.log(arguments[0])
// console.log(arguments[1])
// console.log(arguments[2])
// console.log(arguments[3])
// 对arguments来进行遍历
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i])
}
// shy 18 1.90 北京市
}
foo("shy", 18, 1.90, "北京市")
// 2.arguments的案例
function sum() {
var total = 0
for (var i = 0; i < arguments.length; i++) {
var num = arguments[i]
total += num
}
return total
}
console.log(sum(10, 20)) //50
console.log(sum(10, 20, 30)) // 60
console.log(sum(10, 20, 30, 40)) //100
</script>
2.5_函数中调用函数
在开发中,函数内部是可以调用另外一个函数的
function Hi() {
console.log("早上中午晚上好")
}
function Yes() {
Hi()
console.log("你也是")
}
函数中可以调用自己本身的函数, 但是函数调用自己必须有结束条件,否则会产生无限调用,造成报错。比如下面这种情况
function Hi() {
console.log("早上中午晚上好")
Hi()
}
Hi()
2.6_函数的递归
递归是一种重要的编程思想,同时必须注意,递归要有一个结束条件
//递归实现 x的n次方
// 缺点: 性能是比较低(占用过多的栈内存)
// 优点: 写出来的代码非常简洁
function pow(x, n) {
if(n === 1) return x
return x * pow(x, n-1)
}
3_局部变量和外部变量
外部变量和局部变量的概念:
-
定义在函数内部的变量,被称之为局部变量(Local Variables)。
-
定义在函数外部的变量,被称之为外部变量(Outer Variables)。
全局变量
-
在函数之外声明的变量(在script中声明的),称之为全局变量。
-
全局变量在任何函数中都是可见的。
-
通过var声明的全局变量会在window对象上添加一个属性(了解);
在函数中,访问变量的顺序: 优先访问自己函数中的变量,没有找到时,在外部中访问
<script>
// 1.作用域的理解:message在哪一个范围内可以被使用, 称之为message的作用域(scope)
// 全局变量: 全局作用域
var message = "Hello World"
if (true) {
console.log(message) //可以访问
}
function foo() {
console.log("在foo中访问", message) //可以访问
}
foo()
// 2.ES5之前是没有块级作用域(var定义的变量是没有块级作用域)
//一对花括号{}表示代码块
{
var count = 100
console.log("在代码块中访问count:", count) //可以访问
}
console.log("在代码块外面访问count:", count) //可以访问
// for循环的代码块也是没有自己的作用域
for (var i = 0; i < 3; i++) {
var foo = "foo"
}
console.log("for循环外面访问foo:", foo) //可以访问
console.log("for循环外面访问i:", i) // 3 可以访问
// 3.ES5之前函数代码块是会形成自己的作用域
// 意味着在函数内部定义的变量外面是访问不到的
function test() {
var bar = "bar"
}
test()
//console.log("test函数外面访问bar:", bar) //无法访问,报错
// 函数有自己的作用域: 函数内部定义的变量只有函数内部能访问到
function sayHello() {
var nickname = "kobe"
console.log("sayHello函数的内部:", nickname) //可以访问
function hi() {
console.log("hi function~")
console.log("在hi函数中访问nickname:", nickname) //可以访问
}
hi()
}
sayHello()
// console.log("sayHello外面访问nickname:", nickname) //无法访问,报错
</script>
4_函数表达式
在JavaScript中,函数不是一种神奇的语法结构,而是一种特殊的值, 定义函数的方式,称之为函数声明(Function Declaration);
另外一种写法是函数表达式(Function Expressions):注意,function 关键字后面没有函数名 ,函数表达式允许省略函数名。比如下面这个例子:
<script>
var test = function (){
console.log("函数执行了")
}
test() //函数执行了
</script>
函数用以上两种方法创建, 本质上,函数都是一个值(这个值的类型是一个对象object);
在JavaScript开发中,将函数作为头等公民;
函数声明 VS 函数表达式
-
语法不同
- 函数声明:在主代码流中声明为单独的语句的函数。
- 函数表达式:在一个表达式中或另一个语法结构中创建的函数。
-
JS创建函数的时机不同
- 函数声明:被定义之前,它就可以被调用。这是内部算法的原故;当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数;
- 函数表达式:在代码执行到达时被创建,并且仅从那一刻起可用。
<script>
// 函数声明:先调用,再定义。不会报错
test()
function test() {
console.log("test函数被执行了~")
}
// 函数表达式:先调用,再定义。肯定报错
bar()
var bar = function() {
console.log("bar函数被执行了~")
}
</script>
5_JavaScript头等函数
头等函数(first-class function;第一级函数)是指在程序设计语言中,函数被当作头等公民。这意味着,函数可以作为别的函数的参数、函数的返回值,赋值给变量或存储在数据结构中;
通常对作为头等公民的编程方式,称之为函数式编程。 JavaScript就是符合函数式编程的语言,这个也是JavaScript的一大特点;比如:函数可以在变量和变量之间相互进行赋值;
<script>
// 函数作为头等公民
// 1.函数可以被赋值给变量(函数表达式写法)
var foo1 = function() {
console.log("foo1函数被执行~")
}
// foo1()
// 2.让函数在变量之间来回传递
var foo2 = foo1
foo2()
// 3.函数可以另外一个函数的参数
function bar(fn) {
console.log("fn:", fn)
fn()
}
bar(foo1)
// 4.函数作为另外一个函数的返回值
function sayHello() {
function hi() {
console.log("hi kobe")
}
return hi
}
var fn = sayHello()
fn()
// 5.将函数存储在另外一个数据结构中
var obj = {
name: "xixi",
eating: function() {
console.log("eating")
}
}
obj.eating()
function bar1() {
console.log("bar1函数被执行~")
}
function bar2() {
console.log("bar2函数被执行~")
}
function bar3() {
console.log("bar3函数被执行~")
}
// 事件总线的封装
var fns = [bar1, bar2, bar3]
//函数作为参数时,只写函数名即可,不要加()
// 函数式编程: 使用函数来作为头等公民使用函数, 这种编程方式(范式).
// JavaScript支持函数式编程.
</script>
回调函数(Callback Function)
函数可以作为一个值相互赋值,也可以传递给另外一个函数。
高阶函数必须至少满足两个条件之一:
-
接受一个或多个函数作为输入参数;
-
返回值输出一个函数;
匿名(anonymous)函数: 在传入一个函数时,没有指定这个函数的名词或者通过函数表达式指定函数对应的变量,那么这个函数称之为匿名函数。
<script>
// 1.函数回调的概念理解
function foo(fn) {
// 通过fn去调用bar函数的过程, 称之为函数的回调
fn()
}
function bar() {
console.log("bar函数被执行了~")
}
foo(bar)
// 2.函数回调的案例
function request(url, callback) {
console.log("根据URL向服务器发送网络请求")
console.log("需要花费比较长的时间拿到对应的结果")
var list = ["javascript", "javascript学习", "JavaScript高级编程"]
callback(list)
}
function handleResult(res) {
console.log("在handleResult中拿到结果:", res)
}
request("url", handleResult)
// 3.函数回调的案例重构
function request(url, callback) {
console.log("根据URL向服务器发送网络请求")
console.log("需要花费比较长的时间拿到对应的结果")
var list = ["javascript", "javascript学习", "JavaScript高级编程"]
callback(list)
}
// 传入的函数是没有名字, 匿名函数
request("url", function(res) {
console.log("在handleResult中拿到结果:", res)
})
</script>
6_立即执行函数
一个函数定义完后被立即执行:
-
第一:定义了一个匿名函数,这个函数有自己独立的作用域。
-
第二:加后面的(),表示这个函数被执行了
// 立即执行函数(常用的写法)
(function() {
console.log("立即执行函数被调用~")
})()
// 立即执行函数的参数和返回值
var result = (function(name) {
console.log("函数立刻被执行~", name)
return "Hello World"
})("why")
console.log(result)
应用场景一: 防止全局变量的命名冲突。 在立即执行函数中定义的变量是有自己的作用域的
应用场景二:示例
<body>
<button class="btn">按钮1</button>
<button class="btn">按钮2</button>
<button class="btn">按钮3</button>
<button class="btn">按钮4</button>
<script>
// 1.获取一个按钮监听点击
// 1.1 拿到html元素
// var btnEl = document.querySelector(".btn")
// console.log(btnEl)
// 1.2 监听对应按钮的点击
// btnEl.onclick = function() {
// console.log("点击了按钮1")
// }
// 2.获取所有的按钮监听点击
// 没有使用立即执行函数
//debugger
// var btnEls = document.querySelectorAll(".btn")
// for (var i = 0; i < btnEls.length; i++) {
// var btn = btnEls[i];
// btn.onclick = function() {
// console.log(`按钮${i+1}发生了点击`)
// }
// }
// 使用立即执行函数
var btnEls = document.querySelectorAll(".btn")
for (var i = 0; i < btnEls.length; i++) {
var btn = btnEls[i];
(function(m) {
btn.onclick = function() {
console.log(`按钮${m+1}发生了点击`)
}
})(i)
}
console.log(i)
</script>
</body>
7_代码风格推荐
8_在Chrome进行JS调试debug
在JS代码里面写一句debugger
,一旦运行到debugger就会自动卡在那里进入调试模式。如果第一次运行未进入调试模式,那么多刷新几次浏览器页面。
下图红框圈起来的图标作用:
1 继续执行脚本
2 跳过下一个函数
3 进入下一个函数内部
4 跳出当前函数调用
5 单步调试
推荐两篇文章
写得很好,介绍很全面
- 浏览器工作原理详解 :https://blog.csdn.net/zgrkaka/article/details/78093261
- 浏览器调试功能介绍 :https://blog.csdn.net/qq_40691189/article/details/124438742