前端面试题

DocumentType有什么用?

DOCTYPE是document type(文档类型)的简写,在web设计中用来说明你用的XHTML或者HTML是什么版本。

要建立符合标准的网页,DOCTYPE声明是必不可少的关键组成部分;除非你的XHTML确定了一个正确的DOCTYPE,否则你的标识和CSS都不会生效。

Doctype可声明三种DTD类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。

给100个里绑定点击事件

      利用事件代理, 详见我的另一篇博客:https://blog.csdn.net/Web_J/article/details/83900073

function print() {let person1={ name:"小黄" };let person2=person1

 function print() {
    let person1={
      name:"小黄"
    };
    let person2=person1
    console.log(person1.name)//小黄
    let person3={
      name:person1.name
    };
    person3.name="小张"
    console.log(person1.name)//小黄
    let person4=Object.assign({},person1) 
    //Object.assign()类似深拷贝,只是拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
    person4.name="小强"
    console.log(person1.name)//小黄
    let person5=person2
    person5.name="小马"
    console.log(person1.name)//小马
  }
  print();

var a={x:100}  function A(obj) {var b=obj  b.x=200

var a={x:100}
function A(obj) {
 var b=obj
 b.x=200
 var c=b
 c={x:300} //开辟新内存
 console.log(a.x);//200
 console.log(b.x);//200
 console.log(c.x);//300
}
A(a)
console.log(a);//{x: 200} //修改参数也会改变外面的变量

作用域

var count=10;//全局作用域 标记为f1
function add(){
    var count=0;//函数全局作用域 标记为f2
    return function(){
        count+=1;//函数的内部作用域
        alert(count);
    }
}
var s=add()
s();//输出1
s();//输出2

详看:https://blog.csdn.net/Web_J/article/details/84866582

class Animal {constructor(){this.type = 'animal'}

class Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        setTimeout(function(){
            console.log(this.type + ' says ' + say)  //setTimeout()的this指向window或global对象
        }, 1000)
    }
}
 
var animal = new Animal()
animal.says('hi')  //undefined says hi
 

详看:https://blog.csdn.net/Web_J/article/details/84941963

倒计时10秒

 window.onload = function(){
            let i = 10;
            let timer = setInterval(function(){
            i<0 ? clearInterval(timer) : document.body.innerHTML = i--
            },1000);
 
        }

('b' + 'a' + + 'a' + 'a').toLowerCase()输出什么?

好吧,才疏学浅的我看到这题的答案是:baaa

先说下正确答案,以便大家跟着我一个思路:banana

既然这么说了,那这一定是错误答案了,下面我们来解析一下这个题:

1. js运算优先级和隐式转换

仔细一想,这题估计和JavaScript运算符优先级、隐式转化有关系。
于是先去MDN查了一下JavaScript运算符优先级
我先把上面代码用到的运算符和优先级列举出来:

圆括号(20)>一元正号(16)>加法(13)


好了,现在我们来解析一下这个代码:

'b' + 'a' + (+ 'a') + 'a'

一元正号的优先级高于加法,所以我们这样用括号会让这个代码更加清晰<br> 先运算优先级高的,也就是括号里面的,在与运算括号外面的


2. 一元正号 运算

这时候就涉及到第二个重要的知识点,一元正号的运算,先来看官方文档:

一元正号运算符位于其操作数前面,计算其操作数的数值,如果操作数不是一个数值,会尝试将其转换成一个数值

尽管一元负号也能转换非数值类型,但是一元正号是转换其他对象到数值的最快方法,也是最推荐的做法,因为它不会对数值执行任何多余操作。

它可以将字符串转换成整数和浮点数形式,也可以转换非字符串值true,false和null。小数和十六进制格式字符串也可以转换成数值。

负数形式字符串也可以转换成数值(对于十六进制不适用)。如果它不能解析一个值,则计算结果为 NaN

注意看上面的这段话:如果操作数不是一个数值,会尝试将其转换成一个数值和如果它不能解析一个值,则计算结果为 NaN

那上面代码的+ 'a'就是会变成NaN,过程如下:

'b' + 'a' + NaN + 'a'

// to

'b' + 'a' + "NaN" + 'a'

最终在调用toLowerCase函数转成小写,就变成了banana

let a = {n : 1};let b = a;a.x = a = {n: 2}; 

        let a = {n : 1};
        let b = a;
        a.x = a = {n: 2}; 
        console.log(a.x)
        console.log(b.x)

答案:let a = {n : 1};let b = a;a.x = a = {n: 2};console.log(a.x) console.log(b.x)_微 光的博客-CSDN博客

你知道的网页制作会用到的图片格式有哪些 ?

1.png-8 、 png-24 、 jpeg 、 gif 、 svg
2.但是上面的那些都不是面试官想要的最后答案。面试官希望听到的是Webp , Apng 。(是否有关注新技术,新鲜事物)  
3.Webp: WebP 格式,姑歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积⼤约只有 JPEG 的 2/3 ,并能节省流量的服务器带宽资源和数据空间。
  Facebook Ebay 等知名网站已经开始测试并使用 WebP 格式。
4.在质量相同的情况下,WebP格式图像的体积要比JPEG格式图像小 40%
5.Apng:全称是 “Animated Portable Network Graphics” , 是PNG的位图动画扩展,可 以实现png格式的动态图⽚效果。04年诞生,但一直得不到各浏览器支持,直到
  目前得到iOS safari 8 的支持,有望代替 GIF 成为下代动态图标准  

实现函数柯里化(使用多个参数的一个函数转换成一系列使用一个参数的函数)

function currying(fn) {
  let args_arr = [], max_length = fn.length
  let closure = function (...args) {
    // 先把参数加进去
    args_arr = args_arr.concat(args)
    // 如果参数没满,返回闭包等待下一次调用
    if (args_arr.length < max_length) return closure
    // 传递完成,执行
    return fn(...args_arr)
  }
  return closure
}
function add(x, y, z) {
  return x + y + z
}
curriedAdd = currying(add)
console.log(curriedAdd(1, 2)(3))

 JS 分步实现柯里化函数_weixin_34329187的博客-CSDN博客

js实现栈

function ArrayStack(){  
    var arr = [];  
        //压栈操作  
    this.push = function(element){  
        arr.push(element);  
    }  
        //退栈操作  
    this.pop = function(){  
        return arr.pop();  
    }  
        //获取栈顶元素  
    this.top = function(){  
        return arr[arr.length-1];  
    }  
        //获取栈长  
    this.size = function(){  
        return arr.length;  
    }  
        //清空栈  
    this.clear = function(){  
        arr = [];  
        return true;  
    }  
  
    this.toString = function(){  
        return arr.toString();  
    }  
}

单页面和多页面的区别

引入cdn字体会发生什么

字体跨域 

字体文件在CDN服务器上、项目部署在自己的服务器上,字体文件就出现了跨域加载的问题。

处理这种跨域,只要设置Access-Control-Allow-Origin,允许目标域名访问就可以了,Access-Control-Allow-Origin是HTML5新增的一个特性,在资源类的域名下做如下配置(nginx的配置,apache相似处理)​

location ~ .*\.(eot|ttf|ttc|otf|eot|woff|woff2|svg)(.*) { add_header Access-Control-Allow-Origin http://www.yourdomain.com; }

JS扁平化数组

flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]

递归

function flatten(arr){
    var result=[];
    for(var i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            result=result.concat(flatten(arr[i]))
        }else{
            result.push(arr[i]);
        }
    }
    return result;
}

扩展运算符

function flatten(arr) {
    while(arr.some(item=>Array.isArray(item))) { 
        //some() 方法用于检测数组中的元素是否满足指定条件
        arr = [].concat(...arr);
    }
    return arr;
}

js事件监听和JQ事件监听的写法

       详见JS如何给ul下的所有li绑定点击事件,点击使其弹出下标和内容_微 光的博客-CSDN博客_给ul下的所有li添加点击事件

计算字符串中每个字符出现的次数

const arr="abcdaabc";
let counter = {};
for (let i = 0, len = arr.length; i < len; i++ ) {
    counter[arr[i]] ? counter[arr[i]]++ : counter[arr[i]] = 1;
}
console.log(counter);// {a: 3, b: 2, c: 2, d: 1}

去除字符串中的无效字符和乱码

/**
   * 请处理给定字符串:
   *   - 去掉无用字符和乱码, 只保留大小写英文字母, 单引号, 和空格
   *   - 把一个或多个连续无用字符和乱码换成一个空格
   * @param str: 字符串, 例 "I'm我driving是to乱Beijing码after breakfast"
   * @return str: 例 "I'm driving to Beijing after breakfast"
   */
 

decode=str => {
    var reg = /([a-z]|[A-Z]|\'|\s)+/g // \s查找空白字符。
    var b = str.match(reg) //match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
    return b.join(' ');

  }
  var str = "I'm我driving是to乱Beijing码after breakfast"
  decode(str)

JS大数相加

let a = "9007199254740991";
let b = "1234567899999999999";

function add(a ,b){
   //取两个数字的最大长度
   let maxLength = Math.max(a.length, b.length);
   //用0去补齐长度
   a = a.padStart(maxLength , 0);//"0009007199254740991" padStart()用于头部补全,padEnd()用于尾部补全
   b = b.padStart(maxLength , 0);//"1234567899999999999"
   //定义加法过程中需要用到的变量
   let t = 0;
   let f = 0;   //"进位"
   let sum = "";
   for(let i=maxLength-1 ; i>=0 ; i--){
      t = parseInt(a[i]) + parseInt(b[i]) + f;
      f = Math.floor(t/10);
      sum = t%10 + sum;
   }
   if(f == 1){
      sum = "1" + sum;
   }
   return sum;
}

git版本回退

git reset --hard id

Function.prototype.a = 'a';Object.prototype.b = 'b';function Person(){};

Function.prototype.a = 'a';
Object.prototype.b = 'b';
function Person(){};
var p = new Person();
console.log('p.a: '+ p.a); // p.a: undefined
console.log('p.b: '+ p.b); // p.b: b
 

不少人第一眼看上去就觉得很疑惑,p不是应该继承了Function原型里面的属性吗,为什么p.a返回值是undefined呢?
其实,只要仔细想一想就很容易明白了,Person函数才是Function对象的一个实例,所以通过Person.a可以访问到Function原型里面的属性,但是new Person()返回来的是一个对象,它是Object的一个实例,是没有继承Function的,所以无法访问Function原型里面的属性。

但是,由于在js里面所有对象都是Object的实例,所以,Person函数可以访问到Object原型里面的属性,Person.b => 'b'

qiankun的原理

  • HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
  • 样式隔离,确保微应用之间样式互相不干扰。
  • JS 沙箱,确保微应用之间 全局变量/事件 不冲突。

为什么不用iframe

  • url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
  • UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中..
  • 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
  • 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。

arr = [1,2,3,4],如何得到arr.fn = [1,2,3,4,1,2,3,4]?

1.arr.concat(arr)  //concat()方法生成了一个新的数组,并不改变原来的数组。

2.arr.push.apply(arr,arr) //使用apply劫持数组的push方法

3.[...arr,...arr] //扩展运算符(...)

杨辉三角的JS实现

 
      function compute(m, n) {
        if (n == 0) {
          return 1; //每行第一个数为1
        } else if (m == n) {
          return 1; //最后一个数为1
        } else {
          //其余都是相加而来
          return compute(m - 1, n - 1) + compute(m - 1, n);
        }
      }
      function yanghui(n) {
        //杨辉三角,N为行数
        for (var i = 0; i < n; i++) {
          //一共N行
          for (var j = 0; j <= i; j++) {
            //每行数字的个数即为行号、例如第1行1个数、第2行2个数
            document.write(compute(i, j) + " ");
          }
          document.write("<br>");
        }
      }
      yanghui(15)
    

 二分查找

可用递归和非递归两种方式,折半查找

JS二分查找实现及时间复杂度_微 光的博客-CSDN博客

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值