《python全栈工程师 - web开发前端基础》:javascript函数
课程目标
- 函数的基本定义
- 作用域
- 嵌套函数与闭包
- 高阶函数
- callee与this
详情解读
1.1函数的基本定义
函数声明:
function funcName(args1, args2) {
…
…
return…
}
函数调用传参时可以传递不限数量的参数,在函数内部使用arguments对象接受
函数表达式:
funcName = function (args1, args2) {
…
…
return…
}
使用函数声明与使用函数表达式定义的区别:
函数声明会在调用之前已经加载好
函数表达式只有执行到该行代码时才会定义函数
// 函数声明式定义方式
function myFun(){
console.log("hello world")
}
//函数调用
myFun()
// 函数参数
function mySub(a, b){
console.log("a=>",a ," b=>", b)
return a-b
}
// // 传参调用
// // 顺序传参
// mySub(10,2)
// //不支持关键字传参
mySub(b=2, a=10)
运行结果:(注意js是不支持关键字传参的,不要被mySub(10,m=2)迷惑)
1.2 默认参数位置不限制、按照顺序传参
function myFun(a, c, b=2, d){
console.log("a=>", a, " b=>", b, " c=>", c, " d=>", d)
}
a = 10, b = 2
myFun(10)
a = 10, c = 20, b = 2
myFun(10, 20)
a = 10, c = 20, b = 30
myFun(10,20,30)
a = 10, c = 20, b = 30, d = 40
myFun(10,20,30,40)
1.3参数列表-arguments,通过传参顺序索引0,1,2,3…取值
function myFun(a,b){
console.log(a)
console.log(b)
console.log(arguments)
console.log(arguments[0]) //a
console.log(arguments[0]) //b
}
myFun(1,20)
myFun(1,2,3,4,5,6)
function myStudents(){
console.log(arguments)
if (arguments[0]!=undefined){
console.log("您的名字:",arguments[0] )
}
if (arguments[1]!=undefined){
console.log("您的性别:",arguments[1] )
}
}
myStudents("luxp")
myStudents("luxp", "男")
1.4匿名函数-函数表达式,可以将匿名函数赋值给一个变量
使用函数声明与使用函数表达式定义的区别
函数声明会在调用之前已经加载好
函数表达式只有在执行到该行代码时才会定义函数
my_func = function(){
console.log(arguments)
}
my_func()
myHello1() // 这句正常执行,因为函数声明会在调用之前已经加载好
myHello2() // 这句会报错,因为匿名表达式只有执行到该行代码时才会定义函数
function myHello1(){
console.log("hello")
}
myHello2 = function(){
console.log("hello")
}
// 下面两句都可以正常执行
myHello1()
myHello2()
2.1不支持重载:javascript定义多个同名函数,只有最后一个生效
function myfun(a){
console.log("1")
}
function myfun(a,b){
console.log("2")
}
function myfun(a,b,c){
console.log("3")
}
2.2作用域
在web浏览器中,全局环境表示为窗口window对象下
所有的全局变量与函数都是window的属性或者方法
关闭浏览器窗口,就销毁了所有的全局对象
每个函数都拥有自己的执行环境
每一个代码执行时都有自己的作用域链,作用链前端就是当前执行环境的变量对象,作用域链下一个变量对象就是下一个包含的环境,直到全局环境
在另一个窗口的运行:
在函数内部使用var定义的变量为函数内部变量,
如果没有使用var关键字,变量就会声明为全局变量。
es5规范中并没有块级作用域,即诸如if, while的{}部分,es6拥有块级作用域
my_sex= "男"
function myFun(){
var my_name = "luxp" // 此处my_name是局部作用域的变量,外部不能访问;如果没有用var,则是全局作用域的变量,外部可以访问
my_age = 18
console.log(my_name, my_sex)
}
myFun()
console.log(my_name)
变量作用域查找顺序由内而外寻找,当在函数内部定义局部变量时,首先会声明该变量
var name = "luxp"
function seekName1(){
var name = "luxp_2"
console.log(name) // 输出 luxp_2
var name = "luxp_1"
function subFun(){
var name = "luxp_3"
// name = "luxp_4"
console.log(name) // 输出 luxp_3
}
subFun()
}
seekName1()
//局部变量会被预先声明
function seekName2(){
console.log(name) // 输出全局变量中的name,为 luxp
// 如果用var声明name,则上面的语句打印结果为undefined,是相当于在打印name之前声明了局部变量name
// var name = "luxp_2"
// var name = "luxp_1"
function subFun(){
var name = "luxp_2"
// name = "luxp_4"
console.log(name) // 输出局部变量中的name,为luxp_2
}
subFun()
}
seekName2()
2.3嵌套函数与闭包
function funcParent() {
funcChild() {
}
return funcChild()
}
将函数作为值返回
示例代码:
function create_fun(I){
return function (){
return "func_"+I
}
}
func_array = []
for (i=0;i<5;i++){
func_array[i]=create_fun(i)
}
如何让每个函数输出不同的值
/*
闭包的原因,所有的函数都会输出five
*/
function create_fun(){
var array=['one','two','three','four','five']
var func_array=[]
for(i in array){
console.log(i)
func_array[i]=function(){
return array[i]
}
}
return func_array
}
//执行这一句的时候,内部函数其实是引用i,而不是i的值,执行
//到最后的时候i的值是4,所以全部的函数的i都是5
func_array=create_fun()
func_array[0]()
function create_fun(){
var array = ["one", "two", "three", "four", "five"]
var func_array = []
for (i in array){
func_array[i] = function create_fun(I){
//增加了一个内嵌函数
return function (){
return array[I]
}
//执行,通过执行把i的值固定下来
}(i)
}
return func_array
}
func_array = create_fun()
func_array[0]()
2.4函数作为参数
函数可以作为一个参数给另一个函数调用,另一个函数就被称为该函数的高阶函数
示例代码:
function sum(a,b){
return a+b
}
function sub(a,b){
return a-b
}
function compute(func, a,b){
return func(a,b)
}
value = compute(sum, 10,3)
value = compute(sub, 10, 3)
function selectEvenNumber(number){
if (number % 2 == 0) {
return number
} else {
return 0
}
}
function selectOddNumber(number){
if (number % 2 == 1) {
return number
} else {
return 0
}
}
function map(array, func=selectEvenNumber){
for ( i in array){
array[i] = func(array[i])
}
}
array = [1,2,3,4,5,6,7,8,9]
map(array)
console.log(array)
array = [1,2,3,4,5,6,7,8,9]
map(array, selectOddNumber)
console.log(array)
/*
js中常见的一种高阶用法
*/
function myfun(args, func){}
myfunc(args, function(){})
运行结果:
2.5 高阶函数
function func1(){}
function func2(func){
return func()
}
return func2(func1)
2.5.1 callee与this
arguments.callee可以在内部对函数名实现解耦
callee代表这对函数自身的引用,可以降低函数名与内部调用的耦合性
示例代码一:
function myFun(){
console.log(arguments)
console.log(arguments.callee)
}
运行结果:
示例代码二:
/*利用递归计算阶乘 */
// 这种方法,当函数名改变时,函数内部的递归方法名也得修改
function jiecheng(num) {
if (num === 1) {
return 1
} else {
return num * jiecheng(num-1)
}
}
// 这种方法不一样,无论函数名如何改变,函数内部的递归方法名不用修改
function jiecheng(num) {
if (num === 1) {
return 1
} else {
return num * arguments.callee(num-1)
}
}
2.5.2 this
在函数内部,this引用了函数的执行环境
/* this 指向对象由所在的执行环境决定 */
console.log(this)
function myFun(){
console.log(this)
// return this
this.nickname = "luxp"
}
function myFun(){
function mySubFun(){
console.debug(this)
return this
}
return mySubFun()
}
function myFun(){
var o = new Object()
o.func = function(){
console.log(this)
}
return o
}