一、函数的定义方式
1、函数声明
function demo1() {
var num = 12
var result = Math.pow(num,2)//指数函数
return result
}
2、函数表达式
var demo2 = function (x,y) {
//内置对象arguments前面的两个参数 是 x,y
var sum = arguments[0] + arguments[1]
console.log(sum)
}
3、构造函数
var demo3 = new Function("x","y","return x+y")
二、函数的调用方式
1、函数名()
console.log(demo1())//144
demo(10,20)//30
var re = demo3(1.2,1.3)
console.log(re)//2.5
2、call() / apply()
console.log(demo1.call())//144
console.log(demo1.apply())//144
demo2.call(window, 1, 2)//3
demo2.apply(null, [4, 5])//9
3、自调用
函数表达式自调用
var fn1 = (function () {
console.log('this is function')//this is function
})()
匿名函数
(function () {
console.log('我是匿名函数')//我是匿名函数
})()
4、对象中的函数调用
var obj = {
school: '学校',
study: function () {
console.log('我是对象的函数')//我是对象的函数
},
}
//要用obj去调用 因为所属对象是obj
obj.study()
5、数组中函数的调用
var arr = [10,'0',undefined,null,false,[2, 3],
function () {
console.log('我是函数也是数组的元素')//我是函数也是数组的元素
console.log(this)
//[10, '0', undefined, null, false, Array(2), ƒ, {…}]
},
{},
]
arr[6]()
6、函数当做参数调用
function demo4(x) {
x()
}
demo4(function () {
alert('我是函数也是demo4的参数')//弹窗 我是函数也是demo4的参数
})
7、函数当做返回值的调用
function demo5() {
return function () {
console.log('我是函数也是demo5的返回值')
}
}
demo5()()
如果函数A的返回值是匿名函数B,想要调用匿名函数B 直接再函数A 后面加两个小括号
三、函数中this指向问题(总结)
- 1、在普通函数中this指向window
function fn1() {console.log(this)}
fn1()//window
- 2、在定时器函数中this指向window
var timer = setInterval(function(){
console.log(this);//window
},2000)
- 3、在事件函数中this指向事件源
var btn = document.getElementById("btn")
btn.onclick = function() {
console.log(this)//btn
}
- 4、在对象函数中this指向当前对象
var name = "this window"
var object = {
name: 'this object',
getName: function () {
//this object在对象函数中this指向当前对象(this指向)
console.log(this.name);
console.log(name);//this window 当前没有 往上查找(作用域链查找)
}
}
object.getName()
- 5、在构造函数中this指向实例化对象
function Person(age,name) {
this.age = age
this.name = name
consoel.log(this)//this指向Person的实例对象p1
}
var p1 = new Person(18,;'张哈哈')
- 6、在原型函数中
- 如果原型调用,this指向原型
- 如果实例化对象调用,this指向实例化对象
- 7、在数组函数中this指向当前数组
四、闭包
1、作用域
有且只有函数 才可以产生作用域
全局作用域(永恒作用域)
- 全局变量
- 在任何作用域内都有效
- 生命周期:浏览器打开时创建,关闭时销毁
局部作用域
- 局部变量
- 只在当前作用域内有效
- 生命周期:函数调用时创建,调用完成后销毁
2、闭包的定义?
- 定义在函数内部的函数
3、闭包的作用?
获取父函数内部的变量
console.log(count)//获取不到 因为count是局部的
var num = 15
function parent() {
console.log(num)//15 num是全局的
var count = 12.4
// 闭包函数的本质
// 局部作用域--parent,相对于child作用域是永恒的,本身是作用域是短暂的
function child() {
// 局部作用域--child
console.log(count)
}
child()
}
parent()
锁住父函数内部的变量
// 随机数案例
var getRandom = function (min, max) {
var num = Math.floor(Math.random() * (max - min) + min)
return function(){
console.log(num);
}
}
var result = getRandom(10, 20)
// 两次结果一样 因为父元素执行一次
result()
result()
var btn = document.getElementById("btn")
btn.onclick = (function () {
var count = 0
return function () {
count++
console.log(this)
//由于事件是异步的,所以自调用的是父函数,此时父函数是匿名函数,所以单击事件调用闭包函数
this.innerText = "点赞(" + count + ")"
}
})()
var list = document.querySelectorAll("#list>li")
for (var i = 0; i < list.length; i++) {
(function (i) {
setTimeout(function () {
console.log('索引:'+i);
console.log('文本值:'+list[i].innerText);
},3000)
})(i)
}
4、闭包函数的本质?
- 让父函数相对于闭包函数是永恒作用域
5、闭包作用域之获取复函数内部变量
- this 指向 作用域链的查找规则 预解析 闭包
var name = "this window"
var object = {//不会产生作用域
name: 'this object',
getName: function () {//局部作用域
console.log(this.name);//在对象函数中this指向当前对象
console.log(name);//在当前作用域查找 undefined
var name = "this getName"//var name提升
return function () {
console.log(this.name);//普通函数 this指向window
console.log(name);//this getName 当前作用域没有 往上一级查找
}
}
}
object.getName()()
var name = "this window"
var object = {//不会产生作用域
name: 'this object',
getName: function () {//局部作用域
console.log(this.name);//this object 在对象函数中this指向当前对象
console.log(name);//在当前作用域查找 undefined
var name = "this getName"//var name提升
return function () {
function name(){
console.log('我是函数声明');
}
var name = function () {
console.log(this.name);//普通函数指向window
}
//this object 因为this 指向bind(this)中的this bind的指向object
console.log(this.name);
console.log(name);//this getName函数 当前作用域有name 函数表达式覆盖函数声明
name()
}.bind(this)
return name
}
}
object.getName()()
五、闭包练习题
var x = 11
function fn(x) {
//形参x 相当于var x = 2
console.log(x);//2 fn(2)实参传给x
x = 10
console.log(x);//10 x重新赋值为10
rguments[0] = 20 //fn的第一个参数是x 所以x重新赋值为20
onsole.log(x);//20
fn(2)
console.log(x);//11 全局作用域
var x = 11
function fn(x) {
//相当于 var x 没赋值
console.log(x);//undefined
x = 10
console.log(x);//10
// console.log(arguments); 数组元素是实参
arguments[0] = 20
console.log(x);//10
}
fn()
console.log(x);//11 全局作用域
var x = 11
function fn(x) {
// var x = 11
console.log(x);//11
x = 10
console.log(x);//10
arguments[0] = 20
console.log(x);//20
}
fn(x)//11
console.log(x);//11