前端常见概念讲解

一、原始类型有哪几种?对象类型和原始类型有什么区别?null是对象吗?

6个原始类型,原始类型存储的是值,没有函数能够调用的,string类型比较特殊,如 :('test').toString(),执行该方法时,'test'会被强制转换成String类型(对象),从而能够调用对应的方法 number string null undefined symbol booleancss

对象类型存储的是指针,而原始类型存储的是值,当建立一个对象的时候,内存中会开辟一个空间来存放值,经过指针指向该内存空间。html

二、如何准确判断数据类型?typeof、constructor、instanceof、Object.prototype.toString.call()

一、使用typeof进行判断前端

typeof 除了null,判断原始类型是准确的,其余类型判断都为object(除了function)
typeof 'test'           > "string"
typeof 1                > "number"
typeof undefined        > "undefined"
typeof true             > "boolean"
typeof Symbol()         > "symbol"
typeof null             > "object"
typeof []               > "object"
typeof {}               > "object"

typeof function aaa(){} > "function"

二、使用constructor进行判断

('test').constructor.name           > "String"
(2).constructor.name                > "Number"
(true).constructor.name             > "Boolean"
([]).constructor.name               > "Array"
({}).constructor.name               > "Object"
(function aa(){}).constructor.name  > "Function"
复制代码

constructor判断类型,看似完美,但也存在缺陷,由于对象的constructor是能够更改的,更改后,判断就不可靠了vue

三、使用instanceof
(1) instanceof Number                   > false
('test') instanceof String              > false
({}) instanceof Object                  > true
([]) instanceof Object                  > true
([]) instanceof Array                   > true
(function aaa(){}) instanceof Function  > true
复制代码

能够看出instanceof只能准确判断出对象和函数类型,其余就不能精准判断了。node

四、Object.prototype.toString.call()webpack

以上三种结合起来能够判断数据类型,这里提供一种终极方案。使用Object对象的原型方法toStringios

var test = Object.prototype.toString
test.call(2)            > "[object Number]"
test.call('test')       > "[object String]"
test.call(null)         > "[object Null]"
test.call(undefined)    > "[object Undefined]"
test.call([])           > "[object Array]"
test.call({})           > "[object Object]"
test.call(function(){}) > "[object Function]"
test.call(Symbol())     > "[object Symbol]"
复制代码

三、JS原型和原型链

什么是原型?es6

任何对象都有一个原型对象,原型对象,由对象的内置属性_proto_指向它的构造函数的prototype对象,任何对象都是由一个构造函数建立的,不是每一个对象都有prototype属性,只有方法才有。web

什么是原型链?json

原型链的核心是依赖_proto_的指向,当自身不存在属性时,就一层一层的去查找建立对象的构造函数,直到查找到Object时,就没有_proto_指向了。 如下为简单的原型链分析

function Person(name){
    this.name = name;
}
var p = new Person('hanhan');

/* new的过程分三步 (1) var p = {};--初始化对象p (2) p.__proto__ = Person.prototype;--将对象p的__proto__设置为Person的prototype (3)Person.call(p,'hanhan');--调用构造函数Person来初始化p */

/* p.__proto__ === Person.prototype > true Person.prototype.__proto__ === Object.prototype > true Object.prototype.__proto__ > null */

//因而可知,原型链的顶端是Object,最终__proto__指向null
复制代码

四、闭包

什么是闭包?

闭包是函数和声明该函数的词法环境的组合。如:函数A内部中存在函数B,函数B能够访问函数A中的变量,这就是闭包

function A{
        let age =18;
        window.B = function () {
            console.log(age);
        }
    }
    B(); //打印:18

    /* 有个需求,延迟打印循环的值,代码以下 */
    for(var i = 0;i<10;i++){
        setTimeout(function(){
            console.log(i);
        },0);
    }

    //打印结果为10个10,显然不符合需求,由于setTimeout为异步函数,执行的时候i已经变成10,可使用闭包解决这问题

    for(var i = 0;i<10;i++){
        (function(value){
            setTimeout(function(){
                console.log(value);
            },0);
        })(i);
    }
复制代码

闭包有哪些做用?

主要有两点用处:

一、能够读取函数内部的变量

二、让这些变量的值始终保持在内存中

注意点:

一、使用闭包时,因为变量会被保存在内存中,内存消耗大,因此不能滥用。IE浏览器中可能会致使内存泄露,因此在退出函数以前,将不适用的局部变量进行删除。

五、浅拷贝和深拷贝

浅拷贝只会拷贝全部属性值到新的对象,若是属性值包含对象的话,那么拷贝的是其地址,浅拷贝可使用Object.assgin方法,还能够经过扩展运算符来实现浅拷贝,如:let b = {...a};

在不少状况下,咱们须要用到深拷贝,如何实现深拷贝呢?

一、jQuery中$.extend能够实现深拷贝

二、JSON.parse(JSON.stringify(obj))--该方法会忽略undefined、symbol,不能序列化对象

三、手动实现一个简单的深拷贝

/** * 实现深拷贝 * @param {被深拷贝对象} obj */
function deepClone(obj){
    //判断是否为对象,除null外
    function isObj(o){
        return (typeof o === 'object' || typeof o === 'function') && o !==null
    }
    if(!isObj(obj)){
        throw new Error('传入的值非对象');
    }
    //判断是不是数组
    let isArray = Array.isArray(obj);
    let newObj = isArray ? [...obj] : {...obj}
    Reflect.ownKeys(newObj).forEach(key=>{
        //判断属性对应的值是否为对象,若是是对象的话就进行递归clone
        newObj[key] = isObj(obj[key]) ? deepClone(obj[key]) : obj[key]
    });
    return newObj;
}
复制代码

六、继承

es6中新增了class,用此来实现继承很方便

/** * 继承 * class只是语法糖,本质仍是函数 */

//父类
class Parent{
    // 构造函数,在new的时候执行
    constructor(value){
        this.val = value;
    }

    getValue(){
        console.log(this.val);
    }
}

//子类
class Child extends Parent{
    constructor(value,name){
        super(value)
        this.name = name;
    }

    sayHello(){
        console.log(this.name);
    }
}

var aaa = new Child('18','piao');
复制代码

七、ES6新特性

1:let、const

二、Proxy

new Proxy(aaa,{
    get(target, property, receiver){
        console.log('获取值');
        return Reflect.get(target, property, receiver)
    },
})
复制代码

三、map 生成新数组,遍历原数组,进行变换放入到新的数组

[1,2,3,4].map(v=>v*v)   // ->[1,4,9,16]
复制代码

四、filter 生成新数组,遍历数组,将返回值为true的元素放入新的数组

[1,2,3,4].filter(val=>val>=3)    // ->[3,4]
复制代码

五、reduce 能够将数组中元素,经过回调函数最终转换成一个值,如实现数组元素求和,第二个参数表明初始值

[1,2,3,4].reduce((acc,current)=>acc+current,0)    // ->10
复制代码

八、Event Loop(事件循环)

进程和线程:在应用上来讲进程表明的就是一个程序,线程是进程中更小的单位,指执行一段指令所需时间。

执行栈:能够认为是存储函数调用的栈结构,先进后出,对于异步代码,会被挂起并在须要执行的时候加入到Task队列中,一旦执行栈为空,Event Loop就会从Task队列中拿出须要执行的代码,并放入执行栈中执行,因此他的本质仍是同步行为。

九、call、apply、bind

call、apply是为了改变某个函数运行时的上下文而存在的,也就是改变函数内部的this指向。

call、apply的功能彻底同样,只是参数的方式不同,以下:

func.call(this, arg1, arg2);

func.apply(this, [arg1, arg2])

bind()最简单的用法就是建立一个函数,使这个函数不论怎么调用都有一样的this值

十、事件

事件:就是文档或浏览器窗口发生的一些特色交互的瞬间

事件流:(IE)事件冒泡、(Netscaoe)事件捕获

事件冒泡:事件开始由最具体的元素接收,而后逐级向上传播较为不具体的节点。

事件捕获:由不太具体的节点接收事件,而后再一级一级向下到具体的节点。

事件代理:若是一个节点中的子节点是动态生成的,那么子节点须要注册事件的话,应该注册到父节点上。优势: (1)节省内存 (2)不须要给子节点注销事件

十一、跨域

出于安全考虑,浏览器有同源策略,若是协议、域名、端口号有一个不一样就是跨域。主要用于阻止CSRF攻击。解决跨域问题以下:

一、JSONP

利用script标签没有跨域限制的漏洞,经过标签指向一个须要访问的地址,并提供一个回调函数来接收数据。JSONP只是适用于GET请求

<script src="//xxx.com/api?param=xx&callback=jsonp"></script>
    function jsonp(data){
        console.log(data);
    }
复制代码

二、CORS 服务端设置Access-Control-Allow-Origin 就能够开启 CORS,该属性标识哪些域名能够访问资源,若是设置通配符,表示全部网站均可以访问资源。

三、Proxy代理---经过服务端代理转发,例如用node做为web服务器,请求过程以下:接口请求->node->服务端接口->node->前端,

十二、浏览器渲染原理

JS有引擎,那么执行渲染也有一个渲染引擎,Gecko、WebKit

为何操做DOM慢?

DOM操做属于渲染引擎中的东西,而JS又属于JS引擎中的东西,当咱们经过JS操做DOM时,这个操做会涉及到两个线程之间的通讯,那么势必会带来性能上的损耗。

回流:修改宽度、高度等影响页面布局的都会发生回流

重绘:当节点的外观发生变化,不影响布局的,会发生重绘,回流一定重绘

1三、性能优化

前端性能优化时一个长期的过程,常见的优化方法有以下几种:

网络层面:

一、减小HTTP请求,具体作法以下:

(1)如把多个js或css进行合并请求

(2)设计层面简化页面,如百度首页

(3)合理设置http缓存(设置Cache-Control: max-age)

(4)资源合并与压缩

(5)css雪碧图、base64

(6)懒加载

二、减小资源体积

(1)gzip压缩

(2)代码混淆、压缩

三、缓存

(1)DNS缓存--访问一个域名后,DNS返回正常IP后,操做系统会将这个地址临时存储起来,这就是DNS缓存

(2)CDN部署与缓存

(3)http缓存

强缓存:直接从缓存中读取(Expires、Cache-Control)

协商缓存:由服务端告知,能够从缓存中读取
复制代码

四、使用webp格式的图片

渲染和DOM操做方面:

在网页初步加载时,获取HTML文件以后,最初的工做是构建DOM和构建CSSOM两个树,以后他们合并造成渲染树,最后进行打印。

一、css放在header中,js放在body底部,先让页面渲染

二、尽可能避免内联样式--减小html体积

三、避免直接进行频繁的DOM操做

四、使用class代替内联样式修改

五、使用事件代理

六、函数节流:在必定时间内,函数只能执行一次,函数防抖:函数防抖的基本思想是设置一个定时器,在指定时间间隔内运行代码时清除上一次的定时器,并设置新的定时器,直到函数请求中止并超过期间间隔才会执行

vue项目的性能优化:

vue自己对虚拟DOM diff后才会更新DOM,性能相对来讲已经很高,可是项目中还可能会遇到性能问题,优化主要方法:

一、组件懒加载 二、服务端渲染 三、数据遍历时,设置key值 四、骨架屏

1四、webpack

现代JavaScript应用程序的静态模块打包工具。核心概念:

(1)入口(entry)

(2)输出(output)

(3)loader--可以处理那些非JavaScript文件,本质上,loader将全部类型的文件,转换成应用程序的依赖图能够直接引用的模块。

(4)插件(plugins)

1五、XSS

XSS,跨站脚本攻击。本质上讲,XSS就是浏览器错误的把用户输入的信息当作js脚本执行了。主要分为反射性XSS、存储型XSS、DOM XSS。

反射型XSS:XSS代码出如今URL中,服务端进行解析,最后返回给浏览器,浏览器执行了XSS代码。

存储型XSS:主要是将XSS代码存储在服务器中,下次请求页面的时候就不用带上XSS代码了。例如留言板。

DOM XSS:该问题通常咱们编写JS代码形成的,比如使用eval语句执行用户输入的字符串。

防护:

(1)cookie设置httpOnly

(2)对用户输入的特殊字符进行编码、解码或者过滤

(3)禁止使用eval

(4)使用$().text赋值

1六、CSRF

CSRF跨站伪造请求,在用户已登陆目标网站以后,诱导用户访问一个攻击页面,已用户的身份在攻击页面发送伪造请求。 防护手段:

(1)使用POST,限制GET

(2)加验证码

(3)使用token

1七、常见的兼容性问题

一、默认的内补丁和外补丁不一样,magin和padding

解决:设置{magin:0;padding:0;}

二、标签之间有默认间距

解决:给父元素设置font-size:0

三、ios元素绑定事件,点击无效

解决:加样式cursor:pointer

相关文章
相关标签/搜索