前言

若文章有误,欢迎读者留言反馈

题一 函数执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//分别写出对fun两次调用alert的输出结果、井说明原理
function fun(a, b, c) {
var l = arguments.length;
var num = 0;
for (var i = 0; i < l; i++) {
num += arguments[i];
}
alert(num)
}
fun(1, 2, 3); // 6
fun(1, 2, 3,4); // 10

// 从上往下执行
// arguments是什么? 传入的实参被接收存入到arguments类数组

函数执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//写出函数fun执行后console.log(a)的输出结果,并说明原理
/*
* Go{
* a=0
* fun=function
* }
* */
var a = 0;
function fun() {
/*
* AO{
* a=undefined
*
* }
* */

console.log(a)
var a = 10
}
fun();
console.log(a)


// 变量声明 局部变量就是在函数内部定义的变量 全局变量就是函数外定义的变量

函数执行

1
2
3
4
5
6
7
8
9
// 分别写出下面的执行 a 结果  及原理
var a = 0;
function fun() {
console.log(a);
var a = 10;
console.log(a);
}
fun();
console.log(a);

函数执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 打印执行结果  讲解其原理
var a=1;
var obj ={
"name":"tom"
}
function fn(){
var a2 = a,
obj2 = obj,
a2 =a,
obj2.name ="jack"
}
fn();
console.log(a);
console.log(obj);

题二 引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 分别写出下面的执行 a 结果  及原理

//基础类型 栈区
var a = 0;
var b = a;
b++;
console.log(a)

//引用类型在 堆区
var o ={};
o.a = 0;
var c = o;
c.a = 10;
console.log(o.a)

题三 运算符

1
2
3
4
5
6
7
8
9
10
11
// 请分别计算 a 的值____   及类型
var a='abc'+123+456

var a='456'-'123' // 333 number
// * - % 都会隐式使用什么Number() 将字符串转换成数字类型

// 请计算c的值____
// 比较运算符 < > >= <= == != 全部会类型转换
var a=1;
var b='2';
var c=a>b?(a<b?a:b):(a==b?a:b); // "2"

比较运算符

1
2
3
4
5
6
js中的==和===作用
1=="1" true
1==="1" false

=== 不会改变类别 进行比较
== 会改变类型进行比较

小数

1
2
3
4
5
6
7
8
9
10
11
12
13
0.1 + 0.2 === 0.3 嘛?为什么?

不相等
小数在转换成进制时 会出现缺失精度
解决方法1:转换为整数相加再除以之前的倍数
解决方法2:利用num.toFixed(arg),参数=>保留几位小数,但是结果会转换为字符串类型
思考:num是数字类型,但是却能够像对象一样使用方法?
js内部做了一个处理,将num转换为数字对象
【处理:new Number(num)】

js最大数值
253次幂

题四 循环/遍历

1
2
3
4
5
6
// 打印 i  讲解其原理
for(var i=0;i<10;i++){
console.log(i); // 0
break; // 结束当前循环
}
console.log(i); // 0

循环/遍历

1
2
3
4
5
6
// 打印 i  讲解其原理
for(var i=0;i<10;i++){
console.log(i); //0-9
continue;
}
console.log(i); // 10

乘法表

1
2
3
4
5
for(let i = 1;i<=9;i++){
for(let j = 1; j<= 9;j++){
console.log(i+"*" + j + "="+ i * j );
}
}

题五 this指向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 打印 json.val  讲解其原理
window.val=1;
var json={
val:10,
dbl:function(){
this.val*=2;
}
}
json.dbl(); // 对象里面的
var dbl = json.dbl;
dbl(); // 全距
console.log(json.val)

//函数创建的时候 this就会指向一个对象
// 函数this默认指向window,除非调用时修改, 调用函数时this会改变指向
// 谁调用函数this指向就是谁

this

1
2
3
4
5
6
7
8
9
10
11
12
//  打印 console.log(json.val+val) 讲解其原理
(function(){
var val =1;
var json ={
val:10, // 属性名
dbl:function(){
val*=2; // 变量
}
};
json.dbl();
console.log(json.val+val); // 12
})();

题六 数组

1
2
3
4
5
6
7
// 打印执行结果  讲解其原理
var ary =[1,4,3,2,6,5,8,7];
ary.push("666")
ary.pop()
ary.pop()
console.log(ary.join(""))
console.log(ary)

数组和类数组的区别

1
2
3
什么是类数组
一定会有具有length长度
没有数组的方法

数组

1
数组的pop()、push()、shift()、unshift()分别是什么?

数组去重

1
2
3
4
5
6
7
8
9
10
11
12
let arr = [1,2,3,4,55,66,123,1,2,3]
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
1
2
3
4
5
6
7
8
9
10
11
12
function unique(arr) {
if (!Array.isArray(arr)) {
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i])
}
}
return array;
}
1
2
3
4
let result =ar.filter(function(item,index,arr){
return arr.indexOf(item) == index
})
console.log(result)
1
2
3
4
5
6
7
8
9
let arr = [1,2,2,4,5,4,7,5,6,1]
let res= arr.reduce(function(prev,cur,index,arr){
//console.log(arguments);
if(!prev.includes(cur)){
prev.push(cur)
}
return prev;
},[])
console.log(res);

数组排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let arr= [20,5,10,56,3,100];
function sortArr(arr){
for (let i=0;i<arr.length;i++){
for (let j=0;j<arr.length;j++){
//判断数组的第一项 和 数组的第二项比较
if (arr[j] < arr[j+1]){
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
};
sortArr(arr);
console.log(arr)

数组相加

1
2
3
4
5
6
7
8
9
10
11
12
13
let arr = [1,2,3,4,5,6,7,8,9,10,"11","asd"];  // 数组相加
function num(value) {
if (!value.length)return; //数组长度为零,就是数组没有子项,没有子项之间返回
let len = value.length; // 数组长度
let addNum = 0; // 累计值
for (let i=0;i<len;i++){ // 循环
if (typeof value[i] === "number"){ //循环判断 数组每一项为数字类型,不是数字类型 不要相加
addNum += value[i]
}
}
return addNum;
}
num(arr)

数组降维

1
2
3
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(Infinity);
//  [1, 2, 3, 4, 5, 6]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 多维数组降维
let arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
const res = [];
function flatten(input) {
if (!Array.isArray(input))return

while (input.length) {
// 使用 pop 从 stack 中取出并移除值
const next = input.shift();
if (Array.isArray(next)) {
// 使用 push 送回内层数组中的元素,不会改动原始输入 original input
flatten(next)
} else {
res.push(next);
}
}
}

多项数组数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var arr = ["2", 2, "2", 2, [3, 4], [3, 4, 5], [3, 4], { a: 6, b: 6 }, { a: 6, b: 7 }, { a: 6, b: 6 }, NaN, null, NaN, [7, [7, 8]], [7, [7, 8]], { a: 3, b: 4 }]
function uniqueObj(arr) {
var newArr = []
var tempArr = []
arr.forEach(function (item, idex, arr) {
if (newArr.indexOf(item) === -1) {
if (tempArr.indexOf(JSON.stringify(item)) === -1) {
tempArr.push(JSON.stringify(item))
newArr.push(item)
}
}
})
return newArr
}
console.log(uniqueObj(arr))

题七 字符串

1
2
3
4
5
// 打印执行结果  讲解其原理
var str ="123456789"
str.split("")
console.log(str)
console.log(str.split(""))

反转字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let str = "abcd"   // 字符串空格去除
function reverseStr(value) {
if(!value)return;
let str = value.split("").reverse().join("")
return str
}


function fun(value){
if(!value)return;
let newstr = ""
for(let i=value.length-1;i>=0;i--){
newstr +=value[i]
}
return newstr
}

首字母大小写

1
2
3
4
5
6
7
let str = "abcd"   // 首字母大写
function firstLetterToUpperCase(value){
if(!value)return;
let val= value[0].toUpperCase();
let rep = value.replace(value[0],val)
return rep
}

每个字母大写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 let vs = "You can be a real big baby"
function firstLetterToUpperCase(value) {
if(!value)return;
let arr = value.split(" ");
arr.forEach(function(item,index){
let val = item[0].toUpperCase();
let rep = item.replace(item[0],val);
arr[index] = rep
})
return arr.join(" ")
}

// 判断单个
let vs = "You can be a real big baby"
function firstLetterToUpperCase(value) {
if(!value)return;
let arr = value.split(" ");
arr.forEach(function(item,index){
if(item.length == 1) return
let val = item[0].toUpperCase();
let rep = item.replace(item[0],val);
arr[index] = rep
})
return arr.join(" ")
}

查看字符串重复项

1
2
3
4
5
6
7
8
9
var str = 'caibaojian.com',obj=[];
for(var i = 0; i< str.length; i++){
var key = str[i];
if(!obj[key]){
obj[key] = 1;
}else{
obj[key]++;
}
}

题八 递归算法

1
2
3
4
5
6
7
8
function cc(max){
if(max>1){
return max+cc(max-1);
}else{
return 1;
}
}
cc(10)

题九 闭包

1
2
3
4
5
6
7
8
9
10
11
12
闭包,作用是什么?
是一个函数可以把自己内部的语句和自身所声明时所在的作用域形成一个密封的环境,
在函数外部可以读取到函数内部的变量和函数,函数内部的变量会被保存下来,不会被回收,闭包不会被销毁,

怎么写闭包?
在一个函数中创建一个函数,函数内部使用外部变量;形成闭包;
函数内部被返回,或者被持续引用,那么使用的变量不会被回收,

这就是闭包
函数内部变量 不会被垃圾回收机制 回收

闭包是指有权访问另外一个函数作用域中的变量的函数

闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// // 打印执行结果  讲解其原理
function fn(i) {
return function (n) {
console.log(n + i++)
}
}
var f = fn(10)
f(20)
fn(20)(40)
fn(30)(50)
f(30)

// ++在后 在先计算在赋值 不参与运算
// ++在前 先加赋值在计算 参与运算

题十 Number

1
2
3
4
5
6
7
8
9
10
11
12
// 打印执行结果  讲解其原理
var num="abc123";
num=parseInt(num);
if(num==123){
alert(123);
}else if(num===NaN){
alert(NaN);
}else if(typeof num=="number"){
alert("number")
}else{
alert("str");
}

题十一 节点

1
2
3
4
5
6
怎么添加、移除、复制、创建、和查找节点

document.createElement()
document.removeChild() remove()
appendChild()

滚动过度效果

1
2
3
4
5
6
7
8
9
10
11
document.documentElement.onclick=function(){
let h = this.scrollTop;

let time = setInterval(function(){
h = h-100
if (h < 0) {
clearInterval(time)
}
this.scrollTo(0,h)
},1000/60)
}

题十二 构造函数

判断类型

1
typeof 类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Object.prototype.toString.call("abc")

function type(data) {
var toStr = Object.prototype.toString;
if (data === null) return 'null'
var obj = {
'[object Object]': 'Object',
'[object Array]': 'Array',
'[object RegExp]': 'RegExp',
'[object Number]': 'Number',
'[object String]': 'String',
'[object Boolean]': 'Boolean',
}
if (typeof data === 'object') {
return obj[toStr.call(data)]
} else {
return typeof data;
}
}
1
data  instanceof  type

题十三 循环渲染生成节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
let objArr = [
{
nodeType:"li",
className:"bg",
children:[
{
nodeType:"span",
className:"circre",
},
{
nodeType:"img",
className:"",
},
{
nodeType:"div",
className:"wrap-show",
children:[
{
nodeType:"p",
className:"first",
},
{
nodeType:"p",
className:"",
},
{
nodeType:"div",
className:"computed",
children:[
{
nodeType:"span",
className:"first",
},
{
nodeType:"p",
className:"",
children:[
{
nodeType:"span",
className:"",
},
{
nodeType:"span",
className:"",
},
{
nodeType:"span",
className:"",
},
{
nodeType:"span",
className:"",
},
]
},
]
},
]
},
]
}
]



function createNode(objArr,create = document.createDocumentFragment()) {

objArr.forEach(item=>{
let result = document.createElement(item.nodeType)
if(item.children){
createNode(item.children,result)
}
result.className = item.className
create.appendChild(result)
})
return create
}

深拷贝 浅拷贝

浅拷贝:将数据中所有的数据引用下来,并指向同一个存放地址,拷贝的数据修改之后,会对原数据产生副作用。

深拷贝:将数据中所有的数据拷贝下来,对拷贝之后的数据进行修改不会对原始数据产生副作用。

你以为 Object.assign 是深拷贝方法,其实不然。它也是浅拷贝,只不过是第一级的原始类型的数据,不受牵连,引用类型还是会被篡改,我们用数据说话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj = {
name: 'Nick',
hobby: ['code', 'movie', 'travel', { a: 1 }]
};

// var newObj = Object.assign({}, obj) 浅拷贝一层

var newObj1 = JSON.stringify(obj) // 深拷贝
var newObj = JSON.parse(newObj1)


newObj.name = 'Chen';
newObj.hobby[0] = 'codeing';
newObj.hobby[3].a = 2

console.log('obj', obj)
console.log('newObj', newObj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let obj = {
name:"许鑫",
age:18,
arr:[1,2,3,50],
newObj:{
ss:"值",
ww:{
nam:"夏栀"
}
}
};
//使用递归的方式实现数组、对象的深拷贝
function deepClone1(obj) {
//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
let objClone = Array.isArray(obj) ? [] : {};
//进行深拷贝的不能为空,并且是对象或者是
if (obj && typeof obj === "object") {
// key属性名
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") {
如果obj[key] 是一个对象或值 那么就将值传进去 并进行赋值
objClone[key] = deepClone1(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let newObj = deepClone1(obj)

node爬虫

爬取小说

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const axios  = require("axios");
const jsdom = require("jsdom"); // 用于处理后端html文件
const {JSDOM} = jsdom; // 获取jsdom对象 是后端能操作dom时 后端操作dom与前端操作是一样
const fs = require("fs");


//请求地址
let index = `https://www.biquwx.la/47_47090/3664656.html`;

function fun() {
// 请求地址
axios.get(`${index}`).then((res,err)=>{
// 判断路径最后是否是html文件
let result = index.endsWith("html");
// 转换成能使用后端操作的dom
const dom = new JSDOM(res.data);
// 获取下一章的文件路径
index = dom.window.document.querySelectorAll(".bottem1 a")[3].getAttribute("href");
if (result){
// 获取文本内容
const title = `<h3>${dom.window.document.querySelector("h1").textContent}</h3>`;
const text = `${title} <p>${dom.window.document.querySelector("#content").textContent}</p>`;
// 内容文件写入 文件中 {flag:"a"}在原有的内容上添加
fs.writeFile("./index.html",text,{ 'flag': 'a' },()=>{
console.log(index,"true")
fun()
})
}
})
}
fun();

爬取单个图片

1
2
3
4
5
6
7
8
9
10
11
const fs  = require("fs");
const axios = require("axios");

axios.get("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F202005%2F20%2F20200520024521_zkkfs.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1622870925&t=5fab3f50615706cbd4930f73e68a7f01"
,{responseType:'arraybuffer'}) // 返回格式
.then(res=>{
fs.writeFile("./aa.png",res.data,()=>{
console.log("写入成功")
})
});

爬取图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const fs  = require("fs");
const axios = require("axios");
const jsdom = require("jsdom")
const {JSDOM} = jsdom;


axios.get("https://www.tupianzj.com/meinv/mm/nkmv/")
.then(res=>{
let dom = new JSDOM(res.data);
// 循环遍历节点 进行重新取值返回数组
let arr = [...dom.window.document.querySelectorAll("img")].map(item => item.src);
arr.forEach((item,index)=>{
// 设置图片已流的形式写入
axios.get(item,{ responseType:'stream'}).then((ress)=>{
ress.data.pipe(fs.createWriteStream("./66/"+index+".jpg"))
})
})
});

懒加载

后端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const express = require("express")
const app = express();
const fs = require("fs");

function readfileDir(res,url){
fs.readdir("./public/img",function (err,success) {
let result = success.map(item=>url+item)
res.send(result)
});
}

app.use(express.static('public'));
app.get("/img",function (req,res) {
res.header("Access-Control-Allow-Origin","*");
readfileDir(res,req.headers.host+req.url)
};);
app.listen(3000,()=>{console.log("执行成功");});

// 文件目录

前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{margin: 0;padding: 0}
#box{
width: 600px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: auto;
}
#box img{
width: 240px;
height: 350px;
margin-top: 25px;
}
</style>
</head>
<body>

<div id="box">

</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
let result = function () {
return new Promise((res,rej)=>{
$.ajax({
type:"GET",
url:"http://localhost:3000/img/",
success(val){
res(val)
}
});
})
};

result().then((res)=>{

let fream = document.createDocumentFragment();
res.forEach(item=>{
let dom = document.createElement("img");
dom.dataset.url = "http://"+item;
fream.appendChild(dom);
});
$("#box")[0].appendChild(fream);
init()
})

function init(){
let img = [...document.getElementsByTagName("img")];
let clientH = getClient()
img.forEach(item=>{
if(!item.dataset.url)return;
let result = clientH - item.getBoundingClientRect().top > 0;
if(result){
item.src = item.dataset.url;
delete item.dataset.url
}
})
}
function getClient(){
return document.documentElement.clientHeight
}
document.addEventListener("scroll",init)



/*
图片懒加载的原理
1.给每个图片都设置自定义属性data-image存放 图片的真正地址
2.页面在滚动时 检测每个图片的位置
如果图片在浏览器的可视区域之内 那就取出图片的自定义属性data-image的值
把该值赋给图片的src 这个时候图片才会根据src发起网络请求获取图片

*/

</script>
</body>
</html>