1.函數聲明和函數表達式有什么區別
function命令聲明的代碼區塊,就是一個函數。function命令后面是函數名,函數名后面是一對圓括號,里面是傳入函數的參數。函數體放在大括號里面。
function print(s) {
console.log(s);
}```
除了用function命令聲明函數,還可以采用變量賦值的寫法。
var print = function(s) {
console.log(s);
};```
這種寫法將一個匿名函數賦值給變量。這時,這個匿名函數又稱函數表達式(Function Expression),因為賦值語句的等號右側只能放表達式。
函數的表達式需要在語句的結尾加上分號,表示語句結束。而函數的聲明在結尾的大括號后面不用加分號。
區別:
函數聲明:聲明不必放到調用的前面
函數表達式:聲明必須放到調用的前面
JavaScript 解釋器中存在一種變量聲明被提升(hoisting)的機制,也就是說變量(函數)的聲明會被提升到作用域的最前面,即使寫代碼的時候是寫在最后面,也還是會被提升至最前面。
例如以下代碼段:
alert(foo); // function foo() {}
alert(bar); // undefined
function foo() {}
var bar = function bar_fn() {};
alert(foo); // function foo() {}
alert(bar); // function bar_fn() {}```
輸出結果分別是function foo() {}、undefined、function foo() {}和function bar_fn() {}。
可以看到 foo 的聲明是寫在 alert 之后,仍然可以被正確調用,因為 JavaScript 解釋器會將其提升到 alert 前面,而以函數表達式創建的函數 bar 則不享受此待遇。
# 2.什么是變量的聲明前置?什么是函數的聲明前置
在一個作用域下,var 聲明的變量和function 聲明的函數會前置
與全局作用域一樣,函數作用域內部也會產生“變量提升”現象。var命令聲明的變量,不管在什么位置,變量聲明都會被提升到函數體的頭部。
# 3.arguments 是什么
由于JavaScript允許函數有不定數目的參數,所以我們需要一種機制,可以在函數體內部讀取所有參數。這就是arguments對象的由來。
arguments對象包含了函數運行時的所有參數,arguments[0]就是第一個參數,arguments[1]就是第二個參數,以此類推。這個對象只有在函數體內部,才可以使用。
# 4.函數的"重載"怎樣實現
>函數重載(英語:Function overloading),是Ada、C++、C#、D和Java等編程語言中具有的一項特性,這項特性允許創建數項名稱相同但功能的輸入輸出類型不同的子程序,它可以簡單地稱為一個單獨功能可以執行多項任務的能力。
其他語言重載范例
int sum(int num1, int num2){
return num1 + num2;
}
float sum(float num1, float num2){
return num1 + num2;
}
sum(1, 2);
sum(1.5, 2.4);
Javascript中,先定義的函數,會被后定義的函數覆蓋。因此Javascript不支持函數的重載,不能夠定義同樣的函數然后通過編譯器去根據不同的參數執行不同的函數。
但是javascript卻可以通過自身屬性去模擬函數重載。
變相實現函數重載的方法:
- 利用arguments對象
<script type="text/javascript">
function showSum()
{
//使用arguments對象模擬出重載效果
if (arguments.length == 1)
{
alert(arguments[0] + 1);
}
else if (arguments.length == 2)
{
alert(arguments[0] + arguments[1]);
}
else if (arguments.length == 3)
{
alert(arguments[0] + arguments[1] + arguments[2]);
}
else {
alert('請傳入參數!');
}
}
//顯示101
showSum(100);
//顯示200
showSum(100, 100);
//顯示300
showSum(100, 100,100);
</script>```
- 利用閉包(有點難,學學回來再看。)
參考文章:http://www.cnblogs.com/yugege/p/5539020.html
參考文章:https://johnresig.com/blog/javascript-method-overloading/
參考文章:http://www.cnblogs.com/bluedream2009/archive/2011/01/05/1925963.html
5.立即執行函數表達式是什么?有什么作用
立即執行函數就是
1.聲明一個匿名函數
2.馬上調用這個匿名函數
JavaScript引擎規定,如果function關鍵字出現在行首,一律解釋成語句,為了兼容 JS 的語法。避免瀏覽器報語法錯誤,可以這樣寫:
(function(){alert('我是匿名函數')} ()) // 用括號把整個表達式包起來
(function(){alert('我是匿名函數')}) () //用括號把函數包起來
!function(){alert('我是匿名函數')}() // 求反,我們不在意值是多少,只想通過語法檢查。
+function(){alert('我是匿名函數')}()
-function(){alert('我是匿名函數')}()
~function(){alert('我是匿名函數')}()
void function(){alert('我是匿名函數')}()
new function(){alert('我是匿名函數')}()
只有一個作用:創建一個獨立的作用域。
這個作用域里面的變量,外面訪問不到(即避免「變量污染」)。
參考文章:https://zhuanlan.zhihu.com/p/22465092
6.求n!,用遞歸來實現
function factor(n){
if(n === 1) {
return 1;
}
return n * factor(n-1);
}
factor(5);
注意:求遞歸的時候要考慮負數和0;
7.以下代碼輸出什么?
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';
console.log('name', name);
}
getInfo('饑人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
name: 饑人谷
age: 2
sex: 男
["饑人谷", 2, "男", callee: function, Symbol(Symbol.iterator): function]
name valley
name: 小谷
age: 3
sex: undefined
["小谷", 3, callee: function, Symbol(Symbol.iterator): function]
name valley
name: 男
age: undefined
sex: undefined
["男", callee: function, Symbol(Symbol.iterator): function]
name valley
8 寫一個函數,返回參數的平方和?
function sumOfSquares(){
var sum = 0;
for (var i = 0; i<arguments.length; i++) {
sum = sum+arguments[i]*arguments[i];
}
return sum;
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result)
console.log(result2)
9 如下代碼的輸出?為什么
console.log(a);//undefined;變量a被提升
var a = 1;
console.log(b);//Uncaught ReferenceError: b is not defined;b未聲明
10. 如下代碼的輸出?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);//hello world;函數聲明被提升到代碼最前面。
}
var sayAge = function(age){
console.log(age);//Uncaught TypeError: sayAge is not a function;這是函數表達式,只有var sayAge被提升到代碼前面;
};
11. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10
bar()
function foo() {
console.log(x)//10;
}
function bar(){
var x = 30
foo()
}
函數本身也是一個值,也有自己的作用域。它的作用域與變量一樣,就是其聲明時所在的作用域,與其運行時所在的作用域無關。總之,函數執行時所在的作用域,是定義時的作用域,而不是調用時所在的作用域。
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
barContext= {
AO: {
x:30
}
scope:globalContext.AO
}
fooContex= {
AO: {}
scope:globalContext.AO
}
12. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x) //30
}
foo();
} ```
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
barContext= {
AO: {
x:30
foo: function
}
scope:globalContext.AO
}
fooContex= {
AO: {}
scope:barContext.AO
}
# 13. 以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)//30
})()
}```
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
barContext= {
AO: {
x:30
}
scope:globalContext.AO
}
fooContex= {
AO: {}
scope:barContext.AO
}
立即執行函數的作用域鏈 與普通函數作用域鏈一樣.(要說區別,立即不會提升)
14. 以下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var a = 1;
function fn(){
console.log(a)//undefined
var a = 5
console.log(a)//5
a++
var a
fn3()
fn2()
console.log(a)//20
function fn2(){
console.log(a)//6
a = 20
}
}
function fn3(){
console.log(a)//1
a = 200
}
fn()
console.log(a)//200
globalContext = {
AO: {
a: 1
fn: function
fn3: function
},
Scope: null
}
fnContext= {
AO: {
a:5
fn2: function
}
scope:globalContext.AO
}
fn2Contex= {
AO: {}
scope:fnContext.AO
}
fn3Contex= {
AO: {}
scope:globalContext.AO
}