JS作用域链 & JS引用类型
立即执行函数表达式是什么?有什么作用?
在 Javascript 中,圆括号()是一种运算符,跟在函数名之后,表示调用该函数。比如,print()就表示调用print函数。
有时,我们需要在定义函数之后,立即调用该函数。
JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。
通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
// 写法一
var tmp = newData;
processData(tmp);
storeData(tmp);
// 写法二
(function () {
var tmp = newData;
processData(tmp);
storeData(tmp);
}());
求n!,用递归来实现。
function factorial(num) {
if(num>0) {
return factorial(num-1)*num;
}
else return 1;
}
以下代码输出什么?
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:"
"男"
[object Arguments] {
0: "饥人谷",
1: 2,
2: "男"
}
"name"
"valley"
"name:"
"小谷"
"age:"
3
"sex:"
undefined
[object Arguments] {
0: "小谷",
1: 3
}
"name"
"valley"
"name:"
"男"
"age:"
undefined
"sex:"
undefined
[object Arguments] {
0: "男"
}
"name"
"valley"
写一个函数,返回参数的平方和?
function sumOfSquares(){
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
答案:
function sumOfSquares() {
var result = 0;
for(var i in arguments){
result += (arguments[i]*arguments[i]);
}
return result;
}
如下代码的输出?为什么?
console.log(a);
var a = 1;
console.log(b);
undefined
VM100:3 Uncaught ReferenceError: b is not defined at <anonymous>:3:17 (anonymous) @ VM100:3
因为变量声明被提前变成:
var a;
console.log(a);
a=1;
console.log(b);
如下代码的输出?为什么?
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
输出:
hello world
VM1098:2 Uncaught TypeError: sayAge is not a function at <anonymous>:2:5 (anonymous) @ VM1098:2
因为第一个函数声明被提前,变成:
function sayName(name){
console.log('hello ', name);
}
sayName('world');
sayAge(10);
var sayAge = function(age){
console.log(age);
};
写一个函数squireArr,其参数是一个数组,作用是把数组中的每一项变为原值的平方
var arr = [3, 4, 6]
function squireArr( arr ){
//var arr = 0x0011
for(var i = 0; i < arr.length; i++){
arr[i] = arr[i] * arr[i];
}
}
squireArr(arr)
console.log(arr) // [9, 16, 36]
如下代码的输出?为什么?
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
输出:10
因为变量和函数的声明被提前,所以代码等价于:
var x;
function foo() {
console.log(x)
};
function bar(){
var x = 30
foo()
};
x =10;
bar() ;
又因为作用域链,所以:
- 函数在执行的过程中,先从自己内部找变量
- 如果找不到,再从创建当前函数所在的作用域去找, 以此往上
- 注意找的是变量的当前的状态
写一个函数squireArr,其参数是一个数组,返回一个新的数组,新数组中的每一项是原数组对应值的平方,原数组不变
var arr = [3, 4, 6]
function squireArr( arr ){
var newArr = [];
for(var i = 0; i < arr.length; i++){
newArr[i] = arr[i] * arr[i];
}
return newArr;
}
var arr2 = squireArr(arr)
console.log(arr) // [3, 4, 6]
console.log(arr2) // [9, 16, 36]
如下代码的输出?为什么?
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
输出:30
因为作用域链。
- 函数在执行的过程中,先从自己内部找变量
- 如果找不到,再从创建当前函数所在的作用域去找, 以此往上
- 注意找的是变量的当前的状态
如下代码的输出?为什么?
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() //输出多少
输出2,因为作用域链。
如下代码的输出?为什么?
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() //输出多少
输出1,作用域链。
如下代码的输出?为什么?
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() //输出多少
输出:undefined
因为声明提前和作用域链,fn3函数内等价于:
function fn3(){
var a;
function fn2(){
console.log(a)
}
fn2()
a = 4
}
var a = 2
return fn3
如下代码的输出?为什么?
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
vendor.7ab21e702e7733b6b702.js:1 {a: 1, b: 2}
vendor.7ab21e702e7733b6b702.js:1 true
因为obj1和obj2一开始指向两个地址,在赋值后指向同一地址。
如下代码的输出?为什么?
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}
因为第一个是值传递,第二个是引用传递。
写一个深拷贝函数。
function deepCopy(oldObj) {
var newObj = {};
for(var key in oldObj) {
if(typeof oldObj[key] === 'object') {
newObj[key] = deepCopy(oldObj[key]);//递归调用
}else{
newObj[key] = oldObj[key];
}
}
return newObj;
}