js函数笔试题

第一题

console.log(a)       //       undefined
    var a = 1;
    var getNum = function() {
        a = 2;
    }
    function getNum() {
        a = 3;
    }
    console.log(a)      //        1
    getNum()
    console.log(a)      //        2

思路:
这道题主要考查声明提升和函数声明先于变量声明这两个知识点。在解析这个js片段的时候是按照这样的顺序:

// 声明提升
function getNum() {
    a = 3;
}
var a;
var getNum;

// 
console.log(a);
a = 1;
getNum = function() {
    a = 2;
}
console.log(a)
getNum()
console.log(a)

第一次输出a的时候仅仅是声明了还没有赋值,所以是undefined。第二次的不用说了。第三次输出2是因为变量声明是无法覆盖函数声明的,一开始getNum指向一个函数,后来赋值成了一个函数表达式,指向了另一个函数。

第二题

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
//问:三行a,b,c的输出分别是什么?
//答案:
//a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1

第三题

function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}

//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

答案:
function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}
//答案:
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3

第四题:this在javascript中是如何工作的

var fullname = 'John Doe';
var obj = {
   fullname: 'Colin Ihrig',
   prop: {
      fullname: 'Aurelio De Rosa',
      getFullname: function() {
         return this.fullname;
      }
   }
};

console.log(obj.prop.getFullname());

var test = obj.prop.getFullname;

console.log(test());

答案
上面的代码打印出Aurelio De Rosa和John Doe。原因是在 JavaScript 中,一个函数的上下文环境,也就是this关键词所引用对象,是依赖于函数是如何被调用的,而不是依赖于函数如何b被定义的。
在第一个console.log()调用中, getFullname()是作为obj.prop的函数被调用的。因此,这里的上下文环境指向后者并且函数返回this对象的 fullname属性。相反,当 getFullname() 被赋为test变量的值时,那个语境指向全局对象(window)。这是因为,test被隐式设置为全局对象的属性。因此,函数调用返回window的fullname属性值,在此段代码中,这个值是通过第一行赋值语句设置的。

第五题:请解释 JavaScript 中 this 是如何工作的。

函数被调用,被谁调用那函数中的this就是谁,没有调用者就是window。所以自执行函数的this也是window

function fn() {
  console.log(this)
}
fn() // this -> window

const obj = {
  name: 'xxx',
  getName: function () {
    console.log(this);
    return this.name
  }
}
obj.getName() // this-> obj

箭头函数中的this是外部作用域的this,解决了之前要缓存this的弊端。

const outer = function outer () {
  console.log(this);
  return function inner () {
    console.log(this)
  }
}
const obj = {
  outer
}
obj.outer()()
const outer = function outer () {
  console.log(this);
  return () => console.log(this)

}
const obj = {
  outer
}
obj.outer()()

给元素绑定事件方法,方法中的this是当前绑定的元素。
构造函数中,this绑定到当前创建的对象实例。
使用apply或call调用 this 将会被显式设置为函数调用的第一个参数。bind也可,属于预处理this

第六题

// 每隔一秒输出一次i值
for(var i = 0; i < 5; i++){
    // TODO
}

此题主要考查闭包和js执行机制。以下几种解法:
大概1秒输出一次的版本:

// 利用立即执行函数形成闭包
(function(i){
    setTimeout(function() {
        console.log(i)
}, i * 1000)})(i)
// 利用setTimeout的第三个参数形成闭包
setTimeout(function(i) {
    console.log(i)
}, i * 1000, i)
// 如果不是题目中指定了var,利用ES6的let就简单多了
for(let i = 1; i < 5; i++) {
    setTimeout(function(){
        console.log(i)
    }, i * 1000)
}
// 再看ES7版本
const sleep = (time) => 
    new Promise((resolve, reject) => 
        setTimeout(resolve, time));
(async function(){
   for(var i = 0; i < 5; i++){
       await sleep(1000);
       console.log(i);
   }
})()

之所以是说是大概,是因为setTimeout并不是延时多少秒后执行函数,而是多少秒后把函数扔进事件队列中等待执行,如果此时队列里有其他任务 的话那就不是精确的1秒了。
关于js执行机制,看这里这一次,彻底弄懂 JavaScript 执行机制

再看比较精确的1秒版本:

for(var i =0; i < 5; i++) {
    var time = new Date();
    while(new Date() - time < 1000) {
    }
    console.log(i)
}

直接阻塞线程一秒钟

第七题

var a = {}
var b = {
    key: "a" 
}
var c = {
    key: "c"
}

a[b] = "123";
a[c] = "456";
console.log(a[b])  // 456

这题主要考查对象。其实这里a[b]和a[c]中的b、c都会调用object.prototype.toString(),都变成了[object Object],这样就与对象中的key值无关了。所以a[b]和a[c]的指向是相同的。

第八题

var f = function() {
    var c = "abc";
    return {
        a: function() {
            return c;
        },
        b: function(d) {
            c = d;
        }
    }
}()
console.warn(f.a())         // abc
console.warn(f.c)           // undefined
console.warn(f.b("wx'w"))    // undefined
console.warn(f.a())         // wxw

这题主要考查的是执行上下文中的作用域链。我们要注意到函数表达式后的那个函数执行符——(),它是个立即执行函数,也就是说f是个包含a、b属性的对象。

console.warn(f.a()) 

当a()的执行上下文被激活时,作用域和变量对象被确定,c是个自由变量,需要在作用域链中向上查找,然受在父级作用域中找到,所以输出“abc”。

console.warn(f.c)

这个就不用说啦,f中没有c这个属性,取不到当然返回undefined。

console.warn(f.b("wxw"))

同第一行一样,修改的是父级作用域中的c,但由于没有返回值所以输出的是undefined。
函数会顺着作用域链查找当前执行环境不存在的变量,对象则从原型链上查找!!!

第九题
数组去重 输入[1,2,3,1,‘1’,‘2’,2]返回[1,2,3,‘1’,‘2’]

(function(arr){
    console.log([...(new Set(arr))])
})([1,2,3,1,'1','2',2])

利用Map结构的key可以是任意类型这个特性,能很好的区分字符’1’和数字1,而普通对象的key值是字符串类型,无法区分这两者。

(function(arr) {
    let hash = new Map();
    arr = arr.reduce((item, value) => {
        hash.has(value) ? '' : hash.set(value, true) && item.push(value)
        return item;
    }, [])
    console.log(arr)
})([1,2,3,1,'1','2',2])

第十题
有两个小写字符串s1、s2,s2是s1经过打乱后增加一个小写字符得到的, 编程得出s2中增加的字符,算法时间复杂度最好接近O(n)(如s1是’abc’,s2是’cbad’,那么增加的字符为‘d’)

解法一:
笔者关于这道题的思考,首先是考虑到增加的字符可能是s1中已经存在的,那通过遍历+indexOf()的方案也就没用了,所以笔者在写这道题的时候考虑到s1、s2只有一个字符之差,索性把s1、s2中的字符都填入一个对象中,统计每个字符的个数,个数为奇数的就是那个多出来的字符了。(另外欢迎在评论区中给出更优解)上代码:

var s1 = "aaabweddccc";
var s2 = "aaaewwbcccdd";
(function(a,b){           
    let all = a + b;
    let allLen = all.length;
    let hash = {};
    for(let i = 0; i < allLen; i++) {
        hash[all[i]] ? hash[all[i]]++ : hash[all[i]] = 1;              
    } 
    console.log(hash)                          
    for(let j in hash) {
        if(hash[j] % 2 !== 0) {
            console.log(j)
        }
    }
})(s1,s2)

运行结果:在这里插入图片描述
解法二:
这个方法是后来想到的。思路是这样的,如果没有插入那个额外的字符之前,对两个字符串进行排序后,两字符串对应位置的字符肯定是相同的,插入一个字符之后,必定有个位置的字符不匹配。

(function(a,b){           
    a = a.split("").sort()
    b = b.split("").sort()
    for(let i = 0, len = b.length; i < len; i++) {
        if(a[i] !== b[i])
        console.log(b[i])             
    } 
})(s1,s2)

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值