前端面试

1.手写call函数

Function.prototype._call = function(context){
    var context = context || window;  
    context.fn = this;
    var args = [...arguments].slice(1);
    var result = context.fn(...args);
    delete context.fn;
    return result;
}
/*
调用call  fn.call(obj,arg1,arg2,arg3...) 
手动实现call时,传递参数context为this要指向的对象;改变this指向让新的对象可以执行该函数,相当于给新的对象添加一个函数,执行完再删除。
*/

2.构造函数中有返回return

function Person(name){

this.name = name;

return {

name:"小明";

}

}

var p1 = new Person('小美') // p1是什么??

function Person(name){

this.name = name;

return "小刚"

}

var p1 = new Person('小美') // p1是什么??

总结:

function _new(constructor,params){
    var args = [].slice.call(arguments); //获取参数数组
    var constructor = args.shift();    // 获取构造器,删除操作改变原数组
    var context = Object.create(constructor.prototype); //创建新的对象,context继承构造函数原型的属性和方法
    var res = constructor.apply(context,args); //改变构造函数this的指向
    return typeof res === 'object' ? res : context; // 返回注意!!
}

3.自己封装cookie的set、get方法

let cookieUtil = {
    set: function(name, value, expires, domain, path, secure) {
        let cookieText = '';
        cookieText += encodeURIComponent(name) + '=' + encodeURIComponent(value);
        if (expires instanceof  Date) {
            cookieText += '; expires=' + expires.toGMTString();
        }
        if (path) {
            cookieText += '; path=' + path;
        }
        if (domain) {
            cookieText += '; domain=' + domain;
        }
        if (secure) {
            cookieText += '; secure=' + secure;
        }
        document.cookie = cookieText;
    },
    get: function(name) {
        let cookieName = encodeURIComponent(name) + '=';
        let cookieStart = document.cookie.indexOf(cookieName);
        let cookieValue = '';
        if (cookieStart > -1) {
            let cookieEnd = document.cookie.indexOf(';', cookieStart);
            if (cookieEnd === -1) {
                cookieEnd = document.cookie.length;
            }
            cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
        }
        return cookieValue;
    },
    delete: function(name, domain, path, secure) {
        this.set(name, '', Date(0), domain, secure);
    }
};

4.跨域请求伪造cors fetch对象中需要哪些属性 mode credentials 等

https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

Fetch API 提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,例如请求和响应。fetch方法可以跨网络异步获取资源。

postData('http://example.com/answer', {answer: 42})
  .then(data => console.log(data)) // JSON from `response.json()` call
  .catch(error => console.error(error))

function postData(url, data) {
  // Default options are marked with *
  return fetch(url, {
    body: JSON.stringify(data), // must match 'Content-Type' header
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, same-origin, *omit
    headers: {
      'user-agent': 'Mozilla/4.0 MDN Example',
      'content-type': 'application/json'
    },
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, cors, *same-origin
    redirect: 'follow', // manual, *follow, error
    referrer: 'no-referrer', // *client, no-referrer
  })
  .then(response => response.json()) // parses response to JSON
}

5.nextTick的底层原理

【涉及到浏览器是如何渲染页面的,只有当DOM树,cssom树,render树,布局,渲染结束后才会去触发宏任务,所以这里应该是事件循环机制的原理】nextTick等价于使用promise、setTimeout等做异步处理。(JS是在布局渲染之后才执行其他宏任务的,所以使用setTimeout就可以了)

nextTick 是在DOM更新循环结束后执行延迟回调,获得更新后的DOM。【注意是执行延迟回调】
实现宏任务:先判断是否能使用setImmediate,如果不能降级使用Messagechannel,如果不能降级使用setTimeout。
nextTick支持promise使用。

6.数组扁平化,去重,倒序排

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

去重   

//1方法
arr.filter((item,index,arr){
    return arr.indexOf(item) === index
})
//2ES6
Array.from(new Set(arr))
//3ES6
[...new Set(arr)]

从大到小排序

arr.sort((a,b) => {
    return b-a;
})

7.防抖节流应用场景

debounce:多次点击某个元素时,以最后一次点击开始计时,达到某个时间之后调用函数。

throttle:多次触发某个事件,以第一次触发开始计时多久后调用执行函数。

  • debounce
    • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
    • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
  • throttle
    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

8.BFC可以解决两个div上边的margin吗 可以

9.v8 的垃圾回收机制

由于不同对象的生存周期不同,所以无法只用一种回收策略来解决问题。V8采用了一种代回收的策略,将内存分为两个生代:新生代(new generation)老生代(old generation)

新生代算法

老生代算法

10.git rebase 是干嘛的?

每一次功能开发, 对多个 commit 进行合并处理。

我们来合并最近的 4 次提交纪录,执行:


git rebase -i HEAD~4

11.Linux命令

https://www.cnblogs.com/fnlingnzb-learner/p/5831284.html

12.es6 class类对应babel转化后是什么?怎么转化的?

babel 可以将ES6语法(JSX)转换为ES5。babel是通过自定义插件的方式实现任何代码的转换。

babel插件通过AST语法树实现,将JS代码转换为AST语法树,并允许对AST进行修改,之后转换成js代码。

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    toString() {
        return '(' + this.name + ',' + this.age + ')';
    }
}


function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.toString = function () {
    return '(' + this.name + ',' + this.age + ')';
}

 ES6中class constructor构造方法 this代表实例对象 new调用时自动调用constructor方法

类的数据类型为函数,类本身指向构造函数。class底层依然是构造函数,class内部定义的方法都是不可枚举的,class类必须用new调用。

实例属性:显式定义在this对象上,否则定义在原型上

静态方法:方法前加上static,该方法不会被实例继承(通过类来调用)

ES6 class实现原理

_instanceof和_classCallCheck的作用
检查声明的class类是否通过new的方式调用,否则会报错

function _instanceof(left, right) {
    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
        return right[Symbol.hasInstance](left);
    } else {
        return left instanceof right;
    }
}
function _classCallCheck(instance, Constructor) {
    if (!_instanceof(instance, Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

_createClass和_defineProperties的作用
_createClass函数有三个参数,Constructor是传入构造函数Person,protoProps 是要添加到原型上的函数数组,staticProps 是要添加到构造函数本身的函数,即静态方法。这里的第二个和第三个参数是可以缺省的,会在_createClass 函数体内判断。

_createClass 函数的作用是收集公有函数和静态方法,将方法添加到构造函数或构造函数的原型中,并返回构造函数。

defineProperties 是将方法添加到构造函数或构造函数的原型中的主要逻辑,遍历函数数组,分别声明其描述符。若enumerable 没有被定义为true,则默认为fals,设置 configurabletrue。以上两个布尔值是为了限制 Object.keys() 之类的方法被遍历到。通过判断 value 是否存在,来判断是否是 getter 和 setter。如果存在 value,就为 descriptor 添加 value 和 writable 属性,如果不存在,就直接使用 get 和 set 属性。
最后,使用 Object.defineProperty 方法为构造函数添加属性。

function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
}

 类的实现

var Person =
    /*#__PURE__*/
    function () {
        function Person(name, age) {
            _classCallCheck(this, Person);

            this.name = name;
            this.age = age;
        }

        _createClass(Person, [{
            key: "toString",
            value: function toString() {
                return '(' + this.name + ',' + this.age + ')';
            }
        }]);

        return Person;
    }();

var p = new Person('Mia', 18);

13.webpack css-loader style-loader ???

14.Object.defineProperty(obj,key,{}) 第三个参数包括哪些属性

configurable  可配置的

enumerable  可枚举的

value 

writable  可写的

15.伪类、伪元素的区别

  • 伪类和伪元素都是用来表示文档树以外的"元素"。
  • 伪类和伪元素分别用单冒号:和双冒号::来表示。
  • 伪类 

    其核心就是用来选择那些不能够被普通选择器选择的文档之外的元素,比如:hover。

  • 伪元素
    其核心就是需要创建通常不存在于文档中的元素,比如::before。

16.说一下上线的整个步骤

17.判断数组的方法

// 1 Array.isArray(arr)
// 2 Object.prototype.toString.call(arr)  "[object Array]"
// 3 arr instanceof Array
// 4 arr.constructor === Array

18.js 中事件是如何执行的

1主线程读取JS代码,此时为同步任务,形成相应的堆和执行栈。

2主线程遇到异步任务,指给对应的异步进程进行处理(webAPI)。

3异步进程处理完毕(ajax返回,DOM事件处理),将相应的异步任务推入任务对列。

4主线程执行完当前代码后,会检查异步任务队列中是否有任务需要执行,如果有,则取出一个任务推入主线程处理。

19.expires 和 max-age的区别

expires绝对的

max-age相对的

max-age是HTTP/1.1中,他是指我们的web中的文件被用户访问(请求)后的存活时间,是个相对的值,相对Request_time(请求时间).
例如:A.html  用户请求时间是18:00,max-age设置的是600的话,相当18:00+600秒过期,也就是相对18:00的时间后面600秒后过期.默认的max-age是由Expires算出来的.

Expires是HTTP/1.0中的,它比max-age要麻烦点.Expires指定的时间分下面二种,这个主要考虑到apache中设置是A还是M.

1.相对文件的最后访问时间(Atime)
当Apache使用A时间来做Expires时.这样设置时.他就和max-age的值相等,因为max-age是相对文件的请求时间(Atime).

例如:ExpiresByType text/html A600

由上面我们得知,Apache设置Atime时,过期为600秒时.
Expires=18:00+600=18:10
max-age=18:00+600=18:10
得出:Expires=max-age

2.绝对修改时间(MTime)
这又分二种情况,我们来拿A.htm来讲
假设文件的建立时间为18:00.

当用户Request请求为18:00时,过期为600秒
Expires=18:00+600=18:10
max-age=18:00+600=18:10
得出:Expires等于max-age

当用户Request请求为18:20时,过期为600秒

Expires=18:00+600=18:10(因为设置成Mtime时,时间由文件建立时间来决定)
max-age=18:20+600=18:30
得出:Expires不等于max-age

另外要注意,象上面这种清况时,max-age优化,所以过期时间为18:30.

 

1. localstorage如果满了,怎么办

问题本质:

localStorage 归根结底就两个作用:持久化存储与跨页面传数据。持久化存储不会出问题,存不进去就存不进去呗,取不出来就去其它地方取,或者不取。问题就出在跨页面传数据上,上一个页面因为 localStorage 存满导致数据没有写入,下一个页面读取数据为空,从而导致错误。

问题根源:

同一个域名共享同一个 localStorage,而同一个域名下存在过多独立的业务线,业务线之间各自为政,毫无节制的攫取公共资源,这就是 localStorage 溢出问题的根源。通过业务类型划分,这是最初架构策略的问题。如果 a 业务挂在 a.xxx.com 下,b 业务挂在 b.xxx.com 下,每个业务有独立的团队维护,localStorage 从公共资源变成团队的私有财产。

理想方案:

1、划分域名。各域名下的存储空间由各业务组统一规划使用

2、跨页面传数据:考虑单页应用、优先采用 url 传数据

3、最后的兜底方案:清掉别人的存储

自己的业务最好统一在 key 上加一个前缀,清空 localStorage 时只删别人的。用户用同一个设备打开同一个 app,在同一个时间只能访问一个业务,因此不会存在某个业务正在使用过程中,localStorage 被其它业务清掉的场景。

2. counter 方法实现每次点击增1(counter)

使用闭包

var getId = (function () {
  
   // "use strict";

    var i = 0;
    return function () {
        return ++i;
    };
    
})();

getId();

3. fibonacci实现

let fibonacci = function() {
    let arr= [0, 1];
    return function(n) {
        let result = arr[n];
        if(typeof result != 'number') {
            result = fibonacci(n - 1) + fibonacci(n - 2);
            arr[n] = result; // 将每次 fibonacci(n) 的值都缓存下来
        }
        return result;
    }
}(); // 执行函数

4.白屏怎么办

5.网络相关,七层,各层是做什么的

物理层:界定连接器和网线的规格

数据链路层:互连设备识别和传送数据帧

网络层:地址管理与路由选择

传输层:管理两个节点之间的数据传输。负责可靠传输

会话层:通信管理。负责建立和断开通信连接。

表示层:设备固有数据格式和网络标准数据格式的转换。

应用层:针对特定应用的协议。

6.HTTPS s代表什么??中间的加密是如何做的?

      对称秘钥:对称密钥加密又叫专用密钥加密,即发送和接收数据的双方必使用相同的密钥对明文进行加密和解密运算。通常有两种模式:流加密和分组加密。

      非对称秘钥:非对称加密算法需要两个密钥:公开秘钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

  1.HTTPS保证数据安全的机制:

          在HTTP的概念中介绍了HTTP是非常不安全的,那么在服务器与客户端传递数据的过程中HTTPS是如何保证数据的安全呢?

            1.客户端向服务器端发起SSL连接请求;(在此过程中依然存在数据被中间方盗取的可能,下面将会说明如何保证此过程的安全)

            2 服务器把公钥发送给客户端,并且服务器端保存着唯一的私钥;

            3.客户端用公钥对双方通信的对称秘钥进行加密,并发送给服务器端;

            4.服务器利用自己唯一的私钥对客户端发来的对称秘钥进行解密,在此过程中,中间方无法对其解密(即使是客户端也无法解密,因为只有服务器端拥有唯一的私钥),这样保证了对称秘钥在收发过程中的安全,此时,服务器端和客户端拥有了一套完全相同的对称秘钥。

            5.进行数据传输,服务器和客户端双方用公有的相同的对称秘钥对数据进行加密解密,可以保证在数据收发过程中的安全,即是第三方获得数据包,也无法对其进行加密,解密和篡改。

   2.CA(电子商务认证机构)认证作用: 

          在上面提到的 客户端向服务器端发起请求时存在数据被盗取的过程:  假如服务器端经由中间方向客户端发送公钥的时候,中间方没有将公钥发送给客户端,而是伪造了医药公钥,并将伪造的公钥发送给客户端,此时客户端用中间方伪造的公钥对自己正确的对称秘钥加密并由中间方发送给服务器端,而中间方将用自己伪造的公钥的私钥对其进行解密,得到正确的对称秘钥,并将得到的正确的对称秘钥用服务器端发过来的公钥进行加密发给服务器端,服务器daunt再用正确的私钥进行解密,也得到正确的对称秘钥,此时客户端,服务器端,中间方三者都拥有一套正确的对称秘钥,可以对传送的数据进行加密,解密。

   为了解决上述问题,一般情况下,服务器端会向CA申请认证书,此证书包含了CA及服务器端的一些信息(可以理解为类似公章),这样,服务器端将证书发给客户端的过程中,中间方是无法伪造的,保证了,发给客户端的公钥是服务器端发送的。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值