- 原生javaScript是中大公司挑人的中心,也是决议你将来生长高度的中心。
- 冒泡排序,疾速排序,深度克隆,深度凝结,数组操纵,本章都有。
- 走遍大江南北,照样原生javaScript最美
- 伤风给人人更新,愿望人人多多点赞,感谢!
- 下面是本人一些其他文章和进修的文档 , 全栈工程师一同加油!
- Node.js之疾速搭建微信民众号服务器
- Node.js之疾速搭建服务器+前后端数据库session交互
- ES6教程全篇
- 你该拥抱的TypeScript
疾速排序算法
'这应当是最简朴的疾速排序完成,什么是疾速排序呢?'
'疾速排序(Quicksort)是对冒泡排序的一种革新。
疾速排序由C. A. R. Hoare在1962年提出。它的基本思想是:
经过历程一趟排序将要排序的数据分割成自力的两部份,个中一
部份的统统数据都比别的一部份的统统数据都要小,然后再
按此要领对这两部份数据离别举行疾速排序,全部排序历程
能够递归举行,以此到达全部数据变成有序序列。'
function quickSort(arr) {
if (arr.length <= 1) { return arr; }
var left = [],
right = [],
baseDot = Math.round(arr.length / 2)
base = arr.splice(baseDot, 1)[0];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < base) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quickSort(left).concat([base], quickSort(right));
}
let arr = [5, 3, 4, 12];
const newarr = quickSort(arr);
console.log(newarr);
'每次递归挪用,都邑直到数组中只需一个数字为止,然后
实行上下文栈出栈,返回上一个实行上下文轮回递归,拼接数组'
冒泡排序算法
'什么是冒泡排序算法?'
'冒泡排序(Bubble Sort),是一种计算机科学范畴的较简朴的排序算法。
它反复地访问过要排序的元素列,顺次比较两个相邻的元素,假如他们的顺
序(如从大到小、首字母从A到Z)毛病就把他们交流过来。访问元素的事情
是反复地举行直到没有相邻元素须要交流,也就是说该元素已排序完成。
这个算法的名字由来是因为越大的元素会经过交流逐步“浮”到数列的顶端
(升序或降序分列),就犹如碳酸饮料中二氧化碳的气泡终究会上浮到顶端
一样,故名“冒泡排序”。'
bubbleSortSoul1 = (arr = []) => {
let count = 0;
// i为轮数(因i从0最早 即i<arr.length-1)
for (let i = 0; i < arr.length - 1; i++) {
count++;
// 第i轮仅需比较length-1-i次
for (let j = 0; j < arr.length - 1 - i; j++) {
// 这里能不能写成arr[j-1]>arr[j]? 假如有这类迥殊嗜好 那末j就从1最早吧,然后j<arr.length-i
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log(`bubbleSortSoul1排序完成用了${count}轮`);
return arr;
}
深度克隆
‘为何我们须要深度克隆?而且口试必问?’
'因为援用数据范例存储在堆空间中,当两个变量同时指向同一个地点时,
只需一个转变,那末别的一个也会随着变,我们的原意是想一个转变,另
一个稳定,那末就须要从新开辟一个堆空间出来,所以就有了深度克隆。'
'第一种要领(只实用于基本范例)'
const newObj = JSON.parse(JSON.stringify(oldObj));
'第二种要领,涵盖统统的范例'
const getType = (obj)=> {
var toString = Object.prototype.toString;
var map = {
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Undefined]': 'undefined',
'[object Null]' : 'null',
'[object Object]' : 'object',
'[object Symbol]' : 'symbol'
};
if(obj instanceof Element) {//因为对差别标签,toString会返回对应差别标签的组织函数
return 'element';
}
return map[toString.call(obj)];
}
const getRegExp = re => {
var flags = '';
if (re.global) flags += 'g';
if (re.ignoreCase) flags += 'i';
if (re.multiline) flags += 'm';
return flags;
};
/**
* deep clone
* @param {[type]} parent object 须要举行克隆的对象
* @return {[type]} 深克隆后的对象
*/
const deepClone = oldObj => {
// 保护两个贮存轮回援用的数组
const oldObjArr = [];
const newObjArr = [];
const clone = oldObj => {
let newObj, proto;
const type = getType(oldObj);
switch(type){
case 'boolean':
case 'number':
case 'string':
case 'null':
case 'undefined':
case 'function':{
return oldObj;
break;
}
case 'symbol':{
return Symbol(Symbol.keyFor(oldObj).toString());
break;
}
case 'array':{
newObj = [];
break;
}
case 'regExp':{
newObj = new RegExp(oldObj.source, getRegExp(oldObj));
if (oldObj.lastIndex) newObj.lastIndex = oldObj.lastIndex;
break;
}
case 'date':{
newObj = new Date(oldObj.getTime());
break;
}
//case 'obj':
default:{
// 处置惩罚对象原型
proto = Object.getPrototypeOf(oldObj);
// 应用Object.create割断原型链
newObj = Object.create(proto);
break;
}
}
// 处置惩罚轮回援用
const index = oldObjArr.indexOf(oldObj);
if (index != -1) {// 假如父数组存在本对象,申明之前已被援用过,直接返回此对象
return newObjArr[index];
}
oldObjArr.push(oldObj);
newObjArr.push(newObj);
/*数组和对象都能够用forin语句,虽然数组运用forin会有一个题目(详细看最下面)。
然则这里不会影响,所以这么用
*/
for (let i in oldObj) {// 递归
newObj[i] = clone(oldObj[i]);
}
return newObj;
};
return clone(oldObj);
}
/*
测试胜利
*/
function person(pname) {
this.name = pname;
}
const Messi = new person('Messi');
function say() {
console.log('hi');
};
const oldObj = {
a: say,
b: new Array(1),
c: new RegExp('ab+c', 'i'),
d: Messi
};
const newObj = deepClone(oldObj);
console.log(newObj.a, oldObj.a); //[Function: say] [Function: say]
console.log(newObj.b[0], oldObj.b[0]); // undefined undefined
console.log(newObj.c, oldObj.c); // /ab+c/i /ab+c/i
console.log(newObj.d.constructor, oldObj.d.constructor); // [Function: person][Function: person]
'统统的范例都能够被克隆,完美版'
- 推断对象是不是一个数组的前提是:
- Array.isArray(),这个在安卓的浏览器中兼容性平常
- arr instanceof Array 这个兼容性不错,能够运用
- 另有就是arr. _proto_ .consturctor == Array 这个也是能够的 兼容性应当还不错
- Object.prototype.tostring.call(arr) == [object Array] 这个也能够
怎样提取用最原生的要领提取一个对象内部统统属性的值,而且放在差别数组中?
- 个人认为第一题和第二题连系起来,能够用来处置惩罚前背景交互的数据,假如花样很庞杂,也能够运用这两者的形式连系,然后把他们离别提掏出来举行操纵。
const obj = {
name: 'json',
age: 1,
friend: '梦露',
info: {
name: 'Aron',
age: 2,
friend: '杰西卡',
info: {
name: 'rose',
age: 3,
friend: '霉霉',
info: {
name: 'jerry',
age: 4,
friend: '比伯',
info: {
name: 'damu',
age: 5,
friend: 'XJ',
},
},
},
}
}
let namearr, agearr, friendarr;
namearr = [];
agearr = [];
friendarr = [];
check(obj);
function check(obj) {
const items = Object.getOwnPropertyNames(obj)
items.forEach(function (item) {
if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
check(obj[item]);
} else {
if (item.toString() === 'name') {
namearr.push(obj[item])
} else if (item.toString() === 'age') {
agearr.push(obj[item])
} else if (item.toString() === 'friend') {
friendarr.push(obj[item])
}
}
})
}
/* 这类要领也是一样的结果 运用for in轮回替换的Object.getOwnPropertyNames(obj)要领
function check(obj) {
for (var item in obj) {
if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
check(obj[item]);
} else {
if (item == 'name') {
namearr.push(obj[item])
}
else if (item == 'age') {
agearr.push(obj[item])
}
else if (item == 'friend') {
friendarr.push(obj[item])
}
}
}
}*/
console.log(`namearr:${namearr}`)
console.log(`agearr:${agearr}`)
console.log(`friendarr:${friendarr}`)
请手写一个数组由小到大排序而且去重,不得运用高阶函数
let arr = [1, 1, 2, 2, 5, 5, 'a', 'a', '3', '3']
arr = arr.sort();
let realarr = [];
for (let i = 0; i < arr.length; i++) {
if (i == 0) {
realarr.push(arr[i])
} else if (i !== 0 && arr[i] !== arr[i - 1]) {
realarr.push(arr[i])
}
}
console.log(realarr)
### 怎样将一个对象深度凝结?
跟上面的数组口试题一样,应用了实行上下文栈,先进的后出,最早凝结最深层内里的谁人属性,
再顺次返回上一层继承凝结
var obj = {
name:"王宝强",
age:18,
wife:{
name:"陈羽凡",
age:17,
son:{
name:"贾乃亮",
age:48,
girlFriend:{
name:"吴秀波",
age:50,
zuo:function () {
console.log("翻旧账")
},
foods:["棉花糖","粉色的棉花糖","种种棉花糖",{a:"a"}]
}
}
}
};
Object.prototype.deepFreeze = function () {
var keys = Object.getOwnPropertyNames(this);
var that = this;
keys.forEach(function (key) {
var val = that[key];
if(Object.prototype.toString.call(val) === "[object Object]" || Object.prototype.toString.call(val) === "[object Array]"){
val.deepFreeze()
}
});
return Object.freeze(this)
}
obj.deepFreeze()
## 请运用定时器和canvas写一个随机天生多个彩色泡
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body,
html {
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
border: 1px solid;
background: white;
}
</style>
</head>
<body>
<canvas width="400" height="400"></canvas>
</body>
<script>
window.onload = function () {
var canvasnode = document.querySelector("canvas");
var arr=[];
if (canvasnode.getContext) {
var ctx = canvasnode.getContext("2d");
}
setInterval(function(){
console.log(arr)
ctx.clearRect(0,0,canvasnode.width,canvasnode.height)
arr.forEach(function(item,index){
item.r++;
item.opa-=0.01;
if(item.opa<=0){
arr.splice(index,1)
}
} )
arr.forEach(function(item){
ctx.save()
ctx.fillStyle="rgba("+item.red+","+item.green+","+item.blue+","+item.opa+")";
ctx.beginPath()
ctx.arc(item.x,item.y,item.r,0,2*Math.PI)
ctx.fill()
ctx.restore()
} )
} ,10)
setInterval(function(){
var obj={x:0,y:0,r:0,red:0,green:0,blue:0,opa:0};
obj.x=Math.random()*400;
obj.y=Math.random()*400;
obj.r=10;
obj.opa=1;
obj.red =Math.round(Math.random()*255);
obj.green =Math.round(Math.random()*255);
obj.blue =Math.round(Math.random()*255);
arr.push(obj);
},100 )
}
</script>
</html>
请本身定义一个DOM节点的R操纵,以此作为queryselector在IE8以下的polifill。
(function(w){
w.app = {};
w.app.getElementByClassName=function(className){
var allnode=document.getElementsByTagName("*");
console.log(allnode)
var arr=[];
for(var i=0;i<allnode.length;i++){
var newclass=" "+allnode[i].className+" ";
var reg=new RegExp("\\s+"+className+"\\s+","i");
if(reg.test(newclass)){
arr.push(allnode[i]);
}
}
return arr
}
}(window)
请你手写一个ajax原生javaScript要求?
'因为ajax平常用于比较旧的手艺,这里不实用ES6语法'
var xhr = new XMLHttpRuest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 0) {
//xhr对象建立好了 初始化状况
console.log(0)
}
if (xhr.readyState == 1) {
//代表xhr.send要领还未挪用(还未发送要求),还能够设置要求头相干信息
console.log(1)
}
if (xhr.readyState == 2) {
//此时send要领被挪用了 相应头和首行已返来了
console.log(xhr.getResponseHeader('etag'))
console.log(2)
}
if (xhr.readyState == 3) {
console.log(3)
}
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(4)
console.log(xhr.responseText);
}
}
xhr.open('GET', 'http://localhost:3000/ajax?username=123&password=456');
// xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
// xhr.send('username=123&password=456');
xhr.send()
}*/
'//上面是原生的ajax写法,下面是jQuery中的两种ajax写法'
' 1. 原生jQuery写法 '
$('#btn').click(function () {
$.ajax({
url: 'http://localhost:3000/ajax',
data: 'username=jack&password=123',
method: 'POST',
success: function (data) {
console.log(data)
},
error: function (error) {
console.log(error)
}
})
'2.简写'
$.post('http://localhost:3000/ajax', 'username=rose&age=12', (data) => {
console.log(data)
})
'//假如是get要求直接上面改成get就能够了,data是服务器相应返来的数据'
然后这边给一下服务器 Node.js的express代码 相应上面的ajax要求的
const express = require('express');
const app = express();
app.use(express.static('public'))
app.use(express.urlencoded({ extended: true }));
app.get('/ajax', (req, res) => {
console.log(req.query)
res.send('这是ajax的get要求')
})
app.post('/ajax', (req, res) => {
res.send('这是ajax的post要求')
console.log(req.body)
})
app.listen(3000, err => {
if (!err) {
console.log('端口监听胜利');
} else {
console.log('端口监听失利' + err);
}
})
怎样运用原生javaScript要领提取一个多重对象的值,而且塞到差别对应的数组中?
'这里运用了递归,另有Object原型上的要领,实行上下文栈先进后出的学问。'
const obj = {
name: 'json',
age: 1,
friend: '梦露',
info: {
name: 'Aron',
age: 2,
friend: '杰西卡',
info: {
name: 'rose',
age: 3,
friend: '霉霉',
info: {
name: 'jerry',
age: 4,
friend: '比伯',
info: {
name: 'damu',
age: 5,
friend: 'XJ',
},
},
},
}
}
let namearr, agearr, friendarr;
namearr = [];
agearr = [];
friendarr = [];
check(obj);
/* function check(obj) {
const items = Object.getOwnPropertyNames(obj)
items.forEach(function (item) {
if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
check(obj[item]);
} else {
if (item.toString() === 'name') {
namearr.push(obj[item])
} else if (item.toString() === 'age') {
agearr.push(obj[item])
} else if (item.toString() === 'friend') {
friendarr.push(obj[item])
}
}
})
}*/
function check(obj) {
for (var item in obj) {
if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
check(obj[item]);
} else {
if (item == 'name') {
namearr.push(obj[item])
}
else if (item == 'age') {
agearr.push(obj[item])
}
else if (item == 'friend') {
friendarr.push(obj[item])
}
}
}
}
console.log(`namearr:${namearr}`)
console.log(`namearr:${agearr}`)
console.log(`namearr:${friendarr}`)
## 请手写一个jsonp和cors 处理跨域题目的代码 ?
'jsonp'
document.getElementById('btn').onclick = function () {
/*
1. jsonp
- 特征:
1. 应用script标签自然跨域跨域的特征处理跨域的, 民间推出的
2. 兼容性极好
*/
//建立一个script标签
const script = document.createElement('script');
//设置了相应胜利的回调函数
window.jsoncallback = function (data) {
console.log(data);
}
//设置script的src属性, 向指定服务器发送要求
script.src = 'http://localhost:3000/?callback=jsoncallback';
//添加到body中见效
document.body.appendChild(script);
}
------
'cors的处理要领:在Node.js的服务器代码中设置一个相应头'
app.get('/cors', (req, res) => {
/*
1. cors
特征:
- 官方推出处理跨域的计划,运用起来及其简朴,只需在服务器设置一个相应头
- 兼容性较差
*/
//设置相应头
res.set('access-control-allow-origin', '*'); //许可统统网址跨域
浏览器的轮询机制请简述
'1.浏览器的事宜轮询机制
浏览器中关于js依托js引擎完成,js引擎是单线程,不像java,php这些能够是多线程,高并发。假如要说到浏览器的轮询机制,那末我们首先要说的
就是单线程的js引擎,前端的中心编程头脑形式是异步编程,无论是页面结果、前后端的数据交互,都是以异步为中心,每一个须要异步的场景,
每每伴随着回调函数去实行,而单线程的JS引擎是没法本身做这么多事情,还须要异步线程。
1.每当JS引擎剖析代码时碰到异步代码时,交给异步线程,继承往下剖析代码。
2.异步线程处置惩罚这些异步代码时,一旦他们的所对应的回调函数到达实行前提便会塞进异步行列中,守候JS引擎的轮询。
3.JS引擎会在剖析完下面的统统代码后,再去轮询异步行列,从左到右,顺次实行,这也是说为何定时器的时刻不正确的缘由,在JS
剖析代码时,假如碰到下面代码迥殊多的时刻,那末它就没时刻去轮询异步行列的代码。
浏览器中的轮询机制有一个迥殊的 requestAnimationFrame(callbackname),它所对应的回调函数,是在浏览器下一次重绘重排时实行,它是一个宏使命,有待考据
,现在看只需触发重绘重排就会挪用回调函数,能够避免掉帧,优化机能,削减重绘重排次数,纵然一个空缺页面,它也会重绘重排,所以只需运用好,
它是完整能够替换定时器,还能够运用cancelAnimationFrame(callbackname)消灭。
'
Node.js中的事宜轮询机制 Event loop
'Node.js的事宜轮询机制外另有同步代码,微使命,
要想完整弄懂Node的代码实行,得连系下面的微任
务一同进修。'
'1.实行已到时刻的setTimeout 和 setInterval
2.实行延晚到一个轮回迭代的i/o回调
3.体系内部的 idle prepare等
4.poll 轮询回调行列,顺次掏出,同步实行,与JS的异步行列实行有点相像 直到回调行列为空 或许体系奔溃了 假如回调行列没有内容,那末看
之前是不是设置过setImmadiate(),假如有就去下一个阶段,假如没有,就在当前守候新的回调函数。 假如定时器的时刻到了,那末也会去下一个阶段
5. setImmediate
6.封闭的回调函数 ,一些预备封闭的函数等.
Node.js的事宜轮询机制也能够算作是单线程,由上往下实行,然则到了第6阶段,又会返回第一阶段,死轮回。 '
什么是微使命什么是宏使命?
'想得太多反而不好,把每一个宏使命算作银行列队的老大爷,把微使命算作老大爷须要的营业,
能够他须要办存款,理财,买纪念币等,柜台职员不帮老大爷办完
他所须要的使命 -- 微使命,就不会切换到下一个老大爷 -- 宏使命, 然则编程的逻辑不
能完整笼统成现实生活,
照这类说法,只能先有老大爷才会有营业须要,
。但是在Node中,先实行的是微使命,只需微使命假如有多层,先实行最顶层,再往下顺次执
行)实行完后才能去实行宏使命,微使命有两种,一种是process.nextTick()
中的函数,一种是Promise.then()中的函数,只需他们实行完后,才会去实行宏使命:setTim
eout ,setIneterval,setImmadie。(即实行完了微使命才会遵照Node.js的轮询机制去实行,
统统微使命优先)'