1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
- 使用函數(shù)聲明來聲明的函數(shù)不需要放在調(diào)用的前面就可以被調(diào)用,使用函數(shù)表達(dá)式聲明的函數(shù)需要放在調(diào)用函數(shù)的前面才能被正確調(diào)用。
2.什么是變量的聲明前置?什么是函數(shù)的聲明前置
- 在一個(gè)作用域下,var 聲明的變量和function 聲明的函數(shù)會(huì)前置。
- 使用var聲明的變量會(huì)在執(zhí)行代碼的時(shí)候先預(yù)解析到作用域的頭部,并被賦值為undefined.
- 使用function聲明的函數(shù)也一樣會(huì)被預(yù)解析讀取到作用域的頭部。
3.arguments 是什么
- arguments是一個(gè)函數(shù)自帶的參數(shù)對(duì)象,他包含了函數(shù)所有的參數(shù),而且可以像調(diào)用一個(gè)數(shù)組一樣來調(diào)用,不過arguments并不是一個(gè)數(shù)組,如果用typeof來檢測(cè)的話會(huì)返回"object",表示是一個(gè)對(duì)象。
4.函數(shù)的"重載"怎樣實(shí)現(xiàn)
- 重載在一般的編程語言中,表示有相同的函數(shù)名,但是參數(shù)列表不相同,通過傳遞不同的參數(shù)可以讓函數(shù)內(nèi)部的處理方法不一樣,得到也結(jié)果也可能不同。
- JaveScript中并沒有重載,函數(shù)同名的話會(huì)被覆蓋,但可以在函數(shù)體針對(duì)不同的參數(shù)調(diào)用執(zhí)行相應(yīng)的邏輯。
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
5.立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用
- 立即執(zhí)行函數(shù)表達(dá)式表示直接聲明函數(shù),聲明后直接調(diào)用函數(shù)。不直接在聲明函數(shù)直接加上‘()’調(diào)用時(shí)因?yàn)闉g覽器不識(shí)別會(huì)報(bào)語法錯(cuò)誤。一般寫法為直接將聲明函數(shù)用小括號(hào)括起來然后再在后面添加上小括號(hào)調(diào)用。
- 作用是可以隔離作用域,防止污染全局作用域。
6.求n!,用遞歸來實(shí)現(xiàn)
function fn(n){
if (n === 1){
return 1;
}
return n*fn(n-1);
}
fn(n)
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, '男'); // name:饑人谷 age:2 sex:男 ['饑人谷', 2, '男'] name:valley
getInfo('小谷', 3); // name:小谷 age:3 sex:undefined ['小谷', 3] name:valley
getInfo('男'); // name:男 age:undefined sex:undefined ['男'] name:valley
8. 寫一個(gè)函數(shù),返回參數(shù)的平方和?
function sumOfSquares(){
if (arguments.length === 0){
alert("請(qǐng)輸入至少一個(gè)參數(shù)")
}
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
9. 如下代碼的輸出?為什么
console.log(a); //undefined
var a = 1;
console.log(b); // 報(bào)錯(cuò)
- 因?yàn)樽兞柯暶髑爸玫年P(guān)系,var a 會(huì)被提到作用域頭部,賦值為undefined,然后運(yùn)行到代碼的時(shí)候會(huì)被賦值為1.而變量b并沒有被聲明,函數(shù)運(yùn)行到代碼console.log(b); 時(shí)在作用域內(nèi)找不到變量b,所以瀏覽器報(bào)錯(cuò)。
10. 如下代碼的輸出?為什么
sayName('world'); //hello world
sayAge(10); // 瀏覽器報(bào)錯(cuò) sayAge is not a function
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
- 使用函數(shù)聲明方式來聲明的函數(shù),會(huì)因?yàn)楹瘮?shù)聲明前置被提到作用域的頭部,所以調(diào)用sayName時(shí)即使調(diào)用函數(shù)寫在聲明函數(shù)之前依舊有效果,但是使用函數(shù)表達(dá)式聲明函數(shù)的話,瀏覽器會(huì)先解析sayAge為一個(gè)變量,并賦值為undefined然后提到代碼頭部,然后執(zhí)行到聲明函數(shù)的代碼時(shí)才會(huì)將這個(gè)變量賦值為一個(gè)函數(shù)。調(diào)用寫在聲明之前的話瀏覽器執(zhí)行到調(diào)用函數(shù)的代碼段時(shí)會(huì)認(rèn)為sayAge是一個(gè)變量,使用函數(shù)調(diào)用方式是錯(cuò)誤的,從而報(bào)錯(cuò)。
11. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10
bar() // x= 10
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
==>
/*
globalContext = {
AO:{
x:10;
foo: function(){}
bar: function(){}
}
scope:null;
}
barContext = {
AO:{
x:30;
}
bar.[[scope]] =globalContext.AO
}
fooContext = {
AO:{
}
foo.[[scope]] =globalContext.AO
}
*/
- foo.scope為全局作用域,當(dāng)執(zhí)行bar時(shí)會(huì)現(xiàn)在bar的函數(shù)作用域bar.AO中創(chuàng)建一個(gè)x并被賦值為30,然后調(diào)用函數(shù)foo,在foo的作用域中找不到變量x,所以會(huì)返回到foo.scope中也就是全局作用域中尋找,得到x=10。
12. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var x = 10;
bar() // 30
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
==>
/*
globalContext = {
AO:{
x:10
bar: function(){}
}
scope:null;
}
barContext = {
AO:{
x:30;
foo: function(){}
}
bar.[[scope]] =globalContext.AO
}
fooContext = {
AO:{
}
foo.[[scope]] =barContext.AO
}
*/
- 和上一題差不多,不過這題中foo.scope為barContext.AO,所以x值去barContext.AO里面找,找到x為30
- 以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼
var x = 10;
bar() // 30
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
==>
/*globalContext = {
AO: {
x: 10
bar: function
}
Scope: null
}
barContext = {
AO: {
x: 30
function: function
}
Scope: globalContext.AO
}
functionContext = {
AO: {}
Scope: barContext.AO
}
*/
- 與上一題差不多,只不過這里沒有聲明函數(shù)再調(diào)用,而是立即執(zhí)行函數(shù)表達(dá)式的寫法,函數(shù)的執(zhí)行上下文依然還是barContext.AO,所以取到的x的值依舊是30。
14. 以下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
var a = 1;
function fn(){
console.log(a) //undefined
var a = 5
console.log(a) // 5
a++
var a
fn3() // 1
fn2() // 6
console.log(a) // 20
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn() // undefined 5 1 6 20
console.log(a) // 200
==>
/*
globalContext = {
AO: {
x: 1
fn: function
fn3:function
}
Scope: null
}
fnContext = {
AO: {
a: undefined
a:5
a:6
fn2:function
}
Scope: globalContext.AO
}
fn2Context = {
AO: {
a:20
}
Scope: fnContext.AO
}
fn3Context = {
AO: {
a:200
}
Scope: globalContext.AO
}
*/
- 調(diào)用fn時(shí),因?yàn)樽兞壳爸茫缘谝粋€(gè)console.log(a)得到undefined,然后a被賦值為5,第二次console.log(a)得到 a=5,之后執(zhí)行a++ 使a=6.
- 接著調(diào)用fn3,但是fn3中console.log(a)在a=200之前,且并沒有使用var讓變量聲明前置,找不到變量a,便會(huì)去fn3的執(zhí)行上下文中也就是全局作用域中尋找,得到a=1;然后再將全局作用域中的a賦值為200.
- 然后調(diào)用fn2,console.log(a)在a=20之前,但是依然沒有變量前置,所以會(huì)在fn2的執(zhí)行上下文fnContext.AO中尋找,得到a=6,然后降fnContext.AO中的a賦值為20.
- 最后一次console.log(a)調(diào)用得到的a = 20.到此fn執(zhí)行完畢。
- fn調(diào)用后執(zhí)行的console.log(a),因?yàn)橹叭肿饔糜虻腶 在執(zhí)行fn3是被賦值成了200,所以得到200