1.立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用
立即執(zhí)行函數(shù)表達(dá)式就是
- 聲明一個(gè)匿名函數(shù)
- 馬上執(zhí)行這個(gè)匿名函數(shù)
典型寫(xiě)法:( function(){alert('匿名函數(shù)')} )()
為什么要用一對(duì)括號(hào)把匿名函數(shù)包起來(lái)呢?
因?yàn)椴患永ㄌ?hào),寫(xiě)成function(){alert('匿名函數(shù)')} ()會(huì)報(bào)錯(cuò),原因是function關(guān)鍵字出現(xiàn)在行首,一律解釋成語(yǔ)句。因此,JavaScript引擎看到行首是function關(guān)鍵字之后,認(rèn)為這一段都是函數(shù)的定義,不應(yīng)該以圓括號(hào)結(jié)尾,所以就報(bào)錯(cuò)了。
解決方法就是不要讓function出現(xiàn)在行首,因此可以加點(diǎn)東西,有以下寫(xiě)法
(function(){alert('我是匿名函數(shù)')} ()) // 用括號(hào)把整個(gè)表達(dá)式包起來(lái)
(function(){alert('我是匿名函數(shù)')}) () //用括號(hào)把函數(shù)包起來(lái)
!function(){alert('我是匿名函數(shù)')}() // 求反,我們不在意值是多少,只想通過(guò)語(yǔ)法檢查。
+function(){alert('我是匿名函數(shù)')}()
-function(){alert('我是匿名函數(shù)')}()
~function(){alert('我是匿名函數(shù)')}()
void function(){alert('我是匿名函數(shù)')}()
new function(){alert('我是匿名函數(shù)')}()
那么立即執(zhí)行函數(shù)表達(dá)式有什么作用呢?
作用是創(chuàng)建一個(gè)獨(dú)立的作用域。這個(gè)作用域里面的變量,外面訪(fǎng)問(wèn)不到,這樣可以避免變量污染
2.求n!,用遞歸來(lái)實(shí)現(xiàn)
function recursion(n) {
if (n === 1) {
return 1;
}
return n * recursion(n-1);
}
var result = recursion(10);
console.log(result); //以n等于10為列子,結(jié)果:3628800
3.以下代碼輸出什么?
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('男');
調(diào)用getInfo('饑人谷', 2, '男')輸出:
name: 饑人谷
age: 2
sex: 男
["饑人谷",2,"男"]
name valley
調(diào)用getInfo('小谷', 3)輸出
name: 小谷
age: 3
sex: undefined
["小谷",3]
name valley
調(diào)用getInfo('男')輸出:
name: 男
age: undefined
sex: undefined
["男"]
name valley
注:
1.給函數(shù)傳入?yún)?shù)時(shí)是按順序傳入,沒(méi)有傳入?yún)?shù)則為undefined。
2.在函數(shù)內(nèi)部,可以使用arguments對(duì)象獲取到該函數(shù)的所有傳入?yún)?shù)
4.寫(xiě)一個(gè)函數(shù),返回參數(shù)的平方和?
function sumOfSquares() {
var squaresSum= 0
var paraNum = arguments.length
for (var i = 0; i < paraNum; i++) {
squaresSum = squaresSum + arguments[i]*arguments[i]
}
return squaresSum
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
注:arguments.length代表傳入實(shí)參的個(gè)數(shù)
5.如下代碼的輸出?為什么
console.log(a);
var a = 1;
console.log(b);
輸出:
undefined
error(b is not defined)
注:JS中變量聲明會(huì)被提前,因此上述代碼就相當(dāng)于
var a
console.log(a); //undefined
a = 1;
console.log(b); //未定義,error
6.如下代碼的輸出?為什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
輸出:
hello world
error(sayAge is not a function)
注:JS中函數(shù)聲明和變量聲明一樣也會(huì)被提前,因此上述代碼就相當(dāng)于
function sayName(name){
console.log('hello ', name);
}
var sayAge
sayName('world'); //輸出hello world
sayAge(10); //報(bào)錯(cuò),sayAge不是函數(shù)類(lèi)型
sayAge = function(age){
console.log(age);
};
7.如下代碼輸出什么? 為什么
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
輸出結(jié)果為:10
理由:
1.首先f(wàn)oo()和bar()函數(shù)的聲明會(huì)被提前,因此bar()可以正常執(zhí)行
2.接著bar()調(diào)用了foo(),而foo()輸出了個(gè)x
3.在foo()函數(shù)的內(nèi)部并未找到x變量,這時(shí)候JS會(huì)從聲明該函數(shù)所在的作用域去找, 以此往上(上述代碼中也就是最外層的x,即為10)
8.如下代碼輸出什么? 為什么
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
輸出結(jié)果為:30
理由同上,foo()聲明所在的作用域的x的值為30
9.如下代碼輸出什么? 為什么
var a = 1
function fn1(){
function fn2(){
console.log(a)
}
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
var fn = fn1()
fn() //輸出多少
輸出結(jié)果為:2
理由同題7,fn2()聲明所在的作用域的a的值為2
10.如下代碼輸出什么? 為什么
var a = 1
function fn1(){
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
function fn2(){
console.log(a)
}
var fn = fn1()
fn() //輸出多少
輸出結(jié)果為:1
理由同題7,fn2()聲明所在的作用域的a的值為1
11.如下代碼輸出什么? 為什么
var a = 1
function fn1(){
function fn3(){
function fn2(){
console.log(a)
}
fn2()
var a = 4
}
var a = 2
return fn3
}
var fn = fn1()
fn() //輸出多少
輸出結(jié)果為:undefined
這題尤其注意,這題和上面的不同的點(diǎn)在于,由于變量提前導(dǎo)致fn2()的執(zhí)行是在a變量聲明之后,賦值之前(a此時(shí)只聲明了,還沒(méi)有賦值,因此為undefined),即函數(shù)fn3的實(shí)際執(zhí)行是以下的
function fn3(){
function fn2(){
console.log(a)
}
var a
fn2()
a = 4
}
12.如下代碼輸出什么?為什么
var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2);
console.log(obj1 = obj2);
console.log(obj1 == obj2);
輸出:
false
{a: 1, b: 2}
true
理由:
對(duì)象的相等,當(dāng)且僅當(dāng)他們的引用指向內(nèi)存中的相同區(qū)域時(shí)才相等,即他們?cè)跅?nèi)存中的引用地址相同
obj1和obj2分別是兩個(gè)不同的對(duì)象引用,里面存放的地址是不同的,即他們指向的區(qū)域是不同的,即時(shí)區(qū)域中的內(nèi)容是一樣的也不相等
而把通過(guò)obj1=obj2,將obj2中存放的地址賦給了obj1之后,obj1和obj2指向了同一塊區(qū)域,所以最后兩者相等了
13.如下代碼輸出什么? 為什么
var a = 1
var c = { name: 'jirengu', age: 2 }
function f1(n){
++n
}
function f2(obj){
++obj.age
}
f1(a)
f2(c)
f1(c.age)
console.log(a)
console.log(c)
輸出:
1
{name: "jirengu", age: 3}
理由:
a作為實(shí)參傳給了f1的形參n,相當(dāng)于把a(bǔ)的值賦給了n,然后進(jìn)行++n,及n的值變成了2,而a的值仍然是1
c作為實(shí)參傳給了f2的形參obj,c是一個(gè)對(duì)象,里面存放的是指向它里面的內(nèi)容所在內(nèi)存中區(qū)域的地址,在f2中對(duì)這個(gè)地址指向的內(nèi)存區(qū)域里面的age進(jìn)行了前++,所以改變了這塊內(nèi)存區(qū)域中age的實(shí)際的值,即age最后得到3
至于將c.age作為實(shí)參傳給了f1的形參n,仍然是把a(bǔ)ge作為一個(gè)值賦給了n,并沒(méi)有改變age本身
注:值的傳遞并不能改變本身,引用的傳遞才可以
14.寫(xiě)一個(gè)深拷貝函數(shù)
淺拷貝:對(duì)于字符串類(lèi)型,淺拷貝是對(duì)值的復(fù)制,對(duì)于對(duì)象來(lái)說(shuō),淺拷貝是對(duì)對(duì)象地址的復(fù)制,并沒(méi) 有開(kāi)辟新的棧,也就是復(fù)制的結(jié)果是兩個(gè)對(duì)象指向同一個(gè)地址,修改其中一個(gè)對(duì)象的屬性,則另一個(gè)對(duì)象的屬性也會(huì)改變。對(duì)于淺拷貝,子對(duì)象以及子對(duì)象下面的對(duì)象都是共用的。
淺拷貝實(shí)現(xiàn)函數(shù):
var oldObject = {name:"小明",
age:25,
sex:"男",
city:"南京",
wife:{name:"小牛", sex:"女", age:24, city:"北京"},
friends:["小紅", "小白", "小黃"]
}
function shallowCopy(oldObj) {
var newObj = {}
for (var i in oldObj) {
if (oldObj.hasOwnProperty(i)) { //hasOwnProperty()函數(shù)用于指示一個(gè)對(duì)象自身(不包括原型鏈)是否具有指定名稱(chēng)的屬性。如果有,返回true,否則返回false
newObj[i] = oldObj[i]
}
}
return newObj
}
var newObject = shallowCopy(oldObject)
console.log(newObject) //newObject里面的內(nèi)容和oldObject一樣
console.log(newObject.wife == oldObject.wife) //true
console.log(newObject.friends == oldObject.friends) //true,兩個(gè)true說(shuō)明newObject的子對(duì)象并沒(méi)有開(kāi)辟新的內(nèi)存,和oldObject的子對(duì)象共用一塊堆內(nèi)存
深拷貝:深拷貝是開(kāi)辟新的棧,兩個(gè)對(duì)象對(duì)應(yīng)兩個(gè)不同的地址,即指向堆中不同的空間,修改一個(gè)對(duì)象的屬性,不會(huì)改變另一個(gè)對(duì)象的屬性。深拷貝會(huì)遞歸復(fù)制子對(duì)象及子對(duì)象下面的對(duì)象,并且新對(duì)象和舊對(duì)象不是共用一塊堆區(qū)域。
深拷貝實(shí)現(xiàn)函數(shù):
var oldObject = {name:"小明",
age:25,
sex:"男",
city:"南京",
wife:{name:"小牛", sex:"女", age:24, city:"北京"},
friends:["小紅", "小白", "小黃"]
}
function deepCopy(oldObj) {
var newObj = {}
for (var key in oldObj) {
if (typeof oldObj[key] === 'object') {
newObj[key] = deepCopy(oldObj[key]) //是對(duì)象的遞歸拷貝
} else {
newObj[key] = oldObj[key] //非對(duì)象直接賦值
}
}
return newObj
}
var newObject = deepCopy(oldObject)
console.log(newObject) //newObject里面的內(nèi)容和oldObject一樣
console.log(newObject.wife == oldObject.wife) //false
console.log(newObject.friends == oldObject.friends) //false,兩個(gè)false說(shuō)明newObject的子對(duì)象開(kāi)辟新的內(nèi)存,和oldObject的子對(duì)象的堆內(nèi)存不一樣了