6个原始类型,原始类型存储的是值,没有函数能够调用的,string类型比较特殊,如 :('test').toString(),执行该方法时,'test'会被强制转换成String类型(对象),从而能够调用对应的方法 number string null undefined symbol booleancss
对象类型存储的是指针,而原始类型存储的是值,当建立一个对象的时候,内存中会开辟一个空间来存放值,经过指针指向该内存空间。html
一、使用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]"
复制代码
什么是原型?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');
复制代码
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
复制代码
进程和线程:在应用上来讲进程表明的就是一个程序,线程是进程中更小的单位,指执行一段指令所需时间。
执行栈:能够认为是存储函数调用的栈结构,先进后出,对于异步代码,会被挂起并在须要执行的时候加入到Task队列中,一旦执行栈为空,Event Loop就会从Task队列中拿出须要执行的代码,并放入执行栈中执行,因此他的本质仍是同步行为。
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时,这个操做会涉及到两个线程之间的通讯,那么势必会带来性能上的损耗。
回流:修改宽度、高度等影响页面布局的都会发生回流
重绘:当节点的外观发生变化,不影响布局的,会发生重绘,回流一定重绘
前端性能优化时一个长期的过程,常见的优化方法有以下几种:
网络层面:
一、减小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值 四、骨架屏
现代JavaScript应用程序的静态模块打包工具。核心概念:
(1)入口(entry)
(2)输出(output)
(3)loader--可以处理那些非JavaScript文件,本质上,loader将全部类型的文件,转换成应用程序的依赖图能够直接引用的模块。
(4)插件(plugins)
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赋值
CSRF跨站伪造请求,在用户已登陆目标网站以后,诱导用户访问一个攻击页面,已用户的身份在攻击页面发送伪造请求。 防护手段:
(1)使用POST,限制GET
(2)加验证码
(3)使用token
一、默认的内补丁和外补丁不一样,magin和padding
解决:设置{magin:0;padding:0;}
二、标签之间有默认间距
解决:给父元素设置font-size:0
三、ios元素绑定事件,点击无效
解决:加样式cursor:pointer