blog

javascript上級プログラミング学習ノート|5.5.

jsエンジンはコードの先頭でコードの実行を開始し、パーサは宣言された関数を関数宣言のリフティング処理によってソースツリーの先頭に持ち上げ、どのコードの実行でも利用できるようにします。 引数は......

Jan 15, 2021 · 6 min. read
シェア

Function

  • 関数はオブジェクトであり、すべての関数は関数型のインスタンスで、他の参照型のようにプロパティとメソッドを持ちます。
  • 関数名は関数オブジェクトへのポインターであり、関数に束縛されるものではありません。

宣言メソッド

// 1.関数宣言の定義
function sum(num1, num2) {
 return num1 + num2
}
// 2.関数式の定義
var sum = function (num1, num2) {
 return num1 + num2
}
// 3.Functionコンストラクタの定義
/* コンストラクタ定義を使用することは推奨されない。*/
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エンジンはコードの先頭でコードの実行を開始し、パーサは宣言された関数を関数宣言のリフティング処理によってソースツリーの先頭に引き上げあらゆるコードの実行に利用できるようにします。一方、関数式は、パーサが実行のために解釈するコード行まで実行を待たなければなりません。

関数宣言と関数式の唯一の違いは、関数を変数経由でアクセスできる場合です

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

例では、オブジェクトの配列をオブジェクトのプロパティの 1 つに従って並べ替えたいとします:

/**
 * オブジェクトの配列をオブジェクトキーの1つでソートする。
 * @param {String} 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つの内部特殊オブジェクト引数とthis、そして1つの内部属性呼び出し元を持ちます。

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引数オブジェクトを所有する関数を指定する
}
var trueFactorial = factorial // 関数へのポインタ
factorial = function () {
 return 0
}
console.log(trueFactorial(5)) // 120,すでに引数を使用している.callee関数内のコードを関数名から切り離し、正しく計算できるようにする
console.log(factorial(5)) // 0

thisは、関数が実行される環境オブジェクト、つまり thisの値を参照します。

// vscodeノード環境では、グローバル・オブジェクト・ウィンドウを認識できないので、テスト用に微調整する必要がある。
window.color = 'red'
var o = { color: 'blue' }
function sayColor() {
 console.log(this.color)
}
sayColor() // red,この場合、thisはオブジェクト・ウィンドウを指している。
o.sayColor = sayColor
o.sayColor() // blue,この場合、thisはオブジェクトoを指す。

ES5ではcaller属性が定義されており、現在の関数を呼び出した関数への参照を保持します。

function callerTest() {
 console.log(callerTest.caller)
}
callerTest() // グローバル・スコープで現在の関数を呼び出すと、呼び出し元の値は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と関数の呼び出し元を区別するために、arguments.callerプロパティを定義しています。arguments.callerプロパティは、厳密モードではエラーとなり、非厳密モードでは常に未定義となります。
  • ストリクト・モードでは、関数の呼び出し元属性に値を割り当てることができません。

関数のプロパティとメソッド

各関数には、長さとプロトタイプの2つの属性があります。

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

各関数には、apply()、call()、bind()の3つの継承されないメソッドがあります

apply()とcall()の目的と結果は同じです。どちらも特定のスコープで関数を呼び出しますが、apply()は引数オブジェクトまたは配列インスタンスを受け取り、call()は各引数を受け取ります。

function sumPrototype(num1, num2) {
 return num1 + num2
}

apply()は2つの引数を取ります。(i) 関数を実行するスコープと、(ii) 引数の配列です。

function applySum1(num1, num2) {
 return sumPrototype.apply(this, arguments) // 引数を渡す
}
function applySum2(num1, num2) {
 return sumPrototype.apply(this, [num1, num2]) // 入力配列の例
}
console.log(applySum1(10, 10))
console.log(applySum2(10, 10))

call() はいくつかの引数を取ります: (1) 関数を実行するスコープ。

function callSum(num1, num2) {
 return sumPrototype.call(this, num1, num2) // 各パラメーターを個別に渡す
}
console.log(callSum(10, 10))

apply()とcall()の真の威力は、関数の操作範囲を拡大できることにあります。

// vscodeノード環境では、グローバル・オブジェクト・ウィンドウを認識できないので、テスト用に微調整する必要がある。
window.color = 'red'
var o = { color: 'blue' }
function sayColor() {
 console.log(this.color)
}
sayColor() // red,この場合、thisはオブジェクト・ウィンドウを指している。
sayColor().call(this) // red,この場合、thisはオブジェクト・ウィンドウを指している。
sayColor().call(window) // red,この場合、thisはオブジェクト・ウィンドウを指している。
sayColor().call(o) // blue,この場合、thisはオブジェクトoを指す。

ES5ではbind()メソッドが追加され、thisがbind()関数に渡された値にバインドされる関数インスタンスが生成されます。

// vscodeノード環境では、グローバル・オブジェクト・ウィンドウを認識できないので、テスト用に微調整する必要がある。
window.color = 'red'
var o = { color: 'blue' }
function sayColor() {
 console.log(this.color)
}
var bindColor = sayColor.bind(o)
bindColor() // blue,この時点で thisはオブジェクトoにバインドされている。

&

  • 関数とは何ですか?関数の名前は何ですか?
  • 関数の宣言方法にはどのようなものがありますか?
  • js関数にはオーバーロードがありますか?なぜですか?
  • 関数宣言と関数式の違いは何ですか?
  • 関数の事前宣言とは何ですか?
  • Write 関数: オブジェクトの配列を
  • 関数内部のオブジェクトや属性にはどのようなものがありますか?それぞれのオブジェクトや属性の特徴や用途は何ですか?
  • ストリクト・モードでは、関数内のオブジェクトやプロパティにはどのような制限がありますか?
  • 関数のプロパティとは何ですか?関数のインスタンス・メソッドはどこに格納されていますか?
  • 関数の非相続メソッドとは何ですか?それぞれの使い方と目的は何ですか?
Read next

ファクトリーメソッド・パターン」を学ぶための記事は、あなたには負けない!

まず褒めてから読む、なんと良い習慣でしょう。\n\n\n今日も、「自動車工場の開発と自動車用ソフトウェアの生産」というケースを取り上げて説明します。\n当初は、自動車工場が始まったばかりで、大きな名前ではなく、売上高は限られ、ボスは唯一の国産車を生産し、自動車用ソフトウェアの生産は、この時点で設計された "シンプルな工場モデル "を使用しています!

Jan 15, 2021 · 4 min read