function mySetInterval(fn, ms) {
function interval(){
setTimeout(interval, ms);
fn();
}
setTimeout(interval, ms);
}
// 更好的实现
function mySetInterval(fn, ms, count) {
function interval() {
if(typeof count === 'undefined' || count-- > 0) {
setTimeout(interval, ms);
try {
fn();
} catch(e) {
t = 0;
throw e.toString();
}
}
}
setTimeout(interval, ms);
}
复制代码
例如:有数组[10, 22, 32, 4, 4, 5, 6, 9, 8, 8, 2],返回结果为2
4, 4
8, 8
复制代码
太多了,跟面试前补充的简历几乎同样javascript
根据内容的结构化(内容语义化),选择合适的标签(代码语义化),
便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析
复制代码
TCP链接 须要通过“三次握手”
HTTP/1.0 客户端发送的每次请求都须要服务器回送响应,在请求结束后,会主动释放链接
HTTP/1.1 一次链接中处理多个请求,而且多个请求能够重叠进行,不须要等待一个请求结束后再发送下一个请求
复制代码
补充:css
第一步:
设置响应消息头Access-Control-Allow-Credentials值为“true”。
同时,还须要设置响应消息头Access-Control-Allow-Origin值为指定单一域名
第二步:
客户端须要设置Ajax请求属性withCredentials=true,让Ajax请求都带上Cookie
复制代码
1. elementObject.addEventListener(eventName,handle,useCapture)
2. elementObject.attachEvent(eventName,handle);(仅支持IE8及如下)
3. document.getElementById("demo").onclick = function(){};
复制代码
1. <meta name="viewport"
content="width=device-width, height=device-height, inital-scale=1.0, maximum-scale=1.0, user-scalable=no;"
/>
2. 网页内部的元素宽度要使用百分比,在不一样的屏幕大小下需使用媒体查询定义不一样的css代码
代码解析:
width:控制 viewport 的大小,能够是指定的一个值,好比 1920,或者是特殊的值,如 device-width 为设备的宽度,单位为缩放为 100% 时的 CSS 的像素。
height:和 width 相对应,指定高度,能够是指定的一个值,好比 1080,或者是特殊的值,如 device-height 为设备的高度。
initial-scale:初始缩放比例,即当页面第一次载入是时缩放比例。
maximum-scale:容许用户缩放到的最大比例。
minimum-scale:容许用户缩放到的最小比例。
user-scalable:用户是否能够手动缩放。
复制代码
1. IE: Trident内核
2. Firefox:Gecko内核
3. Google:Blink内核
4. Safari:Webkit内核
-webkit- ,针对safari,chrome浏览器的内核CSS写法
-moz-,针对firefox浏览器的内核CSS写法
-ms-,针对ie内核的CSS写法
-o-,针对Opera内核的CSS写法
复制代码
CSS响应式设计适配多种设备:
1. <meta name="viewport" content="width=device-width, initial-scale=1" />
2. 不要使用绝对宽度
3. 字体大小和长宽边距属性不要用”px”,应该用相对大小的“rem”
4. 使用流动布局
- 若是宽度过小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现
5. link标签的media属性
- <link rel="stylesheet" type="text/css" media="screen and (min-width: 600px) and (max-device-width: 980px)"
href="css600-980.css" />
6. Media Query
7. 图片的自适应(自动缩放)
- img{max-width: 100%;}
- 最好仍是根据不一样大小的屏幕,加载不一样分辨率的图片
复制代码
1. Unicode是'字符集',utf-8是'编码规则'
(以8位为一个编码单位的可变长编码,会将一个码位编码为1到4个字节)
2. 字符集:为每个字符分配一个惟一的ID
编码规则:将码位转为字节序序列的规则
例如:'知'的码位是30693,记做U+7735(16进制为0x77E5)
'Unicode与utf-8关系':
U+0000 - U+007F:0XXXXXXX
U+0080 - U+07FF:110XXXXX 10XXXXXX
U+0800 - U+FFFF:1110XXXX 10XXXXXX 10XXXXXX
U+10000 - U+1FFFF:11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
3. utf-16使用2或4字节来保存,utf-32使用4字节保存
'GBK与utf-8':
- UTF-8包含全世界全部国家须要用到的字符,是国际编码,通用性强。
- GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。
- GBK的文字编码是用'双字节'来表示的,为了区分中文,将其最高位都设定成1,通用性比UTF8差。
复制代码
补充: React-router中的Link和Route的区别html
const promise = new Promise((resolve, reject) => {
console.log('a');
resolve();
console.log('b');
});
promise.then(() => {
console.log('c');
});
console.log('d');
// a b d c,Promise的异步执行
复制代码
(function(x) {
return (function(y) {
console.log(x);
})(2);
})(1);
// 1,闭包问题
复制代码
pi = 0;
radius = 1;
function circum(radius) {
radius = 3;
pi = 3.14;
console.log(2 * pi * radius); // 18.14
console.log(arguments[0]); // 3
}
circum(2);
console.log(pi); // 3.14
console.log(radius); // 1
函数内修改了radius 修改的是"形式参数",修改的pi是"全局的"pi
复制代码
与下述状况相同前端
var pi = 0;
var radius = 1;
function circum(radius) {
radius = 3;
pi = 3.14;
console.log(2 * pi * radius); // 18.84
console.log(arguments[0]); // 3
}
circum(radius);
console.log(pi); // 3.14
console.log(radius); // 1
复制代码
补充java
function foo(a, b){
arguments[0] = 9;
arguments[1] = 99;
console.log(a, b); //9, 99
}
foo(1, 10);
function foo(a, b){
a = 8;
b = 88;
console.log(arguments[0], arguments[1]); //8, 88
}
foo(1, 10);
// ES6的默认函数不会改变arguments类数组对象值
function foo(a=1, b=10){
arguments[0] = 9;
arguments[1] = 99;
console.log(a, b); //1, 10
}
foo();
// 实例
function f2(a) {
console.log(a);
var a;
console.log(a);
console.log(arguments[0])
}
f2(10)
通过变量提高后:
function f2(a) {
var a;
console.log(a);
console.log(a);
console.log(arguments[0])
}
f2(10);
var a会被概括,因为a已经有值,故不会变为undefined
复制代码
稳定排序:
插入排序 [1] ,冒泡排序 [2] ,归并排序 [3] ,基数排序 [4] ,计数排序 [5]
不稳定排序:
快速排序 [1],简单选择排序 [2],希尔排序 [3],堆排序 [4]
复制代码
var obj = {};
var arr = [];
var funcInstance = new (function (){});
var isNull = null;
console.log(typeof obj === 'object'); //true
console.log(typeof arr === 'object'); //true
console.log(typeof funcInstance == 'object'); //true
console.log(typeof isNull === 'object'); // true
// constructor
({}).constructor === Object; //true
([]).constructor === Array; //true
// instanceof
({}) instanceof Object; //true
([]) instanceof Array; //true
// toString: 将当前对象以字符串的形式返回
console.log(Object.prototype.toString.call(obj)); //[object Object]
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(null)); //[object Null]
复制代码
var a = {};
var b = {name:"ZS"};
var c = {};
c[a] = "demo1";
c[b] = "demo2";
console.log(c[a]); // demo2
console.log(c); // Object {[object Object]: "demo2"}
c[a]、c[b]隐式的将对象a,b使用了toString()方法进行了转换,而后再对属性赋值。
即:Object.prototype.toString.call(a) ==> [object Object]
所以,c = { [object Object]: 'demo1'} ==> c = {[object Object]: 'demo2' }
复制代码
function log() {
// var arr = [].slice.call(arguments);
var arr = Array.from(arguments);
var res = '';
arr.forEach(elem => {
res += elem + ' ';
});
console.log(`(app)${res}`);
}
// 测试
log('hello', 'world');
log('hello world');
复制代码
function toTreeData(data){
var pos={};
var tree=[];
var i=0;
while(data.length!=0){
if(data[i].pid==0){
tree.push({
id:data[i].id,
text:data[i].text,
children:[]
});
pos[data[i].id]=[tree.length-1];
data.splice(i,1);
i--;
}else{
var posArr=pos[data[i].pid];
if(posArr!=undefined){
var obj=tree[posArr[0]];
for(var j=1;j<posArr.length;j++){
obj=obj.children[posArr[j]];
}
obj.children.push({
id:data[i].id,
text:data[i].text,
children:[]
});
pos[data[i].id]=posArr.concat([obj.children.length-1]);
data.splice(i,1);
i--;
}
}
i++;
if(i>data.length-1){
i=0;
}
}
return tree;
}
var data=[
{id:1,pid:0,text:'A'},
{id:2,pid:4,text:"E[父C]"},
{id:3,pid:7,text:"G[父F]"},
{id:4,pid:1,text:"C[父A]"},
{id:5,pid:6,text:"D[父B]"},
{id:6,pid:0,text:'B'},
{id:7,pid:4,text:"F[父C]"}
];
var result = toTreeData(data);
console.log(result);
复制代码
第二种思路:web
function treeObj(originObj) {
// 深拷贝
let obj = {};
for(key in originObj) {
var val = originObj[key];
// arguments的callee属性指向拥有这个 arguments 对象的函数
obj[key] = typeof val === 'object'? arguments.callee(val):val;
}
obj['children'] = [];
return obj;
}
function toTreeData(data, attributes) {
let resData = data;
let tree = [];
// 找根节点
for(let i = 0; i < resData.length; i++) {
if(resData[i][attributes.parentId] === ''
||
resData[i][attributes.parentId] === null) {
tree.push(treeObj(resData[i]));
// 删除掉已经放入tree中的根节点
resData.splice(i, 1);
i--;
}
}
// 找寻子树
return run(tree);
function run(childArr) {
if(resData.length !== 0) {
for(let i = 0; i < childArr.length; i++) {
for(let j = 0; j < resData.length; j++) {
if(childArr[i][attributes.id] === resData[j][attributes.parentId]) {
let obj = treeObj(resData[j]);
childArr[i].children.push(obj);
// 删除加入树中的节点
resData.splice(j, 1);
j--;
}
}
run(childArr[i].children);
}
}
return tree;
}
}
let allRes = [
{
id: 4,
resName: "删除角色",
parentId: 2
},
{
id: 3,
resName: "编辑角色",
parentId: ''
},
{
id: 2,
resName: "设置权限",
parentId: ''
},
{
id: 5,
resName: "添加用户",
parentId: 4
},
{
id: 6,
resName: "更新用户",
parentId: 4
},
{
id: 7,
resName: "删除用户",
parentId: 6
},
{
id: 8,
resName: "重置密码",
parentId: 3
},
{
id: 9,
resName: "添加地区",
parentId: 5
},
{
id: 10,
resName: "编辑地区",
parentId: 6
}
];
let data = allRes;
// 属性配置信息
let attributes = {
id: 'id',
parentId: 'parentId',
};
let treeData = toTreeData(data, attributes);
console.log(treeData);
复制代码
// 1. Object.assign
let foo = {
a: 1,
b: 2,
c: {
d: 1,
}
}
let bar = {};
Object.assign(bar, foo);
foo.a++;
foo.a === 2 //true
bar.a === 1 //true
foo.c.d++;
foo.c.d === 2 //true
bar.c.d === 1 //false
bar.c.d === 2 //true
Object.assign()是一种能够对非嵌套对象进行深拷贝的方法;
若是对象中出现嵌套状况,那么其对被嵌套对象的行为就成了普通的浅拷贝。
// 2. JSON.parse和JSON.stringify
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1); // { body: { a: 10 } }
console.log(obj2); // { body: { a: 20 } }
console.log(obj1 === obj2); // false
console.log(obj1.body === obj2.body); // false
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
可是,会破坏原型链,而且没法拷贝属性值为function的属性
// 3. 递归
var json1={
"name":"shauna",
"age":18,
"arr1":[1,2,3,4,5],
"string":'got7',
"arr2":[1,2,3,4,5],
"arr3":[{"name1":"shauna"},{"job":"web"}]
};
var json2={};
function copy(obj1,obj2){
var obj2 = obj2 || {};
for(var name in obj1){
if(typeof obj1[name] === "object"){
obj2[name]= (obj1[name].constructor===Array)?[]:{};
copy(obj1[name],obj2[name]);
}else{
obj2[name]=obj1[name];
}
}
return obj2;
}
json2=copy(json1,json2)
json1.arr1.push(6);
alert(json1.arr1); //123456
alert(json2.arr1); //12345
复制代码
// 递归
function flatten(arr){
var res = [];
for(var i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
res = res.concat(flatten(arr[i]));
}else{
res.push(arr[i]);
}
}
return res;
}
复制代码
回溯算法面试
下面的输出是什么?ajax
var array1 = Array(3);
array1[0] = 2;
var result = array1.map(elem => '1');
// ['1', empty * 2]
复制代码
var setPerson = function(person) {
person.name = 'kevin';
person = {name: 'Nick'};
console.log(person.name); // Nick
person.name = 'Jay';
console.log(person.name); // Jay
}
var person = {name: 'Alan'};
setPerson(person);
console.log(person.name); // Kevin
复制代码
var execFunc = () => console.log('a');
setTimeout(execFunc, 0);
console.log('000');
execFunc = () => console.log('b');
// '000', 'a'
复制代码
补充:setTimeout没法使用含参函数参数算法
window.setTimeout(hello(userName),3000);
这将使hello函数当即执行,并将'返回值'做为调用句柄传递给setTimeout函数
// 方法1:
使用'字符串形式'能够达到想要的结果:
window.setTimeout("hello(userName)",3000);
可是,此处的username变量必须处于全局环境下
// 方法2:
function hello(_name){
alert("hello,"+_name);
}
// 建立一个函数,用于返回一个无参数函数
function _hello(_name){
return function(){
hello(_name);
}
}
window.setTimeout(_hello(userName),3000);
使用_hello(userName)来返回一个不带参数的函数句柄,从而实现了参数传递的功能
复制代码
for(var i = {j: 0}; i.j < 5; i.j++) {
(function(i){
setTimeout(function() {
console.log(i.j);
}, 0);
})(JSON.parse(JSON.stringify(i)));
}
// 0, 1, 2, 3, 4
for(var i = {j: 0}; i.j < 5; i.j++) {
(function(i){
setTimeout(function() {
console.log(i.j);
}, 0);
})(i);
}
// 5, 5, 5, 5, 5
复制代码
1.如何进行输入去重?chrome
// 方法1:
function nonDup(arr){
var res = [];
for(var i = 0; i < arr.length; i++) {
if(res.indexOf(arr[i]) === -1) {
res.push(arr[i]);
}
}
return res;
}
// 方法2:
function nonDup(arr){
var res = new Set(arr);
return [...res];
}
// 方法3:
function nonDup(arr){
return arr.filter((elem, index) => {
return index === arr.indexOf(elem);
});
}
// 方法4:
Array.prototype.uniq = function () {
var hasNaN = false;
for(var i = 0; i < this.length; i++){
if(this[i] !== this[i]) hasNaN = true;
for(var j = i+1; j < this.length;){
if(this[i] === this[j] ||(hasNaN && this[j] !== this[j])){
this.splice(j,1);
}else{
j++;
}
}
}
return this;
}
复制代码
2.实现鼠标滑过头像显示简介
<!DOCTYPE html>
<html>
<head>
<style>
.div1{
width:100px;
height:100px;
background-color:red;
border-radius: 50px;
}
.div2{
width:100px;
height:200px;
margin-top: 10px;
background-color:black;
display: none;
}
</style>
</head>
<body>
<div class='div1'></div>
<div class='div2'></div>
<script type="text/javascript">
var d1 = document.getElementsByClassName('div1')[0];
var d2 = document.getElementsByClassName('div2')[0];
var timer;
d1.addEventListener('mouseenter',function(){
timer = window.setTimeout(function(){d2.style.display="block"},300);
})
d1.addEventListener('mouseout',function(){
window.clearTimeout(timer);
d2.style.display="none";
})
</script>
</body>
</html>
复制代码