前端校招美团面试 第一篇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n0UJb49H-1593429409229)(https://static01.imgkr.com/temp/d39c0ea47bfe42a59d670a6eb6d910fe.png)]

1. js异步加载的方式

方案一、$(document).ready()

需要引入jquery

兼容所有浏览器

$(document).ready(function() {
    alert("加载完成!");
});
方案二、<script>标签的async="async"属性

async属性是HTML5新增属性,需要Chrome、FireFox、IE9+浏览器支持

async属性规定一旦脚本可用,则会异步执行

async属性仅适用于外部脚本

此方法不能保证脚本按顺序执行

<script type="text/javascript" src="xxx.js" async="async"></script>
方案三、<script>标签的defer="defer"属性

defer属性规定是否对脚本执行进行延迟,直到页面加载为止

如果脚本不会改变文档的内容,可将defer属性加入到<script>标签中,以便加快处理文档的速度

兼容所有浏览器

此方法可以确保所有设置了defer属性的脚本按顺序执行

方案四、动态创建<script>标签

兼容所有浏览器

(function(){
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = "http://code.jquery.com/jquery-1.7.2.min.js";
    var tmp = document.getElementsByTagName('script')[0];
    tmp.parentNode.insertBefore(script, tmp);
})();

2. 堆排序原理

需要注意的是 大顶堆 是为了 实现升序排序,小顶堆是为了实现降序排序
参考JS实现堆排序

3.vue组件通信方式

组件间传递数据(props/emit、$parent/$childen、eventBus、vuex/localStorage,provide/inject,$attr/$listien;好吧,我只知道前四个。
详细的参考:vue组件间通信六种方式(完整版)

5.Vue双向绑定原理

vue 双向绑定的原理是基于 vue 响应式原理的

也就是说双向绑定原理解决的是

  1. 视图的变化–>影响到内部的data
  2. 内部data变化–>影响到视图

第一步的实现就是用监听事件来实现
而第二步的实现就是响应式原理所解决的。

例如

<input v-model = "name">

会被编译成

<input value = "name">

<script>
  input.addEventListen("input",($event)=>{
    name = $event.target.value
  })
</script>

从而第一步就实现了,接下来要实现内部data变化–>影响到视图,就是响应式原理的工作了。

6.sessionStrage 会话结束就是失效,那会话究竟是什么时候失效?

所有人都知道,localStorage和sessionStorage的最大区别是生命周期,一个永久,一个仅针对一个会话期间有效。那么,到底什么是一个会话?多个标签页之间的数据是否会共享呢?

后台的session

我们对会话session的认识一般都是从后台的session开始的,比如Java的session,它是基于往cookie写入一个JSESSIONID来实现的,所以,只要你不是打开一个隐身窗口,无论你开多少个标签页,不同标签页之间都会被认为是一个session,你在这个标签页登录了,新开一个标签输入地址,仍然是登录状态。

sessionStorage的session

但是直到今天才发现,HTML5中的这个sessionStorage和传统后台的session并不完全是同一个东西,主要是在多个标签页数据是否会共享的问题上的不同。

误区:之前一直以为,同一个窗口,只要会话还没有过期,不同标签页之间,相同域名下的sessionStorage是一样的。

正确答案:刷新当前页面,或者通过location.href、window.open、或者通过带target="_blank"的a标签打开新标签,之前的sessionStorage还在,但是如果你是主动打开一个新窗口或者新标签,对不起,打开F12你会发现,sessionStorage空空如也。

也就是说,sessionStorage的session仅限当前标签页或者当前标签页打开的新标签页,通过其它方式新开的窗口或标签不认为是同一个session。

大家可以亲自测试一下,手动打开的新标签和点A标签打开的新标签效果完全不一样。

今天又碰到有关sessionStorage的一个问题,比如当我通过A标签打开新的窗口时,在新窗口删除同样的数据,旧窗口的却还在。

经过测试发现:

通过带target="_blank"的A标签、window.open等方式打开新窗口时,会把旧窗口(或标签)的sessionStorage数据带过去,但从此之后,新窗口(或标签)的sessionStorage的增删改和旧窗口已经没有关系了,如果只是在当前标签内跳转新页面(或者刷新),数据还会保留(前提当然是同域)。

总之,在处理sessionStorage时,只要打开新窗口就要特别注意了,新旧窗口数据不会互相同步。

7.跨域

前端常见跨域解决方案(全)

8. {} 和 [] 的 valueOf 和 toString 的结果是什么?

{} 的 valueOf 结果为 {} ,toString 的结果为 "[object Object]"
[] 的 valueOf 结果为 [] ,toString 的结果为 ""
  • toString是把对象转换为字符串;
  • valueOf是把对象转换du成一个基zhi本数据的值
  • valueOf偏向dao于运算,toString偏向于显示。
  1. 在进行对象转换时(例如:alert(a)),将优先调用toString方法,如若没有重写toString将调用valueOf方法,如果两方法都没有重写,按Object的toString输出。
  2. 在进行强转字符串类型时将优先调用toString方法,强转为数字时优先调用valueOf。
  3. 在有运算操作符的情况下,valueOf的优先级高于toString。
    // 对象在参与运算及比较的时候,js引擎会自动的帮我们去调用这两个方法.
    
    // 调用规则:
    //  1. 默认先调用valueOf方法(valueOf 来源于 Object的原型),尝试把对象转成简单数据类型,
        2. 如果没有得到简单数据类型,再继续去调用toString方法
    //  作用: 将对象转成原始值(简单数据类型),但是Object原型上的valueOf达不到目的, 把对象自身给返回了

    /*  var arr = [1,2,3];
        console.log(arr + 1); // 1,2,31
    //  arr.valueOf()  ==> arr
    //  arr.toString() ==> "1,2,3"
    //  "1,2,3" + 1    ==> "1,2,31"
    
    console.log(arr - 0); // NaN  
    // "1,2,3" - 0
    console.log(arr + "6班学习好努力"); // 1,2,36班学习好努力*/

    // var obj = {
    //     name: "lw"
    // };
    // console.log(obj * 1);  // NaN 
    // obj.valueOf() ==> obj
    // obj.toString() ==> "[object Object]"
    // "[object Object]" * 1
    // console.log(obj + "1");  // [object Object]1

    // console.log([] == ![]);  // true
    //  [] == false  ==> 都转数值进行比较
    //  [].valueOf() ==> []
    //  [].toString()  ==> ""
    //  +""  ==> 0

    //  console.log({} == !{});
    // {} == false   ==> 都转数值进行比较
    // {}.valueOf()  ==> {}
    // {}.toString() ==> "[object Object]"
    // +"[object Object]" ==> NaN (字符串转成数值 ===>  NaN, 不是一个数字)1:
        // var obj = {};
        // console.log(obj.toString()); // "[objectObject]"2:
        // var a = {},
        // b = { key: 'b' };
        // c = { key: 'c' };
        // a[b] = 123;
        // a[c] = 456;
        // console.log(a[b]);   //456
    
    // 给如果对象的属性类型不是一个字符串时,就会去转换.
        // js会自动让对象去调用这两个方法,默认先valueOf(),如果没有得到简单数据类型,再去调用toString()
        // 其中对象a中的属性 b ==> "[object,Object]" ,等同于 给对象a,使用[]语法,去添加属性并赋值
        // 再看对象a中的属性 c ==> "[object,Object]" ,等同于 修改同一个属性的属性值,所以最终的到的结果是456

9. 写一个通用的事件侦听器函数

const EventUtils = {
  // 视能力分别使用dom0||dom2||IE方式 来绑定事件
  // 添加事件
  addEvent: function(element, type, handler) {
    if (element.addEventListener) {
      element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
      element.attachEvent("on" + type, handler);
    } else {
      element["on" + type] = handler;
    }
  },

  // 移除事件
  removeEvent: function(element, type, handler) {
    if (element.removeEventListener) {
      element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
      element.detachEvent("on" + type, handler);
    } else {
      element["on" + type] = null;
    }
  },

  // 获取事件目标
  getTarget: function(event) {
    return event.target || event.srcElement;
  },

  // 获取 event 对象的引用,取到事件的所有信息,确保随时能使用 event
  getEvent: function(event) {
    return event || window.event;
  },

  // 阻止事件(主要是事件冒泡,因为 IE 不支持事件捕获)
  stopPropagation: function(event) {
    if (event.stopPropagation) {
      event.stopPropagation();
    } else {
      event.cancelBubble = true;
    }
  },

  // 取消事件的默认行为
  preventDefault: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
    } else {
      event.returnValue = false;
    }
  }
};

10.手动实现 Array.prototype.map 方法

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

function map(arr, mapCallback) {
  // 首先,检查传递的参数是否正确。
  if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') { 
    return [];
  } else {
    let result = [];
    // 每次调用此函数时,我们都会创建一个 result 数组
    // 因为我们不想改变原始数组。
    for (let i = 0, len = arr.length; i < len; i++) {
      result.push(mapCallback(arr[i], i, arr)); 
      // 将 mapCallback 返回的结果 push 到 result 数组中
    }
    return result;
  }
}

手动实现Array.prototype.filter方法

filter()方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
function filter(arr, filterCallback) {
  // 首先,检查传递的参数是否正确。
  if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') 
  {
    return [];
  } else {
    let result = [];
     // 每次调用此函数时,我们都会创建一个 result 数组
     // 因为我们不想改变原始数组。
    for (let i = 0, len = arr.length; i < len; i++) {
      // 检查 filterCallback 的返回值是否是真值
      if (filterCallback(arr[i], i, arr)) { 
      // 如果条件为真,则将数组元素 push 到 result 中
        result.push(arr[i]);
      }
    }
    return result; // return the result array
  }
}

手动实现Array.prototype.reduce方法

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

function reduce(arr, reduceCallback, initialValue) {
  // 首先,检查传递的参数是否正确。
  if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== 'function') 
  {
    return [];
  } else {
    // 如果没有将initialValue传递给该函数,我们将使用第一个数组项作为initialValue
    let hasInitialValue = initialValue !== undefined;
    let value = hasInitialValue ? initialValue : arr[0];// 如果有传递 initialValue,则索引从 1 开始,否则从 0 开始
    for (let i = hasInitialValue ? 0 : 1, len = arr.length; i < len; i++) {
      value = reduceCallback(value, arr[i], i, arr); 
    }
    return value;
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值