JavaScript 解密 —— 函数初步

微信扫一扫,分享到朋友圈

JavaScript 解密 —— 函数初步

在理解函数作为 一等对象
前,先列举下 JavaScript 中对象支持的操作:

  • 可以通过 {}
    字面量创建
  • 可以被赋值给变量、数组项,可以作为其他对象的属性

    var ninja = {}  // 赋值给变量
    ninjaArray.push({})  // 作为数组项
    ninja.data = {}  // 作为其他对象的属性
    
  • 可以作为函数的参数或返回值

  • 可以拥有支持动态创建与赋值的属性

    function hide(ninja) {
    ninja.visibility = false
    }
    hide({})  // 对象作为函数参数
    function returnNewNinja() {
    return {}  // 对象作为函数返回值
    }
    var ninja = {}
    ninja.name = "Hanzo"  // 动态创建的属性
    

函数作为一等对象

JavaScript 中的函数拥有作为对象的所有特性,因此可以像对待任何其他对象一样对其进行使用。

  • 通过字面量创建: function ninjaFunction() {}
  • 将函数赋值给变量: var ninjaFunction = function() {}
  • 数组中加入函数作为数据项: ninjaArray.push(function() {})
  • 函数作为对象的属性: ninja.data = function() {}
  • 函数作为其他函数的参数或返回值

    function call(ninjaFunction) {
    ninjaFunction()
    }
    call(function() {})  // 函数作为参数
    function returnNewNinjaFunction() {
    return function() {}  // 函数作为返回值
    }
    
  • 函数可以拥有支持动态创建和赋值的属性

    var ninjaFunction = function () {}
    ninjaFunction.name = "Hanzo"
    

函数即对象,只不过拥有一项额外的特性(能够被调用)以完成一些特定的动作。任何可以对对象做出的操作,同样可以应用在函数身上。

Callback functions

回调函数即在后续的某个指定的时间节点被其他代码调用(call back)的函数。

var text = "Domo arigato"
function useless(ninjaCallback) {
console.log("In useless function")
return ninjaCallback()
}
function getText() {
console.log("In getText function")
return text
}
console.log(useless(getText))
// In useless function
// In getText function
// Domo arigato

或者

var text = 'Domo arigato'
function useless(ninjaCallback) {
return ninjaCallback()
}
console.log(useless(function() { return text }))
// Domo arigato

回调函数在数组排序中的使用:

var values = [0, 3, 2, 5, 7, 4, 8, 1]
values.sort(function(value1, value2){
return value1 - value2
})

Self-memoizing functions

memoization
是指构建一个特殊的函数,该函数可以将之前计算过的值缓存在自己内部,之后再做同样的计算时则可以直接读取缓存的值而不必重新计算。

function isPrime(value) {
if (!isPrime.answers) {
isPrime.answers = {}
}
if (isPrime.answers[value] !== undefined) {
return isPrime.answers[value]
}
var prime = value !== 1
for (var i = 2; i < value; i++) {
if (value % i === 0) {
prime = false
break
}
}
return isPrime.answers[value] = prime
}
console.log(isPrime(5))
console.log(isPrime.answers)
// true
// { '5': true }

二、函数定义

JavaScript 提供以下几种定义函数的方式:

function myFun() { return 1 }
myArg => myArg * 2
new Function('a', 'b', 'return a + b')
function* myGen() { yield 1 }

函数声明是最基础的定义函数的方式,其基本格式如下:

function myFunctionName(myFirstArg, mySecondArg) {
myStatement1
myStatement2
}

函数声明代码可以出现在另一个函数内部:

function ninja() {
function hiddenNinja() {
return "ninja here"
}
return hiddenNinja()
}

函数表达式

作为 JavaScript 中的一等对象,函数可以通过字面量创建,可以赋值给变量和对象属性,可以作为另一个函数的参数或返回值。

也因此可以将其作为表达式使用,即成为其他代码语句的一部分(比如放在赋值语句的等号右边、充当参数或返回值等)

var myFunc = function() {}
myFunc(function() {  // 作为参数
return function() {}  // 作为返回值
})

函数表达式甚至可以放置在通常应该使用函数标识符的地方,在声明的同时立即完成调用,称为 immediate function

myFunctionName(3)  // 普通调用
(function() {})(3)  // immediate call
+function () {} ()
-function () {} ()
!function () {} ()
~function () {} ()

Arrow function

在很多情况下,arrow function 可以看作对普通函数表达式的简化。如之前的排序示例:

var values = [0, 3, 2, 5, 7, 4, 8, 1]
values.sort(function(value1, value2){
return value1 - value2
})

使用 arrow function 则可以改为如下形式:

var values = [0, 3, 2, 5, 7, 4, 8, 1]
values.sort((value1, value2) => value1 - value2)

arrow function 最简单的语法形式为 param => expression
,一个基本示例如下:

var greet = name => "Greetings, " + name
console.log(greet('Oishi'))  // Greetings, Oishi

更复杂一点的形式如:

var greet = name => {
var helloString = 'Greetings, '
return helloString + name
}
console.log(greet('Oishi'))  // Greetings, Oishi

参数

Rest prarmeters

function multiMax(first, ...remainingNumbers){
var sorted = remainingNumbers.sort(function(a, b){
return b - a
})
return first * sorted[0]
}
console.log(multiMax(3, 1, 2, 3))  // 9

Default parameters

function performAction(ninja, action = "skulking") {
return ninja + " " + action
}
console.log(performAction("Fuma"))  // Fuma skulking
console.log(performAction("Yagyu", "sneaking"))  // Yagyu sneaking

甚至可以这样写:

function performAction(ninja, action = "skulking",
message = ninja + " " + action) {
return message
}
console.log(performAction("Yoshi"))  // Yoshi skulking

三、函数调用

作为“函数”调用

function ninja(name) { console.log(name) }
ninja('Hattori')  // Hattori
var samurai = function(name) { console.log(name) }
samurai('Hattori');  // Hattori
(function(name) { console.log(name) })('Hattori')  // Hattori

作为方法调用:

var ninja = {}
ninja.skulk = function() {}
ninja.skulk()

作为方法调用与作为函数调用的区别:

function whatsMyContext() {
return this
}
console.log(whatsMyContext() === global)  // true
var getMyThis = whatsMyContext
console.log(getMyThis() === global)  // true
var ninja1 = {
getMyThis: whatsMyContext
}
console.log(ninja1.getMyThis() === ninja1)  // true
var ninja2 = {
getMyThis: whatsMyContext
}
console.log(ninja2.getMyThis() === ninja2)  // true

作为构造器函数:

function whatsMyContext(){ return this }
new whatsMyContext()

注意与 函数构造器
(如 new Function('a', 'b', 'return a + b')
)的区别:函数构造器用来从字符串中动态地创建函数,而构造器函数则用来创建对象实例。

构造器函数在调用时一般会执行以下操作:

this
new
function Ninja() {
this.skulk = function() {
return this
}
}
var ninja1 = new Ninja()
console.log(ninja1.skulk() === ninja1)  // true
var ninja2 = new Ninja()
console.log(ninja2.skulk() === ninja2)  // true

若构造器函数的定义中本身具有返回值,则分为两种情况:

  • 若构造器的定义中返回了一个非对象值(字符串、数字等),则该返回值被忽略,由构造器创建的 this
    对象被返回作为 new
    表达式的值
  • 若构造器的定义中返回了一个对象,则该对象作为 new 表达式的值,由构造器创建的 this
    对象则被忽略

    function Ninja() {
    this.skulk = function() {
    return true
    }
    return 1
    }
    var ninja = new Ninja()
    console.log(ninja)  // Ninja { skulk: [Function]  }
    console.log(ninja.skulk())  // true
    
var puppet = {
rules: false
}
function Emperor() {
this.rules = true
return puppet
}
var emperor = new Emperor()
console.log(emperor)  // { rules: false  }
console.log(emperor.rules)  // false

apply
call
方法:

function juggle() {
var result = 0
for (var n = 0; n < arguments.length; n++) {
result += arguments[n]
}
this.result = result
}
var ninja1 = {}
var ninja2 = {}
juggle.apply(ninja1, [1,2,3,4])
juggle.call(ninja2, 5,6,7,8)
console.log(ninja1.result)  // 10
console.log(ninja2.result)  // 26

发现数据结构之美-栈

上一篇

JavaScript 解密 —— 函数进阶(闭包与生成器)

下一篇

你也可能喜欢

JavaScript 解密 —— 函数初步

长按储存图像,分享给朋友