饥人谷技术博客

JavaScript常见作用域问题

2017-08-27  本文已影响0人  zh_yang

1、立即执行函数表达式是什么?有什么作用

我们都知道,一般定义一个函数有函数声明和函数表达式两种方法:
function fnName () {…};   //函数声明
var fnName = function () {…};   //函数表达式
两者的区别是:

所以,要在函数体后面加括号就能立即调用,则这个函数必须是函数表达式,不能是函数声明。

在function前面加()、!、+、-、=等运算符,都将函数声明转换成函数表达式,消除了javascript引擎识别函数表达式和函数声明的歧义,告诉javascript引擎这是一个函数表达式,不是函数声明,可以在后面加括号,并立即执行函数的代码。

(function(){
  console.log(123)
})()         //输出123

(function(){
  console.log(123)
}())         //输出123

!function(){
  console.log(123)
}()         //输出123

+function(){
  console.log(123)
}()         //输出123

-function(){
  console.log(123)
}()         //输出123

var a=function(){
  console.log(123)
}()         //输出123

加括号是最安全的做法,因为!、+、-等运算符还会和函数的返回值进行运算,有时造成不必要的麻烦。

那么这样做有什么作用:
在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,根据javascript函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

2、求n!,用递归来实现

利用n!等于n(n-1)!,(n-1)!等于(n-1)((n-1)-1)!,直至括号内的值为1,另外0!等于1。

function fac(n){
  if( n===1 || n===0 ){return 1}
  return (n*fac(n-1))
}
console.log(fac(1))     //输出1
console.log(fac(2))     //输出2
console.log(fac(3))     //输出6
console.log(fac(4))     //输出24
console.log(fac(5))     //输出120

也可以用三元运算符 ' ? ' 写作:

function fac(n){
  return n===0 || n===1 ? 1 : n*fac(n-1)
}
console.log(fac(5))     //输出120

另外也可以利用循环来处理

function fac(n){
  var i =1
  if( n===1 || n===0 ){console.log(1)}
  else{
    for( var j=n;j>1;j--){
      i*=j
    }
    console.log(i)
  } 
}
fac(5)     //输出120

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('男');

注意:

function getInfo(){
            arguments[0]='饥人谷'
            arguments[1]=2
            arguments[2]='男'
            console.log('name:','饥人谷')     
            console.log('age:', 2)
            console.log('sex:', '男')
            console.log(['饥人谷',2,'男'])
            arguments[0] = 'valley'
            console.log('name', 'valley')
}
getInfo()

/*输出:
name: 饥人谷
age: 2
sex: 男
["饥人谷", 2, "男"]
name valley
*/

getInfo('小谷', 3);相当于

function getInfo(){
            arguments[0]='饥人谷'
            arguments[1]=3
            arguments[2]=undefined
            console.log('name:','饥人谷')     
            console.log('age:', 3)
            console.log('sex:', undefined)
            console.log(['饥人谷',3])
            arguments[0] = 'valley'
            console.log('name', 'valley')
}
getInfo()

/*输出:
name: 饥人谷
age: 3
sex: undefined
["饥人谷", 3]
name valley
*/

getInfo('男');相当于

function getInfo(){
            arguments[0]='男'
            arguments[1]=undefined
            arguments[2]=undefined
            console.log('name:','男')     
            console.log('age:', undefined)
            console.log('sex:', undefined)
            console.log(['男'])
            arguments[0] = 'valley'
            console.log('name', 'valley')
}
getInfo()

/*输出:
name: 男
age: undefined
sex: undefined
["男"]
name valley
*/

四、 写一个函数,返回参数的平方和?

function sumOfSquares(){
   }
   var result = sumOfSquares(2,3,4)
   var result2 = sumOfSquares(1,3)
   console.log(result)  //29
   console.log(result2)  //10

解答思路:遍历每一个传入的参数,求它们的平方和;通过不同遍历的方法,有不同的写法。

循环每执行一次,都要检查一次 array.length 的值,读属性要比读局部变量慢,尤其是当 array 里存放的都是 DOM 元素(像 array = document.getElementByClassName(“class”);),因为每次读 array.length 都要扫描一遍页面上 class=”class” 的元素,速度更是慢得抓狂。

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

for-in 需要分析出 array 的每个属性,这个操作的性能开销很大

function sumOfSquares(){
    var sum=0
    for(i in arguments){
        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
function sumOfSquares(){
    var sum=0
    var length=arguments.length
    for(var i=0;i<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
function sumOfSquares(){
    var sum=0
    var i=arguments.length
    while(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

5、如下代码的输出?为什么

console.log(a);
var a = 1;
console.log(b);

由于变量提升的原则,上述代码相当于

var a
console.log(a)    //输出undefined
a=1
console.log(b)    //报错:Uncaught ReferenceError: b is not defined

6、 如下代码的输出?为什么

sayName('world');
    sayAge(10);
    function sayName(name){
        console.log('hello ', name);
    }
    var sayAge = function(age){
        console.log(age);
    };

输出:"hello" "world" Uncaught TypeError: sayAge is not a function

7、 如下代码输出什么? 为什么

var x = 10
bar() 
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}

输出:10

8、如下代码输出什么? 为什么

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}   

输出: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() //输出多少

输出: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() //输出多少

输出: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() //输出多少

输出:undefined

12、.如下代码输出什么?为什么

var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2);   //输出false
console.log(obj1 = obj2);    //输出{a:1, b:2}
console.log(obj1 == obj2);   //输出true

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)     //输出 1 
console.log(c)     //输出 {name: "jirengu", age: 3}

14、写一个深拷贝函数

思路:深拷贝的难点是对对象中嵌套的对象进行深拷贝,而不是直接引用,如嵌套的对象、数组、函数等typeof返回值为object的属性或方法;但是null除外,虽然typeof null返回object,但是他是一个基本类型,不需要,深度拷贝。
利用typeof,对对象深拷贝:

var soldier1 = {
    name: '侦察兵', 
    age: 3,
    equipment:{rifle:'AK-47',pistol:'desertEagle',knife:null},
    family:['father','sister'],
    other:null
}
function deepCopy(oldObj) {
        var newObj = {}
        for(var key in oldObj) {
            if(typeof oldObj[key] === 'object' && oldObj[key]) {
                newObj[key] = deepCopy(oldObj[key])
            }else{
                newObj[key] = oldObj[key]
            }
        }
        return newObj;
    }
var soldoer2=deepCopy(soldier1)
console.log(soldoer2)

/*输出
{
age:3
equipment:{rifle: "AK-47", pistol: "desertEagle", knife: null}
family:{0: "father", 1: "sister"}
name:"侦察兵"
other:null
}
*/
console.log(soldier1==soldoer2)     //输出 false,已经深拷贝
上一篇 下一篇

猜你喜欢

热点阅读