欢送关注前端小讴的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}// 第二个函数等价于下列代码 -> 笼罩了援用第一个函数的变量addSomeNumberaddSomeNumber = 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 functionvar 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) // 20function 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指向对象windowo.sayColor = sayColoro.sayColor() // blue,此时this指向对象o
ES5 定义了 caller
属性,保留着调用以后函数的函数援用—— 谁调用了以后函数,caller 就是谁(全局作用域中调用以后函数 caller 值为 null)
function callerTest() { console.log(callerTest.caller)}callerTest() // 在全局作用域种调用以后函数,caller 的值为 nullfunction 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指向对象windowsayColor().call(this) // red,此时this指向对象windowsayColor().call(window) // red,此时this指向对象windowsayColor().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:依据对象数组的某个对象进行排序
- 函数外部有哪些对象和属性?这些对象和属性别离有哪些特点或用法?
- 严格模式下,函数外部的对象或属性别离会有哪些限度?
- 函数有哪些属性?其实例办法都保留在哪里?
- 函数有哪些非继承而来的办法?别离有什么用法和作用?