数据类型
如何判断数据类型
typeof
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof ‘str’); // string
console.log(typeof undefined); // undefined
console.log(typeof []); // object
console.log(typeof{}); // object
console.log(typeof function(){}); //function
console.log(typeof null); // object
instanceof
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
Object.prototype.toString.call()
console.log(toString.call(2)); //[object Number]
console.log(toString.call(true)); //[object Boolean]
console.log(toString.call(‘str’)); //[object String]
console.log(toString.call([])); //[object Array]
console.log(toString.call(function(){})); //[object Function]
console.log(toString.call({})); //[object Object]
console.log(toString.call(undefined)); //[object Undefined]
console.log(toString.call(null)); //[object Null]
判断数组的方法
数组方法:JavaScript数组的常用方法
字符串方法:
数组去重
var arr=[1,1,1,3,3,45,65,87,152,654,895,787,62,87,654,152]
第一种:通过查找关键字,从newArr查找arr里面的关键字,当没有的时候返回的值是-1,代表不重复,再把返回-1的arr[i]添加到newArr
var newArr=[]
for(var i=0;i<arr.length;i++){
if(newArr.indexOf(arr[i])===-1){
newArr.push(arr[i])
}
}
console.log(newArr)
第二种:先sort排序,这是相同的都在一起,在用前一个比较后一个,不相等的时候,返回a.push。相等则不做任何操作,最后返回的数值都是不相同的
arr.sort()
var a=[arr[0]]
for(var i=1;i<arr.length;i++){
if(arr[i]!==arr[i-1]){
a.push(arr[i])
}
}
console.log(a)
第三种:搜索关键字默认得到的是角标,当有相同字时,默认得到第一个,得到的角标跟i相等,则代表没有重复的,不相等,代表重复,自动pass掉
var b=[]
for(var i=0;i<arr.length;i++){
if(arr.indexOf(arr[i])===i){
b.push(arr[i])
}
}
console.log(b)
第四种:双for循环,用arr[0]第零个,跟后面每一项比较,相等,则删除,不相等,则继续循环。
for(var i=0;i<arr.length;i++){
for(var j=i+1;j<arr.length;j++){
if(arr[i]===arr[j]){
arr.splice(j,1)
j--
}
}
}
console.log(arr)
第五种:Array.filter + Array.indexOf
filter() 方法:创建一个新数组,新数组中的元素是指定数组中符合某种条件的所有元素。如果没有符合条件的元素则返回空数组。
语法:array.filter(function(item,index,arr))
filter() 不会对空数组进行检测。
filter() 不会改变原始数组。
原理:返回 item 第一次出现的位置等于当前的index的元素
let newArr = arr.filter((item, index) => arr.indexOf(item) === index);
// [1, 2, 4, null, "3", "abc", 3, 5]
第六种:Array.filter + Object.hasOwnProperty
hasOwnProperty() 方法:返回一个布尔值,表示对象自身属性中是否具有指定的属性
原理:利用对象的键名不可重复的特点。
let obj = {}
arr.filter(item => obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item)
第七种:Array.reduce + Array.includes
reduce() 方法:接收一个函数作为累加器,数组中的每个值从左到右开始计算,最终计算为一个值。
语法:arr.reduce(function(total, currValue, currIndex, arr), initValue)
let newArr = arr.reduce((accu, cur) => {
return accu.includes(cur) ? accu : accu.concat(cur); // 1. 拼接方法
// return accu.includes(cur) ? accu : [...accu, cur]; // 2. 扩展运算
}, []);// [1, 2, 4, null, "3", "abc", 3, 5]
第八种:Array.indexOf
indexOf() 方法:返回数组中某个指定的元素位置。该方法遍历数组,查找有无对应元素并返回元素第一次出现的索引,未找到指定元素则返回 -1
let newArr = []
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) newArr.push(arr[i])
}
//等同于 forEach 写法
arr.forEach( item => newArr.indexOf(item) === -1 ? newArr.push(item) : '')
console.log(newArr) // [1, 2, 4, null, "3", "abc", 3, 5]
第九种:new Set + 扩展运算符 || Array.from
Set本身是一个构造函数,可以接受一个具有 iterable 接口数据结构作为参数(如数组,字符串),用来初始化
let newArr = [...new Set(arr)]; // [1, 2, 4, null, "3", "abc", 3, 5]
let newArr = Array.from(new Set(arr)); // [1, 2, 4, null, "3", "abc", 3, 5]
let newStr = [...new Set('ababbc')].join('') // 'abc'
第十种:new Map
ES6 提供了新的数据结构 Map 。类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
get方法读取key对应的键值,如果找不到key,返回undefined。
has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
let map = new Map();
let newStr = [];
for (let i = 0; i < arr.length; i++) {
if (!map.has(arr[i])) {
map.set(arr[i], true);
newStr.push(arr[i]);
}
}
console.log(newArr) // [1, 2, 4, null, "3", "abc", 3, 5]
排序
var arr=[25,65,45,85,995,46,2,36,135,66]
for(var j=0;j<arr.length-1;j++){
for(var i=0;i<arr.length-1-j;i++){
if(arr[i]>arr[i+1]){
var b=arr[i]
arr[i]=arr[i+1]
arr[i+1]=b
}
}
}
console.log(arr)
var arr=[24,23,1,65,75,48,98,126,548,699,58,71]
arr.sort(function(a,b){return a-b})
console.log(arr)
function kfn(arr) {
if (arr.length <= 1) {
return arr
}
var pt = Math.floor(arr.length / 2);
var pi = arr.splice(pt, 1)[0]; //取中间项
var left = [],right = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < pi) {
left.push(arr[i]) //小的放左边
} else {
right.push(arr[i]) //大的放右边
}
}
return kfn(left).concat([pi], kfn(right)) //拼接递归
}
①. DOM的概念和作用
DOM 是 JavaScript操作网页的api接口,全称为“文档对象模型,浏览器会根据 DOM 模型,将结构化文 档(比如
HTML和 XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。所有的节点和最终的树状结构,都有规范的对外接口。DOM 不是 JavaScript 语法的一部分,但是 DOM 操
作是JavaScript 最常见的任务.
②.节点树
一个文档的所有节点,按照所在的层级,可以抽象成一种树状结构。这种树状结构就是DOM树。它有一个顶层节点,下一层都是顶层节点的子节点,然后子节点又有自己的子节点,就这样层层衍生出一个金字塔结构,倒过来就像一棵树。浏览器原生提供document节点,代表的是整个文档。
③.DOM选择器:(查询、创建、添加,修改,删除)
①返回匹配指定id属性的元素节点。如果没有发现匹配的节点,则返回null document.getElementById:
②返回一个类似数组的对象(HTMLCollection实例),包括了所有class名字符合指定条件的元素(兼容问题,低版本ie),如果没有发现匹配的节点,则返回空数组[ ]:.getElementsByClassName:
③搜索 HTML
标签名,返回符合条件的元素。它的返回值是一个类似数组的对象(HTMLCollection实例):document.getElementsByTagName:
④接受一个 CSS
选择器作为参数,返回匹配该选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null;
document.querySelector:(ES5新增选择器)
⑤与querySelector用法类似,区别是返回一个NodeList对象,包含所有匹配给定选择器的节点;
document.querySelectorAll:(ES5新增选择器)
④.DOM的基本操作
①.添加 document.createElement 用来生成元素节点,并返回该节点;
createElement方法的参数为元素的标签名,即元素节点的tagName属性,对于 HTML
网页大小写不敏感,即参数为div或DIV返回的是同一种节点;
②.插入 把newDiv添加到oDiv内部的最后面oDiv.appendChild(newDiv); 例: // 创建 var span =document.createElement(“span”); console.log(span); // 插入到将来的父元素 varoBox = document.getElementById(“box”); oBox.appendChild(span);sapn.innerHTML = “这是一个span”;
Element.innerHTML属性返回一个字符串,等同于该元素包含的所有 HTML代码。该属性可读写,常用来设置某个节点的内容。它能改写所有元素节点的内容,包括和元素。如果将innerHTML属性设为空,等于删除所有它包含的所有节点。
③.替换 box.replaceChild(newNode,oldNode);
④.删除 var el =document.getElementById(‘mydiv’); el.remove(); box.removeChild(oldNode);
事件流分为两种
事件流分三个阶段,
阻止冒泡
function(event){
event.stopPropagation();//阻止冒泡事件
}
function(event){
event.preventDefault();//阻止默认行为
//return false;//也可以
}
阻止默认事件
扩展:
什么是事件
JavaScript和HTML之间的交互是通过事件实现的
事件,就是文档或浏览器窗口发生的一些特定的交互瞬间。可以使用监听器(或事件处理程序)来预定事件,以便事件发生时执行相应的代码。通俗的说,这种模型其实就是一个观察者模式。(事件是对象主题,而这一个个的监听器就是一个个观察者)
什么是事件流
事件流描述的就是从页面中接收事件的顺序。而IE和Netscape提出了完全相反的事件流概念。IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。
事件捕获:
当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的
事件目标:
当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
事件冒泡:
目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发
Vue 阻止默认事件`
@click.stop 代表阻止冒泡事件
@click.prevent 代表阻止默认事件
JS 的 事件执行机制 先同步 —> 所有异步 微任务 —> 异步宏任务
1、为什么js是单线程
2、执行栈与任务列表
因为js是单线程语言,当遇到异步任务(如ajax操作等)时,不可能一直等待异步完成,再继续往下执行,在这期间浏览器是空闲状态,显而易见这会导致巨大的资源浪费。
宏任务与微任务:
异步任务分为 宏任务(macrotask) 与 微任务(microtask),不同的API注册的任务会依次进入自身对应的队列中,然后等待 Event Loop 将它们依次压入执行栈中执行。
Event Loop(事件循环):
Event Loop(事件循环)中,每一次循环称为 tick, 每一次tick的任务如下:
console.log(1);
setTimeout(() => {
console.log("2");
}, 0);
console.log(3);
let p = new Promise((resolve, reject) => {
console.log(4); //
resolve("此处为成功的 信息");
reject("此处为失败!");
});
p.then(
(res) => {
console.log(5, res);
//此处为接收成功的信息
},
(res) => {
console.log('6 :>> ', 6, res);
//此处为接收失败的信息
}
);
console.log(7);
// 成功5/失败6
// 1,3,4,7 , 5/6, 2
1 、调用方式区别
2、参数区别
function a(x,y){
console.log(this ,x,y);//
}
a(1,2);// window
var obj={
"name":"gao"
}
a.call(obj,1,2);// obj
a.apply(obj,[1,2] );//obj
a.bind(obj,1,2)();//obj
相同点
apply方法
apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变thi指向一次。
var name="martin";
var obj={
name:"lucy",
say:function(year,place){
console.log(this.name+" is "+year+" born from "+place);
}
};
var say=obj.say;
setTimeout(function(){
say.apply(obj,["1996","China"])
} ,0);
//lucy is 1996 born from China,this改变指向了obj
say("1996","China")
//martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向
call方法
采纳以参数列表的形式传入,而apply以参数数组的形式传入。
call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10
bind方法
Function.prototype.bind=function () {
var _this=this;
var context=arguments[0];
var arg=[].slice.call(arguments,1);
return function(){
arg=[].concat.apply(arg,arguments);
_this.apply(context,arg);
}
};
面向对象的基本特征:
原型:每一个函数 中 都有一个 prototype 对象 ,这个对象叫原型对象;
原型链:每一个对象中 都有__ proto__ 指向构造函数的 prototype (原型/原型对象) ,一直到null 为止,形成的作用域链叫原型链。
继承的几种方式:
原型链继承的优缺点
类式继承 语法、优缺点
组合继承
闭包 含义:
闭包 使用:
优点:
缺点:
扩展:垃圾回收机制、闭包变量
函数的调用方式决定了 this 的指向不同
箭头函数中的this指向,箭头函数中没有自己的this,它的this是继承而来,默认指向在定义它时所处的对象(宿主对象)。
当函数被当作监听事件处理函数时,其this指向触发该事件的元素(针对于addEventListener 事件)
防抖和节流区别:
es6新增哪些特性
箭头函数和普通函数区别?
什么是promise?
简单来说可以把promise当作一个装着异步操作结果的容器。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise 提供统一的API,各种异步操作都可以用同样的方法进行处理。它将异步函数以同步的方式书写,也解决了回调地狱问题
特点:
缺点:
三个状态:进行中、已成功、以失败。
1)、ajax的全称是AsynchronousJavascript+XML
异步传输+js+xml。
所谓异步,就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果我们可以再来处理这个事。
2)、即异步的 JavaScript 和 XML,是一种用于创建快速动态网页的技术;传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。使用AJAX则不需要加载更新整个网页,实现部分内容更新。
3)、Ajax是一种技术方案,但并不是一种新技术。它依赖现有的CSS/HTML/JavaScript,而其中最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。实现了在页面不刷新个情况下和服务器进行数据交互。
4)、ajax请求应该放在mounted,因为js是单线程,ajax异步获取数据
5)、具体步骤:
1、创建异步请求对象
2、打开链接
3、发送请求
4、监听状态改变
5、响应得到数据(判断 ajax 状态成功 readyState4 && http 状态成功status200 前提下)
http和https区别
服务器请求的区别:
参数放请求头和请求体的差别:
GET请求和POST请求的区别是什么?
请求头:
响应头:
HTTP状态码
一、token与cookie的区别?
二、token是如何避免CSRF攻击的?
2.1、CSRF(跨域请求伪造)的攻击特点是:需要用户自己点击恶意网站的隐藏HTTP请求链接,这个发出去的HTTP请求会自动的携带上你的cookie信息给服务器,于是完成了请求伪造攻击。(就是恶意网站利用了cookie会被HTTP请求自动添加的特性加以利用攻击)
2.2、token因为是自定义字符串,所以HTTP请求不会自动携带它,CSRF也就无法得手了(即使用户点击了恶意网站的请求也无法被拿走token),之所以说token天然防CSRF,但也不是绝对的,前提是不把token存储到浏览器的cookie里。
2.3、【补充】Ajax跨域请求不会自动携带cookie,源自浏览器的ajax同源策略,要想ajax自动携带cookie,需要在服务端进行配置。
1.虚拟dom比真实dom体积小,操作是相对来说消耗性能少,如果在页面中删除一个dom,会引起重绘,影响后边元素的布局
虚拟DOM 的工作过程?
优点:
缺点:
区别
什么是跨域?
在了解跨域之前,首先要知道什么是同源策略(same-origin policy)。简单来讲同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交互。对于浏览器而言只要域名、协议、端口其中一个不同就会引发同源策略,从而限制他们之间如下的交互行为:
跨域的严格一点的定义是:只要协议,域名,端口有任何一个的不同,就被当作是跨域。
解决方案
TCP基础入门
为什么需要三次握手而不是两次或者四次
挥手
为什么四次挥手