系列列表:
從use strict看JS(一):this與箭頭函數
從use strict看JS(二):函數傳參模式與argumentsgit
上一篇說到,use strict對arguments作了如下限定github
arguments。不容許對arguments賦值。禁止使用arguments.callee。arguments再也不追蹤參數的變化面試
這是爲何呢?若是你明白下面兩個例子就不用看這篇文章了~數組
function notChangeName(obj){ obj="change"; } function changeName(obj){ obj.name="change"; } var dog={ name:"dog" }; notChangeName(dog); //輸出Object {name: "dog"},沒改變 console.log(dog); changeName(dog); //輸出Object {name: "change"},改了 console.log(dog); //經典例子,JavaScript高級程序設計的例子 function setName(obj){ obj.name="doge"; obj=new Object(); obj.name="cat"; } var person={}; setName(person); //doge console.log(person.name);
function notChangeName(name){ "use strict"; name="cat"; // 嚴格模式輸出dog,非嚴格輸出cat console.log(arguments[0]); } function changeName(obj){ "use strict"; obj.name="cat"; // 輸出cat console.log(arguments[0].name); } notChangeName("dog"); changeName({name:"dog"}); function dog(){ // "use strict"; //嚴格模式SyntaxError,非嚴格輸出"a" arguments="a"; console.log(arguments); } dog();
js一個變量對應一個值,一個值對應一種類型;而一種類型對應多個值,一個值對應多個變量。
字符串的值不能改變,但能讓變量指向不一樣的值app
舉兩個栗子:函數
no1.this
var dog={ } var cat=dog; dog.name="doge"; var third={ name:"the third man" } // 輸出doge console.log(cat.name);
上述例子中,dog和cat是不一樣的變量,但指向同一個值,因此dog改變會反應到cat上。third是另一個變量,指向不一樣的值,而這兩個值有相同的類型。以下圖spa
no2.prototype
var str="doge"; // 輸出o console.log(str[1]); str[1]="c"; // 輸出o,字符串的值不能改變 console.log(str[1]); str="cat"; // 輸出c,變量指向了不一樣的值 console.log(str[0]);
因此,在前面的例子中,notChangeName函數內部將變量obj指向不一樣的值,外部的dog指向同一個值且值未發生變化。於是不能改變dog的name。
changeName函數中,obj和dog指向同一個值,更改obj的name就等於更改了dog的name。
JavaScript高級程序設計的例子同理。以下:設計
function notChangeName(obj){ obj="change"; } function changeName(obj){ obj.name="change"; } var dog={ name:"dog" }; notChangeName(dog); //輸出Object {name: "dog"},沒改變 console.log(dog); changeName(dog); //輸出Object {name: "change"},改了 console.log(dog); //經典例子,JavaScript高級程序設計的例子 function setName(obj){ obj.name="doge"; obj=new Object(); obj.name="cat"; } var person={}; setName(person); //doge console.log(person.name);
use strict下的arguments會保持對「值」的引用,於是arguments變量是不能被從新賦值的,若是強制賦值呢?好比arguments="a",那就強制報錯,沒得商量。
也是由於保持對「值」的引用,arguments再也不追蹤參數的變化,但若是參數是obj且改變的是「值」,而不是從新賦值,那就不同了。以下:
function notChangeName(name){ "use strict"; name="cat"; // 嚴格模式輸出dog,非嚴格輸出cat console.log(arguments[0]); } function changeName(obj){ "use strict"; obj.name="cat"; // 輸出cat console.log(arguments[0].name); } notChangeName("dog"); changeName({name:"dog"}); function dog(){ // "use strict"; //嚴格模式SyntaxError,非嚴格輸出"a" arguments="a"; console.log(arguments); } dog();
這就是一個點而已,arguments不是數組,是個類數組對象,沒有數組的push、pop、map那些方法,那如何把它變爲數組呢?循環遍歷一遍也是能夠的,arguments有長度,但有更簡單的方法,以下:
function argToArr(index){ var newArg=Array.prototype.slice.apply(arguments); newArg.push(2); } argToArr(1);
爲什麼不直接
arguments=Array.prototype.slice.apply(arguments);
由於如今不少都用use strict了,這個會報錯,還不知道爲什麼會報錯的再看一遍文章哈,自覺點
這個用來幹啥呢,它能在函數內部調用本身,經常使用來解耦和。好比寫個斐波那契數列函數
function fib(n){ if(n===1||n===2){ return 1; } return fib(n-1)+fib(n-2); }
這個問題在哪呢,耦合性太強,改了外層的fib,內部函數名稱也得改。能夠用arguments.callee改進
function fibArg(n){ if(n===1||n===2){ return 1; } return arguments.callee(n-1)+arguments.callee(n-2); }
問題是這個在嚴格模式下不能運行。不繞了,來個終極方法
var fib=(function f(n){ "use strict"; if(n===1||n===2){ return 1; } return f(n-1)+f(n-2); })
這種模式以後還會涉及,跟當即執行函數相似,jQuery這些也用了,之後再聊~
好像沒談爲什麼要這樣限定arguments!
夜已深,就不繼續悟道了。