1. 程式人生 > 實用技巧 >python flask-session的一些知識

python flask-session的一些知識

普通函式和箭頭函式的區別

箭頭函式的this指向規則:

1、箭頭函式沒有prototype(原型),所以箭頭函式本身沒有this

let a = () =>{};
console.log(a.prototype); // undefined

2、箭頭函式的this指向在定義的時候繼承自外層第一個普通函式的this

下面例子中在一個函式中定義箭頭函式,然後在另一個函式中執行箭頭函式。

let a,
barObj = { msg: 'bar的this指向' },
fooObj = { msg: 'foo的this指向' };
bar.call(barObj); // 將bar的this指向barObj
foo.call(fooObj); // 將foo的this指向fooObj function foo() { a(); // 結果:{ msg: 'bar的this指向' } } function bar() { a = () => { console.log(this, 'this指向定義的時候外層第一個普通函式'); // }; // 在bar中定義 this繼承於bar函式的this指向 }

從上面例子中可以得出兩點:

  • 箭頭函式的this指向定義時所在的外層第一個普通函式,跟使用位置沒有關係;
  • 被繼承的普通函式的this指向改變,箭頭函式的this指向會跟著改變。

3、不能直接修改箭頭函式的this指向

上個例子中的foo函式修改一下,嘗試直接修改箭頭函式的this指向。

let fnObj = { msg: '嘗試直接修改箭頭函式的this指向' };
function foo() {
  a.call(fnObj); // 結果:{ msg: 'bar的this指向' }
}

很明顯,call顯示繫結this指向失敗了,包括applybind都一樣。它們(call、aaply、bind)會預設忽略第一個引數,但是可以正常傳參。

然後我又通過隱式繫結來嘗試同樣也失敗了,new呼叫會報錯,這個稍後再說。

SO,箭頭函式不能直接修改它的this指向。

幸運的是,我們可以通過間接的形式來修改箭頭函式的指向:

去修改被繼承的普通函式的this指向,然後箭頭函式的this指向也會跟著改變,這在上一個例子中有演示。

bar.call(barObj);// 將bar普通函式的this指向barObj 然後內部的箭頭函式也會指向barObj

4、箭頭函式外層沒有普通函式,嚴格模式和非嚴格模式下它的this都會指向window(全域性物件)

既然箭頭函式的this指向在定義的時候繼承自外層第一個普通函式的this,那麼,當箭頭函式外層沒有普通函式時,它的this會指向哪裡?

普通函式的預設繫結規則是:在非嚴格模式下,預設繫結的this指向全域性物件,嚴格模式下this指向undefined

如果箭頭函式外層沒有普通函式繼承,它this指向的規則:經過測試,箭頭函式在全域性作用域下,嚴格模式和非嚴格模式下它的this都會指向window(全域性物件)。

Tip:測試的時候發現嚴格模式在中途宣告無效,必須在全域性/函式的開頭宣告才會生效:

a = 1;
'use strict'; // 嚴格模式無效 必須在一開始就宣告嚴格模式
b = 2; // 不報錯

箭頭函式的this指向全域性時,使用arguments會報未宣告的錯誤,指向普通函式時,它的argumens繼承於該普通函式

如果箭頭函式的this指向window(全域性物件),使用arguments會報錯,未宣告arguments

let b = () => {
  console.log(arguments);
};
b(1, 2, 3, 4); // Uncaught ReferenceError: arguments is not defined

PS:如果你聲明瞭一個全域性變數為arguments,那就不會報錯了,但是你為什麼要這麼做呢?

如果箭頭函式的this指向普通函式,它的argumens繼承於該普通函式。

function bar() {
  console.log(arguments); // ['外層第二個普通函式的引數']
  bb('外層第一個普通函式的引數');
  function bb() {
    console.log(arguments); // ["外層第一個普通函式的引數"]
    let a = () => {
      console.log(arguments, 'arguments繼承this指向的那個普通函式'); // ["外層第一個普通函式的引數"]
    };
    a('箭頭函式的引數'); // this指向bb
  }
}
bar('外層第二個普通函式的引數');

那麼應該如何來獲取箭頭函式不定數量的引數呢?答案是:ES6rest引數(…擴充套件符)

rest引數獲取函式的多餘引數

這是ES6的API,用於獲取函式不定數量的引數陣列,這個API是用來替代arguments的,API用法如下:

let a = (first, ...abc) => {
  console.log(first, abc); // 1 [2, 3, 4]
};
a(1, 2, 3, 4);

上面的例子展示了,獲取函式除第一個確定的引數,以及用一個變數接收其他剩餘引數的示例。

也可以直接接收函式的所有引數,rest引數的用法相對於arguments的優點:

(1)箭頭函式和普通函式都可以使用。

(2)更加靈活,接收引數的數量完全自定義。

(3)可讀性更好,引數都是在函式括號中定義的,不會突然出現一個arguments

(4)rest是一個真正的陣列,可以使用陣列的API。而arguments是一個類陣列的物件,如果我們需要使用陣列的API,需要使用擴充套件符/Array.from來將它轉換成真正的陣列。

rest引數有兩點需要注意:

  • rest必須是函式的最後一位引數:
let a = (first, ...rest, three) => {
  console.log(first, rest,three); // 報錯:Rest parameter must be last formal parameter
};
a(1, 2, 3, 4);
  • 函式的length屬性,不包括rest引數
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

箭頭函式不能作為建構函式,不能使用new

無論箭頭函式的this指向哪裡,使用new呼叫箭頭函式都會報錯,因為箭頭函式沒有constructor

let a = () => {};
let b = new  a(); // a is not a constructor

箭頭函式不支援new.target

new.target是ES6新引入的屬性,普通函式如果通過new呼叫,new.target會返回該函式的引用。此屬性主要用於確定建構函式是否為new呼叫的。

  • 箭頭函式的this指向全域性物件,在箭頭函式中使用箭頭函式會報錯
let a = () => {
  console.log(new.target); // 報錯:new.target 不允許在這裡使用
};
a();
  • 箭頭函式的this指向普通函式,它的new.target就是指向該普通函式的引用。
new bb();
function bb() {
  let a = () => {
    console.log(new.target); // 指向函式bb:function bb(){...}
  };
  a();
}

箭頭函式不支援重新命名函式引數,普通函式的函式引數支援重新命名

如下示例,普通函式的函式引數支援重新命名,後面出現的會覆蓋前面的,箭頭函式會丟擲錯誤:

function func1(a, a) {
  console.log(a, arguments); // 2 [1,2]
}

var func2 = (a,a) => {
  console.log(a); // 報錯:在此上下文中不允許重複引數名稱
};
func1(1, 2); 
func2(1, 2);

箭頭函式相對於普通函式語法更簡潔優雅

  • 箭頭函式都是匿名函式,並且都不用寫function
  • 只有一個引數的時候可以省略括號:
var f = a => a; // 傳入a 返回a
  • 函式只有一條語句時可以省略{}return
var f = (a,b,c) => a; // 傳入a,b,c 返回a
  • 簡化程式碼,讓你的函式更優雅:
[1,2,3].map(function (x) {
  return x * x;
}); // 普通函式寫法 
[1,2,3].map(x => x * x); // 箭頭函式只需要一行

箭頭函式不能當做Generator函式,不能使用yield關鍵字

箭頭函式的注意事項及不適用場景

箭頭函式的注意事項

  • 一條語句返回物件字面量,需要加括號,或者直接寫成多條語句的return形式,否則像下面演示的一樣,花括號會被解析為多條語句的花括號,不能正確解析
var func1 = () => { foo: 1 }; // 想返回一個物件,花括號被當成多條語句來解析,執行後返回undefined
var func2 = () => ({foo: 1}); // 用圓括號是正確的寫法
var func2 = () => {
  return {
    foo: 1 // 更推薦直接當成多條語句的形式來寫,可讀性高
  };
};
  • 箭頭函式在引數和箭頭之間不能換行!
var func = ()
           => 1;  // 報錯: Unexpected token =>
  • 箭頭函式的解析順序相對靠前 MDN: 雖然箭頭函式中的箭頭不是運算子,但箭頭函式具有與常規函式不同的特殊運算子優先順序解析規則
let a = false || function() {}; // ok
let b = false || () => {}; // Malformed arrow function parameter list
let c = false || (() => {}); // ok

箭頭函式不適用場景

1、this的意外指向

  • 定義字面量方法
const obj = {
  array: [1, 2, 3],
  sum: () => {
    // 根據上文學到的:外層沒有普通函式this會指向全域性物件
    return this.array.push('全域性物件下沒有array,這裡會報錯'); // 找不到push方法
  }
};
obj.sum();

上述例子使用普通函式或者ES6中的方法簡寫來定義方法,就沒有問題了:

// 這兩種寫法是等價的
sum() {
  return this.array.push('this指向obj');
}
sum: function() {
  return this.array.push('this指向obj');
}
  • 回撥函式的動態this

下文是一個修改dom文字的操作,因為this指向錯誤,導致修改失敗:

const button = document.getElementById('myButton');
button.addEventListener('click', () => {
    this.innerHTML = 'Clicked button'; // this又指向了全域性
});

相信你也知道了,改成普通函式就成了。

2、考慮程式碼的可讀性,使用普通函式

  • 函式體複雜:具體表現就是箭頭函式中使用多個三元運算子號,就是不換行,非要在一行內寫完,非常噁心!

  • 行數較多

  • 函式內部有大量操作


轉自:https://blog.csdn.net/m0_37686205/article/details/88776259

總結

  • 箭頭函式的this永遠指向其上下文的this,任何方法都改變不了其指向
  • 普通函式的this指向呼叫它的那個物件