乐趣区

关于javascript:javascript高级程序设计学习笔记-55Function类型

欢送关注前端小讴的 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 个非凡对象 argumentsthis,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 个属性:lengthprototype

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:依据对象数组的某个对象进行排序
  • 函数外部有哪些对象和属性?这些对象和属性别离有哪些特点或用法?
  • 严格模式下,函数外部的对象或属性别离会有哪些限度?
  • 函数有哪些属性?其实例办法都保留在哪里?
  • 函数有哪些非继承而来的办法?别离有什么用法和作用?
退出移动版