es6-函數


title: es6-函數
date: 2018-02-01 21:47:46
tags: es6


i.jpg

前言

杭州這周溫度達到-5度了,溫度下降的蠻快始腾,年會排舞感覺好懸啊州刽,不知到能拍出啥道道來,現在唯一的心愿就是,早點回家浪箭,冷也阻止不了我回家的腳步穗椅,嗯哼。

我的博客地址 :http://www.aymfx.cn/

引子

ES6函數的改變不算太大奶栖,都是一些其他語言早就有的功能匹表,而Javascript一直比較欠缺的,比如函數參數默認值宣鄙,任意參數的表示法袍镀,最大的變化應該是支持箭頭函數(其他語言稱之為LAMBDA表達式),一種對匿名函數的一種簡寫方式

函數形參的默認值

es5 模擬默認參數

function sendAjax(url,timeout,callback){
    timeout = timeout || 2000;
    callback = callback || $.noop(); //默認參數
    
    $.ajax(url).done(function(){
        setTimeout(callback,timeout)
    })
    
}

上面的賦值操作會存在問題冻晤,你懂的苇羡,所以引入了es6的默認參數


function add(a=200,b=2){
    return a+b;
}

console.log(add()); //202
console.log(add(2)); //4


console.log(add(null,2)); //2  null是合法值 被當成0
console.log(add(undefined,2)); //202


默認參數對arguments對象的影響

非嚴格模式下

function temp(first,second){
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
    first = 'c';
    second = 'd'
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
}

temp('a','b')


//true
//VM264:3 true
//VM264:6 true
//VM264:7 true


嚴格模式下

function temp(first,second){
    'use strict'
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
    first = 'c';
    second = 'd'
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
}

temp('a','b')


//true
//VM264:3 true
//VM264:6 false
//VM264:7 false

非嚴格模式下,參數與argument的值保持一致,嚴格模式下arguments與傳進來的初始參數保持一致鼻弧,看看es6默認值存在的話

非嚴格模式下

function temp(first,second='b'){
    console.log(arguments.length)
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
    first = 'c';
    second = 'b'
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
}

temp('a')

//1
//true
//VM264:3 false
//VM264:6 false
//VM264:7 false


嚴格模式下

function temp(first,second='b'){
    'use strict'
    console.log(arguments.length)
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
    first = 'c';
    second = 'd'
    console.log(first=== arguments[0]);
    console.log(second=== arguments[1]);
}

temp('a')

// Illegal 'use strict' directive in function with non-simple parameter list

//hhhhhhhhhhhh,不能用设江,尷尬

默認參數表達式,可以傳函數

function getValue(){
    return 5;
}

function add(first,second=getValue()){
    return first+second;
}


console.log(add(1,2)); //3
console.log(add(10));  //15

可以將先前定義好的形參當默認值


function add(first,second=first){
    return first+second;
}

console.log(add(1,2)); //3
console.log(add(10));  //20

反之不行哈

function add(first=second,second){
    return first+second;
}

console.log(add(1,2)); //3
console.log(add(undefined,10));  //second is not defined

//這就是所謂的臨時死區(qū)TDZ,未初始化之前不可被引用

不定參數 (...keys)

//模仿Underscore.js pick()方法

function pick(object,...keys){
    console.log(arguments.length); //3
    let result = Object.create(null);
    for(let i=0,len=keys.length;i<len;i++){
        result[keys[i]]= object[keys[i]]
    }
    
    return result;
    
}


let person = pick({name:'ly',age:'18',sex:'mael'},'age','sex'); 

console.log(person.name); //undefind
console.log(person.age); //18
console.log(person.sex); //mael

不定參數的要求

function pick(obj,...keys,last){} //報錯攘轩,不定參數必須放在最后后面

//不定參數不能用于對象字面量setter之中

let object = {
    set name(...values){
        //執(zhí)行邏輯
    }
}

Function 構造函數功能增強 可以使用默認參數和不定參數

const add = new Function('first','second = first','return first+second')

console.log(add(1,2),add(1))  //3 2


var pick = new Function("...args","return args[0]")

console.log(pick(1,2));  //1


展開運算符

//之前求最大值的時候

let values = [25,100,75,56];

console.log(Math.max.apply(this,values));  //100

//有點麻煩叉存,但是用展開運算符的話

console.log(Math.max(...values)); //100

//開不開心,我們可以拿其他值和數組值比較

console.log(Math.max(...values,200)); //200

函數中可以獲取函數名稱的的屬性 name

var func1 = function () {};
// ES5
func1.name // ""
// ES6
func1.name // "func1"
//上面代碼中撑刺,變量func1等于一個匿名函數鹉胖, ES5 和 ES6 的name屬性返回的值不一樣。
//如果將一個具名函數賦值給一個變量够傍,則 ES5 和 ES6 的name屬性都返回這個具名函數原本的名字甫菠。
const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"
//Function構造函數返回的函數實例,name屬性的值為 “anonymous” 冕屯。
(new Function).name // "anonymous"
//bind返回的函數寂诱,name屬性值會加上 “bound ” 前綴。
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "



//還有幾個es6的情況

var dosomething = function(){}

console.log(dosomething.bind().name);  //bound dosomething
console.log((new Function()).name);    //anonymous

明確函數的多重用途

js函數有兩種內部方式 [[Call]]和[[Construct]],當通過new關鍵字調用函數時安聘,執(zhí)行的是[[Construct]]函數,他負責創(chuàng)建一個通常被稱作實例的新對象痰洒,然后再執(zhí)行函數體,將this綁定到實例上;如果不同過new則執(zhí)行[[Call]]函數,從而直接執(zhí)行代碼中的函數體

es5判斷函數被調用的方法

function Person(name){
    if(this instanceof Person){
        this.name = name;
    } else{
        throw new Error('必須new才行,嘿嘿')
    }
}

var person = new Person("ly"); //
var notperson =Person("ll"); // 必須new才行浴韭,嘿嘿

//但是可以蒙混過關

var notperson =Person.call(peson,"ll"); //


new.target 精準判斷

function Person(name){
    if(typeof new.target !== 'undefined'){
        this.name = name;
    } else{
        throw new Error('必須new才行丘喻,嘿嘿')
    }
}

var person = new Person("ly"); //
var notperson =Person.call(person,"ll"); //

塊級作用域

在es5的時代,當啟用嚴格模式時念颈,下列代碼會報錯,es6則不會,因為產生了塊級作用域泉粉,該函數可以在這個if條件語句內部使用,外部依舊是undefined

 "use strict"
 if(true){
    console.log(typeof add); //function
    function add(a,b){
        return a+b;
    }
 }
 
 console.log(typeof add);  //undefined

但是在非嚴格模式下,該函數還是會被提升到全局作用域頂部

 if(true){
    console.log(typeof add); //function
    function add(a,b){
        return a+b;
    }
 }
 
 console.log(typeof add);  //function


重要改變 箭頭函數

一些好玩的改變(興奮狀)

  • 沒有this,spuer,arguments和new.target綁定
  • 不能通過new關鍵字調用
  • 沒有原型
  • 不可以改變this的綁定
  • 不支持arguments對象
  • 不支持重復的命名參數

箭頭函數的語法

let add = (a,b) => a+b;

//實際類似于

let add = function(a,b){return a+b}


//當箭頭函數只有一個參數時嗡靡,不需要括號

let reflrct = value => value

//類似于

let reflrct = function(value){return value}

//不寫參數時要加括號

let name = () => 'ly';


//類似于

let name = function(){return 'ly'}


//如果需要寫復雜的函數體跺撼,則必須這樣寫

let getName = (fisrtName,secondName) => {
    return firstName+' '+ secondName;
}

//類似于

let getName = function(fisrtName,secondName){
    return firstName+' '+ secondName;
}

//如果想反回一個字面量對象則需要這樣寫

let person = () => ({
    name:'ly',
    age:18
})

//類似于

let person = function(){
    return {
    name:'ly',
    age:18
}
}

//創(chuàng)建一個立即表達函數

let person = ((name) => ({getName:() => name}))('ly')

//自己還原下看看,嘿嘿


箭頭函數沒有this綁定

let PageHandler = {
     id:'13579',
     init:function(){
         document.addEventListener('click',function(event){
             this.doSomething(event.type)  //會報錯
         })
     },
     doSomething:function(type){
         console.log(type);
     }
}

es5的做法讨彼,將會這么做

let PageHandler = {
     id:'13579',
     init:function(){
         document.addEventListener('click',(function(event){
             this.doSomething(event.type)  
         }).bind(this))
     },
     doSomething:function(type){
         console.log(type);
     }
}



但是有了箭頭函數的話歉井,就帥多了

let PageHandler = {
     id:'13579',
     init:function(){
         document.addEventListener('click',event => this.doSomething(event.type) 
         )
     },
     doSomething:function(type){
         console.log(type);
     }
}

因為箭頭函數是沒有this的,所以在處理的過程中,它里面的this取決函數外部非箭頭函數的this值

箭頭函數不存在arguments綁定所以可以這么操作

 function outer(){
     return () => arguments[0];
 }
 
 let inner = outer(18)
 
  console.log(inner()); //18  就是這么騷氣哈误,直接訪問箭頭函數體外函數的arguments

call(),bind(),apply() 都是可以用的哩至,但是改變不了this的值的哈

尾調用的優(yōu)化(Tail Call)

尾調用指的是函數做為另一個函數最后一條語句被調用,它不會在調用棧上增加新的堆棧幀,而是直接更新調用棧黑滴,調用棧所占空間始終是常量憨募,節(jié)省了內存,避免了爆棧的可能性,但是es5存在調用棧變得過大則會造成程序問題

尾調用實例


 function add(a,b){
     
 }
 
 function max(a,b,c,d){
 
    //......
     return add(a,c);
     
 }

優(yōu)化需要滿足以下條件,尾調用才不會創(chuàng)建新棧幀,而是清除并重用當前棧幀

  • 尾調用不訪問當前棧的變量(不形成閉包)
  • 尾調用是函數內部的最后一句
  • 尾調用的結果將作為函數值返回 (必須有return fn())

使用場景 尾遞歸

錯誤方式

console.time('testForEach');
function factorial(n) {
    if(n<=1){
        return 1
    } else {
        return n*factorial(n-1)  //如果n很大袁辈,在不斷遞歸的情況下菜谣,會棧溢出,這也不是尾遞歸
    }
}
var a =factorial(5000);
console.log(a); 
console.timeEnd('testForEach'); // 1.55322265625ms


正確寫法

console.time('testForEach');
function factorial(n,p=1) {
    if(n<=1){
        return 1*p;
    } else {
        let result = p*n;
        return factorial(n-1,result)  
}
}
factorial(5000);
console.timeEnd('testForEach'); //0.492919921875ms    測 了10000 居然棧溢出  搞不懂

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末晚缩,一起剝皮案震驚了整個濱河市尾膊,隨后出現的幾起案子,更是在濱河造成了極大的恐慌荞彼,老刑警劉巖冈敛,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異鸣皂,居然都是意外死亡抓谴,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門寞缝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來癌压,“玉大人,你說我怎么就攤上這事荆陆√步欤” “怎么了槐雾?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵叠纷,是天一觀的道長滑沧。 經常有香客問我驶睦,道長,這世上最難降的妖魔是什么攒菠? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任渐裸,我火速辦了婚禮助析,結果婚禮上命浴,老公的妹妹穿的比我還像新娘粘衬。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布稚新。 她就那樣靜靜地躺著,像睡著了一般跪腹。 火紅的嫁衣襯著肌膚如雪褂删。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天冲茸,我揣著相機與錄音屯阀,去河邊找鬼。 笑死轴术,一個胖子當著我的面吹牛难衰,可吹牛的內容都是我干的。 我是一名探鬼主播逗栽,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼盖袭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了彼宠?” 一聲冷哼從身側響起鳄虱,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凭峡,沒想到半個月后拙已,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡摧冀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年倍踪,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片索昂。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡建车,死狀恐怖,靈堂內的尸體忽然破棺而出楼镐,到底是詐尸還是另有隱情癞志,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布框产,位于F島的核電站凄杯,受9級特大地震影響,放射性物質發(fā)生泄漏秉宿。R本人自食惡果不足惜戒突,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望描睦。 院中可真熱鬧膊存,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爵卒,卻和暖如春虚缎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钓株。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工实牡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人轴合。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓创坞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親受葛。 傳聞我的和親對象是個殘疾皇子题涨,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內容

  • 函數參數的默認值 基本用法 在ES6之前,不能直接為函數的參數指定默認值奔坟,只能采用變通的方法携栋。 上面代碼檢查函數l...
    呼呼哥閱讀 3,359評論 0 1
  • 1.函數參數的默認值 (1).基本用法 在ES6之前,不能直接為函數的參數指定默認值咳秉,只能采用變通的方法婉支。
    趙然228閱讀 684評論 0 0
  • ES6函數的擴展 1.函數默認值 定義:ES6允許為函數設定默認值,即直接寫在參數定義的后面 示例function...
    lijaha閱讀 399評論 0 0
  • 第一章 塊級作用域綁定 let 和 const 都是不存在提升,聲明的都是塊級標識符都禁止重聲明 每個const聲...
    NowhereToRun閱讀 1,577評論 0 2
  • 或許我們缺的不是錢炕舵,是信任與關心
    Momoe_47f9閱讀 239評論 0 0