みなさん、こんにちは。また会いましょう。
休日は一瞬で、年明けの初日は朝起きたくないので、遅刻しないように目を閉じて服を着ました。
大丈夫、大丈夫、要点をつかんで、元気を出してください!
序文
関数はすべてのプログラミング言語の重要な部分です。Es6が登場する前は、JavaScriptの関数構文はあまり変更されておらず、多くの問題とあいまいな慣行が残っており、一部の関数を実装するために多くのコードを作成する必要がありました。
関数パラメーターのデフォルト値
JavaScript関数には特別な場所があります。つまり、関数パラメーターで定義されているパラメーターの数に関係なく、任意の数のパラメーターを渡すことができます。ただし、場合によっては、パラメーターのみを入力できます。この場合でも、多くのロジックを書くとコードの冗長性につながります。幸い、Es6バージョンには関数のデフォルト値があります。
Es5コードとEs6コードを比較してみましょう
Es5はデフォルトパラメータを処理します
function person(name, age) {
name = typeof(name) != "undefined" ? name : `蛙人${+ new Date()}`
age = typeof(age) != "undefined" ? age : 24
}
person()
上記の例では、Es5はデフォルトのパラメーター値をこのように処理します。パラメーターが多い場合、このようなコードを記述すると非常に冗長になるため、Es6には関数パラメーターのデフォルト値があります。
Es6はデフォルトパラメータを処理します
function person(name = "蛙人", age = 24) {
console.log(name, age)
}
person() // 蛙人 24
person("张三", 30) // 张三 30
person(null, null) // null null
上記の例は、Es6で処理されるデフォルトのパラメーターです。コードが非常に単純化されていることがわかります。上記のコードは、パラメーターがnullで渡されていることを確認できます。デフォルトのパラメーターの場合、nullも有効な値です。この場合、関数パラメータが未定義の場合にのみ使用されます。デフォルト。
関数パラメーター式
デフォルトのパラメーター値に関して、最も興味深い機能は、非プリミティブ値がパラメーターに渡されること、またはデフォルトのパラメーターを函数
またはとして定義できることです变量
。
function defaultName() {
return "蛙人"
}
function person(name = defaultName()) {
console.log(name)
}
person("张三") // 张三
person() // 蛙人
デフォルトパラメータの式は、関数
person
が作成されるとすぐには実行されませんが、関数が呼び出されてパラメータが渡されないときに実行されることに注意してください。
上記の例では、パラメータが渡されない場合defaultName
、デフォルト値の関数が呼び出されます。
変数に渡されるデフォルトのパラメータを見てみましょう。
let defaultName = "蛙人"
function person(name = defaultName) {
console.log(name)
}
person("张三") // 张三
person() // 蛙人
function person(name, nickName = name) {
console.log(name, nickName)
}
person("张三") // 张三 张三
person("蛙人", "掘金蛙人") // 蛙人 掘金蛙人
上記の例では、前の関数が変数に置き換えられていることを除いて、最初のコードブロックをすべて理解できます。2番目のコードブロックのコードを見て、nickName
パラメーターのデフォルト値を最初のパラメーターname
パラメーターに設定します。これは、パラメーターのデフォルト値を参照するときに、前のパラメーターの値のみを引用できるようにするためです。関数パラメーターは定義された変数と同等です。背後にある変数は前の変数にアクセスできますが、現在のスコープ内でのみ、関数パラメーターは現在のスコープです。別の例を見てみましょう。
function person(name = nickName, nickName) {
console.log(name, nickName)
}
person("张三") // 张三 张三
上記の例では、最初のパラメータのデフォルト値は2番目のパラメータです。このとき、2番目の変数を定義する前にアクセスすると一時的なデッドゾーンが発生するため、実行時にエラーがスローされます。一時的なデッドゾーンがわからない私の最後の記事を読むことができます。「一目でわかるvar、let、constの違い」
関数パラメーターのデフォルト値が引数に与える影響
関数のデフォルトパラメータを使用する場合、argumentsオブジェクトの動作は以前とは異なります。
Es5非厳密モードで引数を使用する
Es5非厳密モードでは、パラメータという名前の関数の変更がarguments
オブジェクトに反映されます。arguments
取得されるのは、現在の関数の実際のパラメータです。arguments
非厳密モードでは、正式なパラメータとマッピング関係があります。 、仮パラメータarguments
の変更は変更に続きます。
function test(a, b) {
console.log(a == arguments[0]) // true
console.log(b == arguments[1]) // true
a = "a"
b = "b"
console.log(arguments) // ["a", "b"]
}
test(1, 2)
上記の例では、非厳密モードでは、名前付きパラメーターの変更がarguments
オブジェクトに同期的に更新されます。ときにa
パラメータが変化し、それがにマップされますarguments[0]
オブジェクト。
Es5strictモードで引数を使用する
ストリクトモードを見てみましょうarguments
function test(a, b) {
'use strict';
console.log(arguments) // [1, 2]
b = 10
console.log(arguments) // [1, 2]
}
test(1, 2)
上記の例は厳密モードです。パラメータを変更しb
てarguments
オブジェクトを再度出力すると、それはまだ初期値であることがわかります。厳密モードではJavaScript
、arguments
オブジェクトの紛らわしい動作はキャンセルされます。パラメータがどのように変更されても、arguments
オブジェクトは変更されなくなります。
Es6の引数に対するデフォルトのパラメーター値の使用の影響
Es6では、関数がデフォルトのパラメーター値を使用する場合arguments
、オブジェクトの動作はJavaScript
strictモードの動作と一致します。
function test(a, b = 2) {
a = 12
b = 10
console.log(arguments) // [1]
}
test(1)
上記の例では、arguments
オブジェクトが実際のパラメーターを取得している[1]
ため、arguments
オブジェクトが出力されます。実際のパラメーターパラメーターが値を渡すため、arguments
オブジェクトの値は1つだけであることがわかります。2番目のポイントを見るa
とb
、パラメーター値は変更されarguments
ていますが、オブジェクトは変更されていません如果一个函数使用了默认参数值,那么arguments对象的行为都将与JavaScript中的严格模式下保持一致
。これは上記のとおりです。
名前のないパラメータの処理
jsの関数パラメーターの数は任意です。渡される数が少ない場合、デフォルトパラメーターの機能により、関数宣言のコードを効果的に簡略化できます。より多くの番号が渡されると、Es6はより良いソリューションも提供します。
Es5で名前のないパラメータを取得する
function test(a, b, c) {
console.log(arguments) // [1, 2, 3]
}
test(1, 2, 3)
上記の例でarguments
は、オブジェクトはすべてのパラメーターを取得することもできますが、2番目のパラメーターの後にすべてのパラメーターを取得する場合は、ループしてそれらを除外する必要があります。
Es6で名前のないパラメータを取得する
function test(...parmas) {
console.log(params) // [1, 2, 3, 4]
}
test(1, 2, 3, 4)
function test(a, b, ...params) {
console.log(params)
}
test(1, 2, 3, 4)
上記の例では、最初のコードブロックはEs6のすべてのパラメーターを実装していますが、それでもニーズを満たしていません。次に、達成する2番目のコードブロックのコードを見てください。2番目のパラメーターの後にすべてのパラメーターがあります。
名前のないパラメータへのEs6アクセスの欠点
まず、各関数は1つのget変数パラメーターのみを宣言でき、関数の最後にのみ配置できます。そうしないと、エラーが報告されます。
function test(...params, a, b) {
}
test()
上記の例では、エラーがスローされます。無数のパラメーターが宣言された後は、後でパラメーターを宣言し続けることはできません。
もう1つのポイントはsetter
、setter
関数は関数を受け取るだけであり、不定パラメーターとして書き込まれた後は配列になり、プログラムが異常になるため、オブジェクトリテラルで不定パラメーターを定義できないことです。
let obj = {
set name(...params) {
}
}
関数名属性
でJavaScript
すべての機能が持つname
プロパティを、プロパティは関数名の文字列に格納されます。名前のない関数にはまだname
属性があり、name
属性値は空の文字列です。
function person() {}
let test = function() {}
console.log(person.name) // person
console.log(test.name) // test
上記の例では、person
関数のname
属性値は「person」であり、宣言時の関数の名前に対応しています。無名関数式test
関数のname
名前は、無名関数に割り当てられた変数に対応しています。
name属性の特殊なケース
もともと各関数のname
名前は現在の関数名に対応していると思っていましたが、後で気づきました。関数の特殊なケースを見てみましょう
var person = {
get getName() {
return "蛙人"
}
}
console.log(Object.getOwnPropertyDescriptor(person, 'getName').get.name) // get getName
function test() {}
console.log(test.bind().name) // bound test
上記の例でperson.getName
は、これは値関数getter
であるため、その関数名get getName
、関数の場合setter
、名前には接頭辞が付きますset
。bind
関数を作成することにより、その名前の前に「bound」が付けられます。
矢印機能
Es6の矢印関数は、最も興味深い機能の1つです。矢印関数は、矢印を=>
使用して関数を定義する新しい構文ですが、従来のJavaScript
関数とは多少異なります。詳細については、次の点を参照してください。
- ノー
this
、super
、arguments
new
キーワードで呼び出すことはできません- プロトタイプなし
prototype
this
方向を変えることはできません- 繰り返される名前付きパラメーターをサポートしていません
矢印関数と従来の関数には、変更されていないname属性があります。
矢印関数の構文
let person = () => "蛙人"
// 相当于下代码
function person() {
return "蛙人"
}
上記の例では、矢印関数の右側の式が評価されると、すぐに戻ります。
矢印関数パラメーター
let getName = val => val
// 相当于下代码
function getName(val) {
return val
}
矢印関数にパラメータが1つしかない場合は、括弧を省略してパラメータ名を直接書き込むことができます。2つ以上のパラメーターを渡す場合は、括弧を使用する必要があります。次の例を見てください
let sum = (a, b) => a + b
// 相当于下代码
function sun(a, b) {
return a + b
}
オブジェクトリテラルを返したい場合は、次のように書くことができます
let getObj = () => ({name: "蛙人", age: 24}) // {name: "蛙人", age: 24}
// 相当于下代码
function getObj() {
return {
name: "蛙人",
age: 24
}
}
矢印機能にはこれがありません
矢印関数のthis
値は、関数外の非矢印関数の値によって異なりますthis
。上位層がまだ矢印関数である場合は、検索を続けます。見つからない場合this
は、window
オブジェクトです。
let person = {
test: () => {
console.log(this)
},
fn() {
return () => {
console.log(this)
}
}
}
person.test() // window
person.fn()() // person对象
上記の例では、矢印がないことがはっきりとわかりますthis
。したがってthis
、外側の非矢印関数関数のみが検索されます。
矢印関数にはarguments
オブジェクトがありません
同様に、矢印関数にはarguments
オブジェクトがありませんが、外側のレイヤーに矢印以外の関数のレイヤーがある場合arguments
、次のように外側の関数のオブジェクトを検索します。
let test1 = () => console.log(arguments) // 执行该函数会抛出错误
function test2(a, b, c) {
return () => {
console.log(arguments) // [1, 2, 3]
}
}
test2(1, 2, 3)()
上記の例では、現在の矢印関数にarguments
オブジェクトがないことがはっきりとわかりますが、その外層に移動して、矢印関数ではない関数を見つけます。注意:箭头函数找arguments对象只会找外层非箭头函数的函数,如果外层是一个非箭头函数的函数如果它也没有arguments对象也会中断返回,就不会在往外层去找了
。次の例を見てください
function test(a) {
return function() {
return () => {
console.log(arguments) // []
}
}
}
test(1)()()
上記の例でわかるように、内部の矢印関数は、外側のレイヤーで矢印関数ではない関数を見つけ、外側の関数にarguments
オブジェクトがあるかどうかに関係なく戻ります。それが非矢印関数である場合にのみ、外層が矢印関数である場合、それは外層を探し続けます。
矢印関数はnew
キーワードで宣言できません
let test = () => {}
new test() // 抛出错误,找不到constructor对象
矢印関数にはプロトタイプがありませんprototype
矢印関数にはプロトタイプがないことを忘れないでください。インタビュアーが尋ねる可能JavaScript
性がありprototype
ます。のすべての関数に属性がありますか?
let test = () => {}
test.prototype // undefined
矢印機能はthis
方向を変えることができません
let person = {}
let test = () => console.log(this)
test.bind(person)()
test.call(person)
test.apply(person)
上記の例でthis
は、ポインティングを変更する方法はエラーをスローしませんが、無効であり、this
ポインティングを変更することはできません。
矢印関数は名前付きパラメーターを繰り返すことはできません
let sum = (a, a) => {} // 抛出错误,参数不能重复