function後面直接跟括號,中間沒有函數名的就是匿名函數。javascript
let fn = function() { console.log('我是fn') } let fn2 = fn console.log(fn.name) //fn console.log(fn2.name)//fn,fn和fn2指向的是同一個function。
function後面有函數名字的,不是直接跟括號的的就是具名函數。
若是把一個具名函數賦值給一個變量,那麼這個具名函數的做用域就不是window了。html
let fn = function fn1() { console.log('function') } console.log(fn.name) //fn1 console.log(fn1,name) // ReferenceError: fn1 is not defined
箭頭函數是es6知識點,具備如下幾個特色:java
let fn = e => e+1 console.log(fn(1)) //2 let fn1 = (i,y) => i+y console.log(fn1(2,3)) //5 let fn2 = (i,y) => { i+=1; y+=2; return i+y } console.log(fn2(5,6)) //13
靜態做用域又叫作詞法做用域,採用詞法做用域的變量叫詞法變量。詞法變量有一個在編譯時靜態肯定的做用域。詞法變量的做用域能夠是一個函數或一段代碼,該變量在這段代碼區域內可見(visibility);在這段區域之外該變量不可見(或沒法訪問)。詞法做用域裏,取變量的值時,會檢查函數定義時的文本環境,捕捉函數定義時對該變量的綁定。
詞法做用域:變量的做用域是在定義時決定而不是執行時決定,也就是說詞法做用域取決於源碼,經過靜態分析就能肯定,所以詞法做用域也叫作靜態做用域。 with和eval除外,因此只能說JS的做用域機制很是接近詞法做用域(Lexical scope)。es6
經過詞法做用域樹能判斷變量指向關係,可是不能判定變量的值,變量的值還須要根據執行順序進一步做出判斷,看一下例子:ajax
由於JavaScript採用的是詞法做用域,bian'liang的做用域基於函數建立的位置,跟調用時的位置無關。數組
var i = 1, j = 2, k = 3; function a(o, p, x, q) { var x = 4; alert(i); function b(r, s) { var i = 11, y = 5; alert(i); function c(t) { var z = 6; alert(i); }; var d = function() { alert(y); }; c(60); d(); }; b(40, 50); } a(10, 20, 30); //1 11 11 5
/** * 模擬創建一棵語法分析樹,存儲function內的變量和方法 */ var SyntaxTree = { // 全局對象在語法分析樹中的表示 window: { variables:{ i:{ value:1}, j:{ value:2}, k:{ value:3} }, functions:{ a: this.a } }, a:{ variables:{ x:'undefined' }, functions:{ b: this.b }, scope: this.window }, b:{ variables:{ i:'undefined' y:'undefined' }, functions:{ c: this.c, d: this.d }, scope: this.a }, c:{ variables:{ z:'undefined' }, functions:{}, scope: this.b }, d:{ variables:{}, functions:{}, scope: { scope: this.b } } };
/** * 活動對象:函數執行時建立的活動對象列表 */ let ActiveObject = { window: { variables: { i: { value: 1 } j: { value: 2 } k: { value: 3 } }, functions: { a: this.a } } a: { variables: { x: { vale: 4 }, functions: { b: this.b }, scope: this.window, params: { o: { value: 10 }, p: { value: 20 }, x: this.variables.x q: { vale: 'undefined' } }, arguments: [this.params.o, this.params.p, this.params.x] } } b: { variables: { i: { vale: 11 }, y: { vale: 5 }, }, functions: { c: this.c, d: this.d }, params: { r: { value: 40 } s: { value: 50 } }, arguments: [this.params.r, this.params.scope] scope: this.a } c: { variables: { z: { value: 6 }, functions: {}, params: { t: { value: 60 } }, arguments: [this.params.t] scope: this.b } } d: { variables: {}, functions: {}, params: {}, arguments: [] this.scope: this.b } }
進入call stack 時的一些規則:app
函數的全部形參(若是咱們是在函數執行上下文中)異步
全部函數聲明(FunctionDeclaration, FD)ide
全部變量聲明(var, VariableDeclaration)函數
/* * example1:形參 */ function test(a, b) { /* var a = 10 var b = undefined 根據規則1,在進入執行上下文時會自動對形參聲明而且賦值。 */ console.log(a) var c = 10; function d() {} var e = function _e() {}; (function x() {}); } test(10); // 10
/* * example2:函數聲明 */ function test(a, b) { console.log(a) function a() {} var e = function _e() {}; } test(10); // ƒ a() {} .根據規則2,進入執行上下文會自動聲明形參而且賦值,可是同名的函數聲明會替換這個變量。 function test(a, b) { console.log(a) var a = 30; var a = function _e() {}; } test(10); // 10 .根據規則2,進入執行上下文會自動聲明形參而且賦值,可是同名的函數聲明會替換這個變量。
/* * example3:變量聲明 */ console.log(foo);//會打印出foo函數,根據規則3,同名的變量聲明不會干擾函數聲明和形參 function foo(){ console.log("foo"); } var foo = 1;
在es5中,函數有四種調用方式:
1. fn(p1,p2) 2. obj.fn(p1,p2) 3. fn.call(context,p1,p2) 4. fn.apply(context,p1,p2)
第三和第四種纔是正常的js函數調用方式,其餘兩種就是語法糖。
fn(p1,p2) 等價於 fn.call(undefined,p1,p2) 等價於 fn.apply(context,[p1,p2]) obj.fn(p1,p2) 等價於 obj.fn.call(obj,p1,p2) 等價於 obj.fn.apply(obj,[p1,p2])
若是你傳的 context 就 null 或者 undefined,那麼 window 對象就是默認的 context(嚴格模式下默認 context 是 undefined)
this是call的第一個參數!!!!
var obj = { foo: function(){ console.log(this) } } var bar = obj.foo obj.foo() // 打印出的 this 是 obj bar() // 打印出的 this 是 window
obj.foo() 至關於 obj.foo.call(obj) 也就至關於把函數名前面的做爲call的第一個參數,也就是this,若是沒有就是window。 bar() 至關於 bar.call(undefined)
在執行函數的時候,this是隱藏的一個參數,且必須是一個對象,若是不是,js是自動把它轉爲對象。
function fn() { console.log(this) console.log(arguments) } fn.call(1,2,3) // Number {1} [2,3]
arguments是僞數組它相似於Array,但除了length屬性和索引元素以外沒有任何Array屬性。
call和apply裏面除了第一個參數以外的都是arguments,若是arguments的個數少建議使用call,使用apply也能夠,若是不肯定就使用apply。
使用一下方法吧arguments轉爲真正的數組:
var args = Array.prototype.slice.call(arguments); var args = [].slice.call(arguments); // ES2015 const args = Array.from(arguments); const args = [...arguments]
MDN 官方文檔對 bind() 的定義:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
大概意思就是,bind會返回一個新的函數(並無的調用原來的函數),這個新函數會call原來的函數,call的參數由你決定。看例子:
this.x = 9; var module = { x: 81, getX: function() { return this.x; } }; var retrieveX = module.getX; var boundGetX = retrieveX.bind(module); boundGetX(); // 81
retrieveX.bind(module)返回了一個新的函數boundGetX,而後調用這個新的函數的時候,把這個函數裏面的this綁定到了module對象上,因此this.x就至關於module.x也就是等於81.
在計算機科學中,柯里化(英語:Currying),又譯爲卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。這個技術由克里斯托弗·斯特雷奇以邏輯學家哈斯凱爾·加里命名的,儘管它是Moses Schönfinkel和戈特洛布·弗雷格發明的。
說的明白一點就是,給函數傳遞一部分參數,讓它返回一個函數去處理其餘參數,舉個例子,求三個數之和:
let addOne = function add(x) { return function(y) { return function(z) { return x+y+z } } } let one = addOne(3) console.log(one)//ƒ (y) {return function (z) {return x + y + z}} let two = one(4) console.log(two)//ƒ (z) {return x + y + z} let three = two(5) console.log(three)//12
在數學和計算機科學中,高階函數是至少知足下列一個條件的函數:
- 接受一個或多個函數做爲輸入
- 輸出一個函數
舉一些高階函數的例子:
/* *接受一個或多個函數做爲輸入 */ 1. Array.prototype.filter() 2. Array.prototype.forEach() 3. Array.prototype.reduce() 4. Array.prototype.map() 5. Array.prototype.find() 6. Array.prototype.every()
/* *輸出一個函數 */ 1. fn.bind(args)
函數A做爲參數(函數引用)傳遞到另外一個函數B中,而且這個函數B執行函數A。咱們就說函數A叫作回調函數。若是沒有名稱(函數表達式),就叫作匿名回調函數。
名詞形式:被當作參數的函數就是回調
動詞形式:調用這個回調
注意回調跟異步沒有任何關係
傳遞的方式有兩種,函數引用和函數表達式。
$.get('myhtmlpage.html', myCallBack);//這是對的 $.get('myhtmlpage.html', myCallBack('foo', 'bar'));//這是錯的,那麼要帶參數呢? $.get('myhtmlpage.html', function(){//帶參數的使用函數表達式 myCallBack('foo', 'bar'); });
箭頭函數的主要區別在this,箭頭函數是沒有this這個概念的,看例子:
setTimeout(function(a){ console.log(this) //這個this指的是{name:'Jack'} setTimeout(function(a){ console.log(this) //這個this指的是window,由於沒有bind,調用setTimeout的是window },1000) }.bind({name:'Jack'}),1000)
setTimeout(function(a){ console.log(this) //這個this指的是{name:'Jack'} setTimeout(function(a){ console.log(this) //這個this指的是{name: "Jack"},由於bind了外面的this也就是{name: "Jack"} },1000) }.bind({name:'Jack'}),1000)
setTimeout(function(a){ console.log(this) //這個this指的是{name:'Jack'} setTimeout(a=>console.log(this),1000)//這個this指的是{name:'Jack'},由於箭頭函數沒有this的概念,它指的this就是外面的this,也就是{name:'Jack'} }.bind({name:'Jack'}),1000)
至此基本上說了js的全部函數內容,只是簡單舉個例子,更深刻的研究還須要看一些其餘大佬的博客哦~~~~