函數聲明和函數表達式有什么區別?
函數聲明:function functionName() {}
函數表達式:var fn = function() {}
- 函數聲明會提前,函數表達式可以省略標識符(函數名)。
函數聲明不必放到調用的前面,函數表達式聲明必須放到調用的前面。
什么是變量的聲明前置?什么是函數的聲明前置
在一個作用域下,var 聲明的變量和function 聲明的函數會前置.前置到當前作用域的開頭。
變量聲明的前置:
console.log(i);
var i = 1; //undefined
代碼執行過程:
var i;. //提前在程序最開始,聲明一個變量i 未賦值 所以是 undefined
console.log(i);
i = 1; //console.log(i)在 i = 1 ;賦值語句之前,而變量聲明前置所以打印的時候i是undefined;
函數的聲明前置:
test(1)
function test(x){
console.log(x);
} // 1
通過函數聲明的方式建立的函數表達式會提前,這段代碼過程:
function test(x){};
test(1)
輸出的結果為1;因為function test(x){} 整個函數 已經提前到了test(1)之前。
但是,同樣的方法,使用函數表達式,其出現的結果是報錯,因為其調用在其聲明之前。
如下例子:
func1(); // 輸出:我是函數聲明
func2(); // 報錯
console.log(a); // 輸出:undefined
function func1() {
console.log("我是函數聲明");
}
var func2 = function() {
console.log("我是函數表達式");
}
var a = 10;
arguments 是什么?
arguments是一個類數組對象。代表傳給一個function的參數列表。
?arguments對象是函數內部的本地變量;arguments 已經不再是函數的屬性了。可以在函數內部通過使用 arguments 對象來獲取函數的所有參數。這個對象為傳遞給函數的每個參數建立一個條目,條目的索引號從0開始。它包括了函所要調用的參數。object對象。類數組。
函數的"重載"怎樣實現?
首先,要明確,在JS中,沒有重載。同名函數會覆蓋。但可以在函數體針對不同的參數調用執行相應的邏輯。
如下例:
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);//Byron 26
printPeopleInfo('Byron', 26, 'male');//Byron 26 male
javascript不能支持函數的重載,如下:
function f(length)
{
alert("高為:"+length);
}
function f(length,width)
{
alert("高為:"+length+",寬為:"+width);
}
上面那段代碼其實是行不通的,因為函數定義時的參數個數和函數調用時的參數個數沒有任何關系。在函數中可以用f.arguments[0]和f.arguments[1]得到調用時傳入的第一和第二個參數,所以定義function(length),后面用f(10,10)調用是沒有問題的。所以在上面這段代碼中,第二個函數是永遠不可能被調用到的,那么,要怎樣才能實現像函數重載那樣的功能呢?
那就是在函數定義中用f.arguments.length判斷一下調用時傳入的參數個數。然后對不同的情況采用不同的處理方式。 如下:
function f()
{
var len= arguments.length;
if(2 == len)
{
var length = arguments[0];
var width = arguments[1];
f2(length,width);
}
else
{
var length = arguments[0];
f1(length);
}
}
function f1(length)
{
alert("高為:"+length);
}
function f2(length,width)
{
alert("高為:"+length+",寬為:"+width);
}
*這樣,你就可以給函數f()傳入一個參數也可以傳入兩個參數了,比如f(10)和f(10,10); *
- 這樣雖然可以實現重載,但也不是很好用,我們可以根據具體情況在一個函數中實現重載,如果要重載的兩個函數相差較大,那就保留兩個函數,而如果兩個函數的實現基本差不多,那么可以在一個函數中進行判斷,處理不同的部分,而不需要像上面那樣寫成三個函數,如下:
function f(length)
{
var len= arguments.length;
if(1 == len)
{
var width = arguments[1];
alert("高為:"+length+",寬為:"+width);
}
else
{
alert("高為:"+length);
}
}
立即執行函數表達式是什么?有什么作用
(function(){
var a = 1;
})()
作用: 隔離作用域。
??JavaScript有很多致命缺陷,比如JavaScript中沒有命名空間,而且只有function代碼塊內部可以隔離變量作用域,自調用匿名函數就用來防止變量彌散到全局,以免各種js庫沖突。
求n!,用遞歸來實現
function fn(n) {
if(n < 0){
alert("error")
}
else if(n == 0 || n == 1) {
return 1;
}
return n * fn(n-1);
}
fn(5);
以下代碼輸出什么?
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,'男']
name valley
name:小谷
age:2
sex: undefined
['小谷','3']
name valley
name:男
age:undefined
sex:undefined
['男']
name valley
寫一個函數,返回參數的平方和?
function sumOfSquares(){
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i]*arguments[i]
}
return sum;
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
如下代碼的輸出?為什么
console.log(a);
var a = 1;
console.log(b);
// undefined
// ReferenceError: b is not defined
console.log(a)輸出的是undefined、因為變量在當前作用域下被前置,結果在console.log(a)前面的var a;雖然聲明了但是沒有賦值,結果為undefined.
console.log(b) b完全是沒有聲明也沒有賦值,結果是報錯.//ReferenceError: b is not defined
*/
如下代碼的輸出?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
// hello world
// TypeError: sayAge is not a function
sayNme('world');會返回'hello world'.
sayAge(10);因為是使用表達式定義,所以,當調用在定義之前就會報錯,sayAge is not a function.
如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
/* 10
1.
globalContext = {
AO: {
x: 10, foo: function, bar: function
},
foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
}
2.調用bar()
barContext = {
AO: {
x: 30
}
Scope: bar.[[scope]] = globalContext.AO
}
3.調用foo()
fooContext = {
AO: {}
Scope: foo.[[scope]] = globalContext.AO
} */
如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
輸出: 30
1.
globalContext={
AO:{
x:10,
bar : function
},
Scope:null
}
bar.[[scope]]=globalContext.AO
2. 調用bar
barContext={
AO:{
x: 30,
foo:function
},
Scope: bar.[[scope]]=globalContext.AO
}
foo.[[scope]]=barContext.AO
3. 調用foo
fooContext={
AO:{},
Scope: foo.[[scope]]=barContext.AO
}
以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
輸出: 30
1.
globalContext={
AO:{
x: 10,
bar:function
}
Scope: null
}
bar.[[scope]]=globalContext.AO
2.調用bar
barContext={
AO:{
x:30,
function(){}
}
Scope:bar.[[scope]]=globalContext.AO
}
function().[[scope]]=barContext.AO
3. 調用function()
functionContext={
AO:{}
Scope:function().[[scope]]=barContext.AO
}
以下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var a = 1;
function fn(){
console.log(a)
var a = 5
console.log(a)
a++
var a
fn3()
fn2()
console.log(a)
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn()
console.log(a)
輸出: undefined 5 1 6 20 200
1.
globalContext={
AO:{
a:200,
fn:function,
fn3:function
}
Scope: null
}
fn.[[scope]]=globalContext.AO
fn3.[[scope]]=globalContext.AO
2. 調用fn
fnContext={
AO:{
a:20,
fn2:function
}
Scope: fn.[[scope]]=globalContext.AO
}
fn2.[[scope]]=fnContext.AO
3. 調用fn3
fn3Context={
AO:{}
Scope:fn3.[[scope]]=globalContext.AO
}
4. 調用fn2
fn2Context={
AO:{}
Scope:fn2.[[scope]]=fnContext.AO
}