共计 5075 个字符,预计需要花费 13 分钟才能阅读完成。
欢送关注前端小讴的 github,浏览更多原创技术文章
Function 类型
- 函数是 对象 ,每个函数都是
Function
类型的实例,都与其余援用类型一样具备 属性 和办法 - 函数名是 指向函数对象的指针,不会与某个函数绑定(一个函数可能会有多个名字)
相干代码 →
3 种申明形式
// 1. 函数申明定义
function sum(num1, num2) {return num1 + num2}
// 2. 函数表达式定义
var sum = function (num1, num2) {return num1 + num2}
// 3.Function 构造函数定义
/* 不举荐应用构造函数定义,因为会造成解析 2 次代码(1 次解析惯例 js 代码,1 次解析传入构造函数中的字符串)*/
var sum = new Function('num1', 'num2', 'return num1+num2')
拜访函数指针
function sum(num1, num2) {return num1 + num2}
console.log(sum(10, 10))
var anotherSum = sum // 应用不带圆括号的函数名是拜访函数指针,而非调用函数
console.log(anotherSum(10, 10))
/* sum 和 anotherSum 同时指向同一个函数 */
sum = null // sum 与函数断绝关系
console.log(anotherSum(10, 10)) // 但 anotherSum()仍可失常调用
console.log(sum(10, 10)) // 会报错,sum is not a function
没有重载
function addSomeNumber(num) {return num + 100}
// 创立第二个函数
function addSomeNumber(num) {return num + 200}
// 第二个函数等价于下列代码 -> 笼罩了援用第一个函数的变量 addSomeNumber
addSomeNumber = function (num) {return num + 200}
var result = addSomeNumber(100)
console.log(result) // 300
函数申明与函数表达式
js 引擎在代码开始执行之前,解析器通过 函数申明晋升(function declaration hoisting)的过程,将 申明函数 放到源代码树的顶部,使其 在执行任何代码之前可用(能够拜访);而 函数表达式 则必须等到解析器执行到所在代码行才被解释执行。
函数申明 和函数表达式 的惟一区别就是 什么时候能够通过变量拜访函数
console.log(sumDeclare(10, 10)) // 函数申明会提前
function sumDeclare(num1, num2) {return num1 + num2}
console.log(sumExpression(10, 10)) // 函数表达式不会提前,会报错,sumExpression is not a function
var sumExpression = function (num1, num2) {return num1 + num2}
作为值的函数
像传递参数一样,把一个函数传递给另一个函数,也能够将一个函数作为另一个函数的后果返回
function callSomeFunction(someFunction, someArgument) {return someFunction(someArgument)
}
function add10(num) {return num + 10}
var result1 = callSomeFunction(add10, 10) // 拜访函数的指针而不是执行函数
console.log(result1) // 20
function getGreeting(name) {return 'Hello,' + name}
var result2 = callSomeFunction(getGreeting, 'Nicholas') // 拜访函数的指针而不是执行函数
console.log(result2) // Hello,Nicholas
【例】想要依据数组对象的某个对象属性进行排序:
/**
* 依照对象数组的某个 object key,进行数组排序
* @param {String} key 要排序的 key
* @param {String} sort 正序 / 倒序:asc/desc,默认为 asc
*/
function arraySort(key, sort) {return function (a, b) {if (sort === 'asc' || sort === undefined || sort === '') {// 正序:a[key] > b[key]
if (a[key] > b[key]) return 1
else if (a[key] < b[key]) return -1
else return 0
} else if (sort === 'desc') {// 倒序:a[key] < b[key]
if (a[key] < b[key]) return 1
else if (a[key] > b[key]) return -1
else return 0
}
}
}
var userList = [{ name: 'Tony', id: 3},
{name: 'Tom', id: 2},
{name: 'Jack', id: 5},
]
console.log(userList.sort(arraySort('id'))) // 按 id 正序排列
console.log(userList.sort(arraySort('id', 'desc'))) // 按 id 倒序排列
函数外部属性
函数外部有 2 个非凡对象 arguments
和 this
,1 个外部属性 caller
arguments
是一个 类数组对象 ,保留着函数的所有参数。对象有 callee
属性,该属性是一个 指针 ,指向 领有这个 arguments 对象的函数
// 递归函数:计算阶乘
function factorial(num) {if (num <= 1) return 1
else return num * factorial(num - 1)
}
// 外部不再援用函数名,无论函数名是什么,都能够保障实现递归调用
function factorial(num) {if (num <= 1) return 1
else return num * arguments.callee(num - 1) // callee 指向领有这个 arguments 对象的函数
}
var trueFactorial = factorial // 保留函数的指针
factorial = function () {return 0}
console.log(trueFactorial(5)) // 120,已用 arguments.callee 解除函数体内代码与函数名的耦合,仍能失常计算
console.log(factorial(5)) // 0
this
援用的是 函数执行的环境对象 ,即 this 值( 全局作用域 调用函数时援用的是 window
)
// vscode 是 node 运行环境,无奈辨认全局对象 window,测试时需做微调
window.color = 'red'
var o = {color: 'blue'}
function sayColor() {console.log(this.color)
}
sayColor() // red,此时 this 指向对象 window
o.sayColor = sayColor
o.sayColor() // blue,此时 this 指向对象 o
ES5 定义了 caller
属性,保留着调用以后函数的函数援用—— 谁调用了以后函数,caller 就是谁(全局作用域中调用以后函数 caller 值为 null)
function callerTest() {console.log(callerTest.caller)
}
callerTest() // 在全局作用域种调用以后函数,caller 的值为 null
function outer() {inner()
}
function inner() {console.log(inner.caller)
}
outer() // outer()调用了 inner,因而打印 outer()函数的源代码
function inner() {console.log(arguments.callee.caller) // 能够解除严密耦合
}
outer() // 后果不变,打印 outer()函数的源代码
- 函数在 严格模式 下运行时,拜访
arguments.callee
会报错- ES5 定义了
arguments.caller
属性,严格模式会报错,非严格模式始终是undefined
,该属性是为了辨别arguments.caller
和 函数的caller
。- 严格模式 不能为函数的
caller
属性赋值,会报错
函数属性和办法
每个函数都蕴含 2 个属性:length
和 prototype
length
示意函数心愿接管的 命名参数的个数
function nameLength(name) {return name}
function sumLength(sum1, sum2) {return sum1 + sum2}
function helloLength() {return 'Hello'}
console.log(nameLength.length, sumLength.length, helloLength.length) // 1,2,0
prototype
保留着 函数所有实例办法 且不可枚举 (应用for-in
无奈发现),每个函数都蕴含 3 个非继承而来的办法apply()
、call()
和 bind()
。
apply()
和 call()
的用处和后果雷同 —— 都是在特定的作用域中调用函数,apply()
接管 arguments 对象或数组实例,call()
接管每一个参数
function sumPrototype(num1, num2) {return num1 + num2}
apply()
接管 2 个参数:① 运行函数的作用域;② 参数数组(实例或 arguments 对象均可)
function applySum1(num1, num2) {return sumPrototype.apply(this, arguments) // 传入 arguments 对象
}
function applySum2(num1, num2) {return sumPrototype.apply(this, [num1, num2]) // 传入数组实例
}
console.log(applySum1(10, 10))
console.log(applySum2(10, 10))
call()
接管若干参数:① 运行函数的作用域;残余参数别离传入
function callSum(num1, num2) {return sumPrototype.call(this, num1, num2) // 别离传入每个参数
}
console.log(callSum(10, 10))
apply()
和 call()
真正弱小的中央在于 可能裁减函数运行的作用域
// vscode 是 node 运行环境,无奈辨认全局对象 window,测试时需做微调
window.color = 'red'
var o = {color: 'blue'}
function sayColor() {console.log(this.color)
}
sayColor() // red,此时 this 指向对象 window
sayColor().call(this) // red,此时 this 指向对象 window
sayColor().call(window) // red,此时 this 指向对象 window
sayColor().call(o) // blue,此时 this 指向对象 o
ES5
追加 bind()
办法,其 创立一个函数实例,其 this 被绑定到传给 bind() 函数的值
// vscode 是 node 运行环境,无奈辨认全局对象 window,测试时需做微调
window.color = 'red'
var o = {color: 'blue'}
function sayColor() {console.log(this.color)
}
var bindColor = sayColor.bind(o)
bindColor() // blue,此时 this 被绑定给对象 o
总结 & 问点
- 函数是什么?函数名是什么?
- 函数别离有哪几种申明形式?
- js 的函数有重载嘛?为什么?
- 函数申明与函数表达式有什么区别?
- 什么是函数的申明提前?
- 请写出 function:依据对象数组的某个对象进行排序
- 函数外部有哪些对象和属性?这些对象和属性别离有哪些特点或用法?
- 严格模式下,函数外部的对象或属性别离会有哪些限度?
- 函数有哪些属性?其实例办法都保留在哪里?
- 函数有哪些非继承而来的办法?别离有什么用法和作用?