JS-函数
2020-06-14 本文已影响0人
刘淘
1.函数基础 函数参数
函数写法:
function func(){}
var func=function(){}
经常使用对象来封装具有某一特定功能的函数集合,内部函数可简写为func(){}
var getName = function (name) {
console.log(name)
}
getName('xiaoming')
const user = {
name: null,
getName() {
return this.name
},
setName() {
this.name = name
}
}
函数参数
- 函数参数分为行参和实参,建议两者数量保持一致
- 如果行参数量大于实参数量,那未传递的形参将赋值为undefined(常用于实现函数重载)
- 如果实参数量大于形参数量,那多余的实参将被忽略(无意义)
- 使用短路运算符或默认参数对某些参数赋默认值,默认参数必须放在函数声明的最后
- 使用函数参数arguments声明可变参数,但arguments不是数组,需要通过[...arguments]或Array.from(arguments)来转化
- 使用...args来替换arguments声明可变参数,可直接使用数组的相关方法
+使用...扩展运算符声明参数,但必须放到函数声明的最后,甚至是默认参数的最后
// 形参&实参
function sum(a, b) {
console.log(a, b)
}
sum(1) // 1, undefined
sum(1, 2, 3) // 1, 2
// 默认参数
function avg(year = 1, total) {
// year = year || 1
return Math.round(total / year)
}
console.log(avg(3000)) // 3000
console.log(avg(3000, 2)) // 1500
function sort(arr, type = 'asc') {
return arr.sort(function (a, b) {
return type === 'asc' ? a - b : b - a
})
}
console.log(sort([1, 3, 4, 2, 5]))
console.log(sort([1, 3, 4, 2, 5], 'desc'))
//利用扩展运算符计算arguments
function sum1() {
return [...arguments].reduce((a, b) => a + b)
}
function sum2() {
return Array.from(arguments).reduce((a, b) => a + b)
}
console.log(sum1(1, 1))
console.log(sum1(11, 11))
//使用扩展运算符声明参数,必须放到最后
function totalDisPrice(discount = 0, ...price) {
return price.reduce((a, b) => a + b) * (1 - discount)
}
console.log(totalDisPrice(.1, 100, 200))
2.全局函数
- 使用function func() 或者var func=function()定义的函数全都会直接挂载到window上,成为全局函数
- 全局函数可能与window上已有成员冲突,造成全局污染
- 建议不要独立定义函数,而是要将函数放在对象或类的内部去定义
//window自带的函数
console.log(window.screenX)
var screenX = function () {
console.log('获取x轴的位置')
}
//覆盖window上已有成员,造成全局污染
console.log(window.screenX)
//放在一个对象上,避免覆盖window已有成员
const position = {
screenX() {
console.log('获取x轴的位置')
},
}
console.log(position.screenX)
3.匿名函数
- 使用var func=function()定义匿名函数,同时函数是引用类型
-
函数表达式function func(){}与匿名函数var func=functioin(){}的区别:函数表达式存在变量提升,匿名函数不存在
image.png
4.立即执行函数
- 立即执行函数不需要外部调用,只需引入即可执行,格式:(function(){})()
*立即执行函数常用于构建第三方插件库
*立即执行函数解决第三方库与业务库之间的命名冲突问题,当然也可以使用模块化来解决
(function(){
console.log('somethig is wrong')
})()
//第三方库js:vendor.js
; (function (window) {
'use strict'
const getName = function () {
console.log('from vendor:vendor Name')
}
window.vendor = { getName }
})(window)
//业务库 app.js
{
const getName = function () {
console.log('from app:app Name')
}
window.app = { getName }
}
//立即执行函数解决库之间的命名冲突问题
///在同一个页面引入vendor.js app.js
vendor.getName() //from vendor:vendor Name
app.getName() //from app:app Name
5.回调函数
- 回调函数即在其他函数的内部调用,以匿名函数
- 回调函数常用于事件处理,数组操作
//<button name="callback">回调</button>
document.querySelector('[name="callback"]').addEventListener('click', function() {
alert(this.innerHTML)
})
const nums = [1, 2, 3, 4, 5]
// [10, 20, 30, 40, 50]
console.log(nums.map(function(item) {
item = item * 10
return item
}))
6.递归函数
- 递归函数即不断重复调用自身,直到有返回结果为止
- 递归函数类似入栈 出栈,当递归开始时会依次将每一次递归表达式入栈,当有返回结果时依次将结果传递到上一层的表达式出栈
// 阶乘
const factorial = function (num) {
// if (num === 1) return 1
// return num * factorial(num - 1)
return num === 1 ? 1 : num * factorial(num - 1)
}
console.log(factorial(2)) // 120
// 求和
const sum = function (...args) {
// if (!args.length) return 0
// return args.pop() + sum(...args)
return !args.length ? 0 : args.pop() + sum(...args)
}
console.log(sum(1, 2, 3, 4, 5)) // 15
7.箭头函数
- 使用箭头函数可极大简化代码编写,去掉之前的function关键字,格式:()=>{}
- 当箭头函数只有一个参数时,可去掉()
- 当箭头函数体只有一句话时,可去掉{}
- 箭头函数无法解决递归 构造函数 事件处理等场景
const sum = function (...args) {
return args.reduce(function (a, b) {
return a + b
})
}
//当箭头函数体只有一句话时,可去掉{}
const sum = (...args) => {
return args.reduce((a, b) => {
return a + b
})
}
const sum = (...args) => args.reduce((a, b) => a + b)
console.log(sum(1, 2, 3, 4, 5))
8.this指针
- 函数定义在类或对象的内部,称之为方法
- 在方法内部可以使用this获取对象的所有成员,包括方法本身
- 在方法内部在定义函数,函数内部的this则是window,而不是对象本身
-
如果想再方法内部函数中获取当前对象,可以使用常量或者箭头函数来改变this指针
image.png
image.png
image.png
image.png
image.png - 在对象中定义DOM事件回调函数,可使用function或箭头函数
- 如果是function,当前this则是指向当前DOM元素
- 如果是是箭头函数,当前this指向的是当前对象 本身
- 如果同时需要获取当前DOM对象和对象本身,对function而言使用常量解决,对箭头函数而言使用event
- 如果同时对多个DOM元素定义事件回调函数,建议保持纯净性:要么都使用function,要么都使用箭头函数
//eg: <button name='landiao'>蓝调</button>
//eg: <button name='dianyin'>电音</button>
const music = {
name: '音乐',
show() {
const landiao = document.querySelector('[name="landiao"]')
const dianyin = document.querySelector('[name="dianyin"]')
const _this = this
landiao.addEventListener('click', function () {
console.log(this) //<button name='landiao'>蓝调</button>
console.log(`${_this.name}-${this.innerHtml}`)//音乐-蓝调
})
dianyin.addEventListener('click', (e) => {
console.log(this) //{name:'音乐',show:f} 箭头函数的this就是定义时所在的对象
console.log(`${this.name}-${e.target.innerHtml}`) //音乐-电音
})
},
bind() {
const buttons = document.querySelectorAll('button')
buttons.forEach((item) => {
console.log(this) //箭头函数的this就是其定义时所在的对象{name:'音乐',show:f,bind:f}
item.addEventListener('click', (e) => {
console.log(this) //箭头函数的this就是其定义时所在的对象{name:'音乐',show:f,bind:f}
console.log(`${this.name}-${e.target.innerHTML}`)
})
})
}
}
user.show()
user.bind()
9.call apply bind
- 使用call apply改变this指针的指向,将this指向当前传入的对象,且函数会立即执行
- call apply的区别:call可传入多个参数,apply只能传入数组
*使用bind也能改变this指针的指向,将this指向当前传入的对象,但函数不会立即执行,同时返回一个函数 - 使用bind传参有两种方式:定义时传参(优先)或调用是传参
- 使用bind常用于处理事件回调从外面传入参数
//eg: <button name='landiao'>蓝调</button>
//eg: <button name='dianyin'>电音</button>
const user = {
name: 'xiaoming',
}
function Person(url,skills){
console.log(this.name,url,siklls)
}
Person.call(user,'http://baidu.com',['蓝调','电音'])
Person.apply(user,['http://baidu.com',['蓝调','电音']])
//bind bind bind start
const fun1=Person.bind(user) //bind返回的是一个函数,不会立即执行
fun1('http://baidu.com',['蓝调','电音']) //bind的传参方式
const fun2=Person.bind(user,'http://baidu.com',['蓝调','电音'])
fun2() //执行bind返回的函数
//bind bind bind end
//应用1
function showInnerHtml(){
alert(this.innerHtml())
}
const buttons=document.querySelectorAll('button')
buttons.forEach(item=>{
item.addEventListener('click',(e)=>{
show.call(e.target)
})
})
//应用2 随机切换背景图
function Color(elem) {
this.elem = elem
this.colors = ['#9b59b6', '#1abc9c', '#34495e', '#e74c3c', '#f39c12']
this.run = function () {
setInterval(function () {
//Math.floor向上取整 Math.random随机 (0~1)
const index = Math.floor(Math.random() * this.colors.length)
this.elem.style.backgroundColor = this.colors[index]
}.bind(this), 1000)
}
}
const color = new Color(document.body)
color.run()
- 使用call apply实现类的继承,对已有的功能执行复用
function Request() {
this.get = (params) => {
const query = Object.keys(params).map(item => `${item}=${params[item]}`).join('&')
const url = `http://baidu.com/${this.url}?${query}`
console.log(url)
}
}
// 继承
function Article() {
this.url = 'article/list'
Request.call(this)
// Request.apply(this)
}
function User() {
this.url = 'user/list'
Request.call(this)
// Request.apply(this)
}
const article = new Article()
const user = new User()
article.get({ id: '1', cat: 'js' }) // http://baidu.com/article/list?id=1&cat=js
user.get({ name: 'miracle', role: 'admin' }) // http://baidu.com/user/list?name=miracle&role=admin