• 一面准备:项目经历、开放问题回答、基础


    文章目录

    • 给自己挖的坑现在来填呜呜呜!(其实也不算是坑 毕竟是项目是自己之前亲手做出来的 但是之前的项目经历有的时间太久远很多技术方面的就忘了 现在只有代码)于是现在来做个阶段性总结,把之前的项目经历的一些要点和技术点总结下,以准备面试官大佬的简历提问(瑟瑟发抖~)
    • 趁有时间写点学习前端的小tips。。。(狂补!!!)

    1⃣️项目1:Chrome插件

    作用和怎么想到的:

    因为教务处的网站比较古老,每次登陆的时候都要写验证码和账号密码,是真的很麻烦,同时之前有有关网络安全(比如什么黑进教务处或者是学生信息爬取、选课的时候模拟大规模登录把服务器搞炸啥的,但是仅仅是有这种想法,肯定是违背《网安法》的)而且插件听起来就跟生活很接近,毕竟是在Chrome浏览器上面运行的。

    目录树以及作用:

    前端:

    扩展程序的扩展页面和将信息发到页面其他js的操作:popup.html、popup.js

    <!DOCTYPE html>
    <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>SICNU 教 务 处 登 陆 </title>
        <style>
            * {
                margin: 20;
                padding: 20;
    
            }
    
            body {
                width: 300px;
                height: 250px;
                /* background:-webkit-linear-gradient(bottom,#FF66CC,#FF3399,#CC00FF,#9900FF,#6633FF,#3399FF,#66FFFF,#66FF99,#99FF00,#FFFF66,white); */
                background: -webkit-linear-gradient(bottom, #6633FF, #3399FF,#76daf3);
            }
    
            div {
                line-height: 30px;
                font-size: 30px;
                text-align: center;
            }
    
            p {
                line-height: 25px;
                font-size: 20px;
                text-align: center;
            }
     
            #login_click{ margin-top:40px; height:40px;}
            #login_click a 
            {
                text-decoration:none;
                background:#3399FF;
                color:#f2f2f2;
                
                padding: 5px 20px 5px 20px;
                font-size:16px;
                font-family: 微软雅黑,宋体,Arial,Helvetica,Verdana,sans-serif;
                font-weight:bold;
                border-radius:6px;
                
                -webkit-transition:all linear 0.30s;
                -moz-transition:all linear 0.30s;
                transition:all linear 0.30s;
            
            }
            #login_click a:hover { background:#4d68ff; }
            
    
            #login_click1{ margin-top:40px; height:40px;}
            #login_click1 a 
            {
                text-decoration:none;
                background:#4d68ff;
                color:#f2f2f2;
                
                padding: 5px 20px 5px 20px;
                font-size:16px;
                font-family: 微软雅黑,宋体,Arial,Helvetica,Verdana,sans-serif;
                font-weight:bold;
                border-radius:6px;
                
                -webkit-transition:all linear 0.30s;
                -moz-transition:all linear 0.30s;
                transition:all linear 0.30s;
            
            }
            #login_click1 a:hover { background:#3399FF; }
            .title{
                color: #f3a531;/*#04ff25*/
                margin-top:50px;
                font-size:30px;
                font-family: 微软雅黑,宋体,Arial,Helvetica,Verdana,sans-serif;
                font-weight:bold;
                border-radius:10px;
            }
        </style>
    </head>
    <body>
    
        <div id="container" class="title">
            <!-- <img src="/images/sicnu.png" alt="Pulpit rock" width="30" height="30"> -->
            Never    Mind
        </div>
        <!-- <p line-height=10px font-size=10px>填写账号和密码,一键登陆!</p> -->
        <!-- <p></p> -->
        
        <!-- <p style="margin-top:25px">账号:<input id="username" maxlength="11" type="text/javascript" name="username" /> </p> -->
        <!-- <p style="margin-top:25px">密码:<input id="password" maxlength="20" type="password" name="password" /> </p> -->
        
        <p>
            <!-- <link rel="stylesheet" href="css/login.css" type="text/css" /> -->
            <div style="margin-top:50px" id="login_click1">
                <a id="user" href="#">修改账号密码</a>
            </div> 
            <div style="margin-top:40px" id="login_click">
                <a id="jwc" href="#">登陆教务处!</a>
            </div> 
        </p>
    </body>
    
    <script src='js/popup.js'></script>
    </html>
    
    //控制两个按钮,按下就发greeting
    console.log("######## popup ########")
    //找到标签页tabs的id,发送greeting,等待response
    function sendGreet(greet){
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            chrome.tabs.sendMessage(tabs[0].id, {greeting: greet}, function(response) {
                console.log(response.farewell);
            });
        })
    }
    document.getElementById('jwc').onclick = function()
    {
        // if(document.getElementById('username').value!=null && document.getElementById('password').value!=null){
        //     var bg = chrome.extension.getBackgroundPage();
        //     bg.writedata(document.getElementById('username').value,document.getElementById('password').value);
        // }
        sendGreet("jwc");
    }
    
    document.getElementById('user').onclick = function()
    {
        // if(document.getElementById('username').value!=null && document.getElementById('password').value!=null){
        //     var bg = chrome.extension.getBackgroundPage();
        //     bg.writedata(document.getElementById('username').value,document.getElementById('password').value);
        // }
        sendGreet("user");
    }
    
    
    

    得到popup的跳转指令进行定向跳转的操作:all_content.js

    //接收popup的greeting并跳转
    console.log("######## all_content #########");
    chrome.runtime.onMessage.addListener(
        function (request, sender, sendResponse) {
            if (request.greeting == "jwc") {
                sendResponse({farewell: "request hello success"});
                console.log('ON CLICK message success');
                if (window.location.href.indexOf("202.115.194.60") < 0 ) {
                    console.log("----------------jump----------------");
                    window.open("http://202.115.194.60/");
                    window.close();
                }   
            }
            if (request.greeting == "user") {
                sendResponse({farewell: "request hello success"});
                console.log('ON CLICK message success');
                window.open("http://49.232.13.120:1111/");
                window.close(); 
            }
        }
    );
    

    在教务处域名下获取验证码并识别以及获取账号密码模拟点击登录的操作:content.js(验证码)和getkey_content.js(账号密码并点击)

    //发送验证码图片和收到验证码字符串
    console.log("######## content #########");
    window.onload = function() { 
        if(!document.getElementById("tbPassWord")){
            
        }
        else{
            let imgsrc = "http://202.115.194.60/(S(2uetwrdaij231tdylwslokfu))/CheckCode.aspx";
            let image = new Image();
            image.src = imgsrc;
            image.setAttribute("crossOrigin", "anonymous");
            image.onload = function () {
                let canvas = document.createElement("canvas");
                canvas.width = image.width;
                canvas.height = image.height;
                let context = canvas.getContext("2d");
                context.drawImage(image, 0, 0, image.width, image.height);
                let url = canvas.toDataURL("image/png");  
                console.log(url);  
                var imgbase64 = url.substring(22);
                url = "http://49.232.13.120:1111/sendbase64";
                var request = new XMLHttpRequest();
                try{
                    request.open("POST",url); 
                    request.send(imgbase64);
                }
                catch(e){
                    alert("哼唧 = =# 服务器繁忙请重试的啦!");
                }
                request.onload = function() {
                    if(request.status == 200 && request.responseText.length == 4) {
    
                        document.getElementById("txtCode").value = request.responseText;
                        console.log(request.responseText);
                    }else{
                        window.open("http://202.115.194.60/");
                        window.close();
                    }
                }
            }
        }
    } 
    
    
    
    //获取密码用户名并提交
    console.log("######## getkey_content #######");
    function getusername(){
    	var url = "http://49.232.13.120:1111/getusername"
    	var request = new XMLHttpRequest();
    	try{
    		request.open("GET",url);
    		request.send();
    	}
    	catch(e){
    		alert("哼唧 = =# 服务器繁忙请重试的啦!");
    	}
    	request.onload = function(){
    		if(request.status == 200 && request.response!=""){
    			console.log(request.response);
    			setTimeout(document.getElementById("tbUserName").value = request.responseText,1000);
    			document.getElementById("btnLogin").click();
    		}
    	}
    }
    function getpassword(){
    	var url = "http://49.232.13.120:1111/getpassword"
    	var request = new XMLHttpRequest();
    	try{
    		request.open("GET",url);
    		request.send();
    	}
    	catch(e){
    		alert("哼唧 = =# 服务器繁忙请重试的啦!");
    	}
    	request.onload = function(){
    		if(request.status == 200 && request.response!=""){
    			console.log(request.response);
    			setTimeout(document.getElementById("tbPassWord").value = request.responseText,1000);
    			document.getElementById("btnLogin").click();
    		}else {
    			alert("你还没在插件登陆页面设置账号密码哦!
    QAQ或者是填写错误!
    点击跳转至登陆页面吧!");
    			window.open("http://49.232.13.120:1111/");
    			window.close();
    		}
    	}
    }
    for(var i = 0;i<1;i++){
    	setTimeout(getusername,1000);
    }
    for(var i = 0;i<1;i++){
    	setTimeout(getpassword,1000);
    }
    
    
    
    

    后端:

    Flask相关

    from flask import Flask, request,render_template
    import base64
    import filemaker
    
    app = Flask(__name__)  # 创建�?个服务,赋�?�给APP
    
    
    @app.route('/', methods=['get', 'post'])  # 指定接口访问的路径,支持�?么请求方式get,post
    def wait():
        return render_template('index.html')
    
    
    @app.route('/sendbase64', methods=['get', 'post'])  # 指定接口访问的路径,支持�?么请求方式get,post
    def response():
        url = str(request.get_data())[1:]
        print(url)
        if url:
            ip = str(request.remote_addr)
            try:
                getbase64 = base64.b64decode(url)
            except:
                return url
            text = filemaker.gettext(ip, getbase64)
            print(text)
            return text
        else:
            return "NULL"
    
    
    @app.route('/sendusername', methods=['get', 'post'])
    def sendusername():
        username = str(request.get_data())[1:]
        print(username)
        if username:
            ip = str(request.remote_addr)
            us = filemaker.maketxt(ip + "_username", username)
            print("us:" + us)
            return "us:" + us
        else:
            return "NULL"
    
    @app.route('/sendpassword', methods=['get', 'post'])
    def sendpassword():
        password = str(request.get_data())[1:]
        print(password)
        if password:
            ip = str(request.remote_addr)
            pw = filemaker.maketxt(ip + "_password", password)
            print("pw:" + pw)
            return "pw:" + pw
        else:
            return "NULL"
    
    @app.route('/getpassword', methods=['get', 'post'])
    def getpassword():
        ip = str(request.remote_addr)
        if ip:
            password = filemaker.getpassword(ip)[1:-1]
            print("password" + password)
            return password
        else:
            return "NULL"
    
    
    @app.route('/getusername', methods=['get', 'post'])
    def getusername():
        ip = str(request.remote_addr)
        if ip:
            username = filemaker.getusername(ip)[1:-1]
            print("username" + username)
            return username
        else:
            return "NULL"
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=1111)
    
    
    from PIL import Image
    import img_to_one_zero
    import captcha_to_text
    
    
    def gettext(ip, getbase64):
        file = open(ip + ".png", 'wb')
        file.write(getbase64)
        file.close()
        img = Image.open(ip + ".png")
        img_to_one_zero.ImgtoZeroOne(img, str(ip + ".png"))
        text = captcha_to_text.textpredict(ip + ".png")
        print(text)
        return text
    
    
    def maketxt(ip, data):
        file = open(ip + ".txt", 'w')
        file.write(data)
        file.close()
        return "done"
    
    
    def getpassword(ip):
        file = open(ip + "_password.txt", 'r')
        password = file.readline()
        return password;
    
    
    def getusername(ip):
        file = open(ip + "_username.txt", 'r')
        password = file.readline()
        return password;
    
    

    图像识别相关

    img_to_one_zero.py
    # !/usr/bin/env python
    # -*- coding:utf-8 -*-
    # author: haotian time:2019/10/
    from PIL import Image
    import cv2
    import matplotlib.pyplot as plt
    
    
    def sum_9_region_new(img, x, y):
        """
        9邻域框,以当前点为中心的田字框,黑点个数
        :param x:
        :param y:
        :return:
        """
        # 判断图片的长宽度下限
        cur_pixel = img.getpixel((x, y))  # 当前像素点的值
        width = img.width
        height = img.height
    
        if cur_pixel == 1:  # 如果当前点为白色区域,则不统计邻域值
            return 0
    
        if y == 0:  # 第一行
            if x == 0:  # 左上顶点,4邻域
                # 中心点旁边3个点
                sum = cur_pixel 
                      + img.getpixel((x, y + 1)) 
                      + img.getpixel((x + 1, y)) 
                      + img.getpixel((x + 1, y + 1))
                return 4 - sum
            elif x == width - 1:  # 右上顶点
                sum = cur_pixel 
                      + img.getpixel((x, y + 1)) 
                      + img.getpixel((x - 1, y)) 
                      + img.getpixel((x - 1, y + 1))
    
                return 4 - sum
            else:  # 最上非顶点,6邻域
                sum = img.getpixel((x - 1, y)) 
                      + img.getpixel((x - 1, y + 1)) 
                      + cur_pixel 
                      + img.getpixel((x, y + 1)) 
                      + img.getpixel((x + 1, y)) 
                      + img.getpixel((x + 1, y + 1))
                return 6 - sum
        elif y == height - 1:  # 最下面一行
            if x == 0:  # 左下顶点
                # 中心点旁边3个点
                sum = cur_pixel 
                      + img.getpixel((x + 1, y)) 
                      + img.getpixel((x + 1, y - 1)) 
                      + img.getpixel((x, y - 1))
                return 4 - sum
            elif x == width - 1:  # 右下顶点
                sum = cur_pixel 
                      + img.getpixel((x, y - 1)) 
                      + img.getpixel((x - 1, y)) 
                      + img.getpixel((x - 1, y - 1))
    
                return 4 - sum
            else:  # 最下非顶点,6邻域
                sum = cur_pixel 
                      + img.getpixel((x - 1, y)) 
                      + img.getpixel((x + 1, y)) 
                      + img.getpixel((x, y - 1)) 
                      + img.getpixel((x - 1, y - 1)) 
                      + img.getpixel((x + 1, y - 1))
                return 6 - sum
        else:  # y不在边界
            if x == 0:  # 左边非顶点
                sum = img.getpixel((x, y - 1)) 
                      + cur_pixel 
                      + img.getpixel((x, y + 1)) 
                      + img.getpixel((x + 1, y - 1)) 
                      + img.getpixel((x + 1, y)) 
                      + img.getpixel((x + 1, y + 1))
    
                return 6 - sum
            elif x == width - 1:  # 右边非顶点
                # print('%s,%s' % (x, y))
                sum = img.getpixel((x, y - 1)) 
                      + cur_pixel 
                      + img.getpixel((x, y + 1)) 
                      + img.getpixel((x - 1, y - 1)) 
                      + img.getpixel((x - 1, y)) 
                      + img.getpixel((x - 1, y + 1))
    
                return 6 - sum
            else:  # 具备9领域条件的
                sum = img.getpixel((x - 1, y - 1)) 
                      + img.getpixel((x - 1, y)) 
                      + img.getpixel((x - 1, y + 1)) 
                      + img.getpixel((x, y - 1)) 
                      + cur_pixel 
                      + img.getpixel((x, y + 1)) 
                      + img.getpixel((x + 1, y - 1)) 
                      + img.getpixel((x + 1, y)) 
                      + img.getpixel((x + 1, y + 1))
                return 9 - sum
    
    
    def collect_noise_point(img, n):
        '''收集所有的噪点'''
        noise_point_list = []
        for x in range(img.width):
            for y in range(img.height):
                res_9 = sum_9_region_new(img, x, y)
                if (0 < res_9 < n) and img.getpixel((x, y)) == 0:  # 找到孤立点
                    pos = (x, y)
                    noise_point_list.append(pos)
        return noise_point_list
    
    
    def remove_noise_pixel(img, noise_point_list):
        '''根据噪点的位置信息,消除二值图片的黑点噪声'''
        for item in noise_point_list:
            img.putpixel((item[0], item[1]), 1)
    
    
    def get_bin_table(threshold):
        '''获取灰度转二值的映射table,0表示黑色,1表示白色'''
        table = []
        for i in range(256):
            if i < threshold:
                table.append(0)
            else:
                table.append(1)
        return table
    
    
    def remake(guess_img, much_num, n, i):
        """
        guess_img:传入图片文件
        much_num: 阈值,控制二值化程度,自行调整(不能超过256)
        n:九宫格法去除像素点周围点的数量(推荐6和7)
        """
    
        imgry = guess_img.convert('L')
        table = get_bin_table(much_num)
        binary = imgry.point(table, '1')
        noise_point_list = collect_noise_point(binary, n)
        remove_noise_pixel(binary, noise_point_list)
        binary.save(i)
    
    
    def ImgtoZeroOne(image, i):
        """
        image:传入处理识别图片
        i:第i个图片
        """
        image = image.resize((120, 50))  # 根据图片长宽改正,实验表明以原图大小处理后识别概率比较高
        remake(image, 235, 8, i)
    
        Image.open(i).save(i)
        image = Image.open(i)
        image = image.resize((120, 50))  # 根据图片长宽改正,实验表明以原图大小处理后识别概率比较高
        remake(image, 120, 6, i)
        Image.open(i)
        image = Image.open(i)
        image = image.resize((120, 50))  # 根据图片长宽改正,实验表明以原图大小处理后识别概率比较高
        remake(image, 100, 4, i)
        Image.open(i)
        image = Image.open(i)
        image = image.resize((120, 50))  # 根据图片长宽改正,实验表明以原图大小处理后识别概率比较高
        remake(image, 80, 2, i)
    
    
    captcha_to_text.py
    from keras.models import load_model
    from helpers import resize_to_fit
    from imutils import paths
    import numpy as np
    import imutils
    import cv2
    import pickle
    import tensorflow as tf
    
    MODEL_FILENAME = "captcha_model.hdf5"
    MODEL_LABELS_FILENAME = "model_labels.dat"
    
    
    # Load up the model labels (so we can translate model predictions to actual letters)
    with open(MODEL_LABELS_FILENAME, "rb") as f:
        lb = pickle.load(f)
    
    # Load the trained neural network
    model = load_model(MODEL_FILENAME)
    
    def textpredict(image_file):
        # loop over the image paths
        # image_file = ""
        # Load the image and convert it to grayscale
        image = cv2.imread(image_file)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
        # Add some extra padding around the image
        image = cv2.copyMakeBorder(image, 20, 20, 20, 20, cv2.BORDER_REPLICATE)
    
        # threshold the image (convert it to pure black and white)
        thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
    
        # find the contours (continuous blobs of pixels) the image
        contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
        # Hack for compatibility with different OpenCV versions
        # contours = contours[0] if imutils.is_cv2() else contours[1]
        contours = contours[1] if imutils.is_cv3() else contours[0]
    
        letter_image_regions = []
    
        # Now we can loop through each of the four contours and extract the letter
        # inside of each one
        for contour in contours:
            # Get the rectangle that contains the contour
            (x, y, w, h) = cv2.boundingRect(contour)
    
            # Compare the width and height of the contour to detect letters that
            # are conjoined into one chunk
            if w / h > 1.25:
                # This contour is too wide to be a single letter!
                # Split it in half into two letter regions!
                half_width = int(w / 2)
                letter_image_regions.append((x, y, half_width, h))
                letter_image_regions.append((x + half_width, y, half_width, h))
            else:
                # This is a normal letter by itself
                letter_image_regions.append((x, y, w, h))
    
        # Sort the detected letter images based on the x coordinate to make sure
        # we are processing them from left-to-right so we match the right image
        # with the right letter
        letter_image_regions = sorted(letter_image_regions, key=lambda x: x[0])
    
        # Create an output image and a list to hold our predicted letters
        predictions = []
    
        # loop over the lektters
        for letter_bounding_box in letter_image_regions:
            # Grab the coordinates of the letter in the image
            x, y, w, h = letter_bounding_box
    
            # Extract the letter from the original image with a 2-pixel margin around the edge
            letter_image = image[y - 2:y + h + 2, x - 2:x + w + 2]
    
            # Re-size the letter image to 20x20 pixels to match training data
            letter_image = resize_to_fit(letter_image, 20, 20)
    
            # Turn the single image into a 4d list of images to make Keras happy
            letter_image = np.expand_dims(letter_image, axis=2)
            letter_image = np.expand_dims(letter_image, axis=0)
    
            # Ask the neural network to make a prediction
            prediction = model.predict(letter_image)
    
            # Convert the one-hot-encoded prediction back to a normal letter
            letter = lb.inverse_transform(prediction)[0]
            predictions.append(letter)
    
        # Print the captcha's text
        captcha_text = "".join(predictions)
    
        return captcha_text
    
    

    相关技术点:

    css伪类

    css伪类

    验证码图片怎么获取的

    本来是想着直接从浏览器缓存里面获取第一次请求的图片的,但是由于权限问题属实没有找到方法,于是就只好重新手动模拟请求一个验证码图片咯。

    let imgsrc = "http://202.115.194.60/(S(2uetwrdaij231tdylwslokfu))/CheckCode.aspx";
    let image = new Image();
    image.src = imgsrc;
    image.setAttribute("crossOrigin", "anonymous");//关闭防画布污染策略
    image.onload = function () {
        let canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;
        let context = canvas.getContext("2d");
        context.drawImage(image, 0, 0, image.width, image.height);
        let url = canvas.toDataURL("image/png");  
        console.log(url);  
        var imgbase64 = url.substring(22);
        url = "http://49.232.13.120:1111/sendbase64";
        var request = new XMLHttpRequest();
        try{
            request.open("POST",url); 
            request.send(imgbase64);
        }
        catch(e){
            alert("哼唧 = =# 服务器繁忙请重试的啦!");
        }
    

    如果返回的验证码字符串有问题或者是网络报错(非200)

    request.onload = function() {
                    if(request.status == 200 && request.responseText.length == 4) {
    
                        document.getElementById("txtCode").value = request.responseText;
                        console.log(request.responseText);
                    }else{
                        window.open("http://202.115.194.60/");
                        window.close();//刷新页面重来
                    }
                }
    

    扩展程序popup是怎样传递消息给页面的

    function sendGreet(greet){
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            chrome.tabs.sendMessage(tabs[0].id, {greeting: greet}, function(response) {
                console.log(response.farewell);
            });
        })
    }
    

    tab选择器
    在这里插入图片描述
    然后就可以在popup的js里给页面的content-script发信息啦

    document.getElementById('jwc').onclick = function()
        sendGreet("jwc"); # 这里就可以给页面发送信息啦!
    }
    

    页面怎么接收popup的信息呢,并且怎样实现只要在每个页面点击教务处登录按钮就能跳转页面登录的呢

    chrome.runtime.onMessage.addListener(
        function (request, sender, sendResponse) {
            if (request.greeting == "jwc") {
                sendResponse({farewell: "request hello success"});
                console.log('ON CLICK message success');
                if (window.location.href.indexOf("202.115.194.60") < 0 ) {
                    console.log("----------------jump----------------");
                    window.open("http://202.115.194.60/");
                    window.close();
                }   
            }
            if (request.greeting == "user") {
                sendResponse({farewell: "request hello success"});
                console.log('ON CLICK message success');
                window.open("http://49.232.13.120:1111/");
                window.close(); 
            }
        }
    );
    

    2⃣️项目2(基于数据挖掘和语义情感分析的商品指标评价研究)

    在这里插入图片描述
    主要收获是:
    在GitHub上找到了类似的网站评论语义情感分析的代码,用的是LSTM时间循环神经网络,于是我就git clone然后改了改调用了下,训练了模型然后给那道题的评论进行情感分析;
    一些数据处理的方式:就比如纯手写了一个解决“3/14/2020这种日月年中间还有个符号的,在excel里面完全找不到排序方式”的python代码,主要思想是找到那串字符的两个“/”的位置;
    然后就是一些数学算法的python实现。

    3⃣️前端面试复习笔记:

    输入一个url到页面呈现到浏览器上的全过程

    详细版

    1. DNS解析
      在这里插入图片描述
    2. TCP连接建立(三次握手,四次挥手)
      TCP(Transmission Control Protocol)传输控制协议
      TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
      位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
      第一次握手(A向B请求建立联机):主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1就知道A要求建立联机;
      第二次握手(B向A请求确认联机):主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1随机产生seq=7654321的包;
      第三次握手(A向B回复确认联机的情况):主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功
      FTP协议及时基于此协议。
      在这里插入图片描述
      为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
    3. 加载文件(HTML,JS,CSS)
    4. 渲染页面(生成DOMtree,CSSrule,结合成render tree ,页面布局,元素绘制)

    怎样以对象为构造函数创建一个对象

    设计模式

    Js的新规范

    你平时开发中,是怎么调试代码的?

    console.log , alert(),其他语言设置断点

    跨域解决方案:使用CORS实现跨域

    跨域

    类的继承

    vim

    在这里插入图片描述

    Linux命令

    Linux命令

    JS中new操作符具体做了什么事情

    var a = new A();
    1.创建一个空对象 : var obj={}
    2.继承A原型链: obj=A.prototype
    3.将this指向obj执行A :A.call(obj)
    或者

    1. 创建一个全新的对象;
    2. 把这个对象内置的的原型引用指向到构造函数的prototype属性所引用的对象上;
    3. 将函数中的this对象指向这个全新的对象;
    4. 如果函数return出去的是一个引用类型的值,则返回这个值;否则就return这个全新的对象。

    transition和animation区别

    Transition:对元素某个属性或多个属性的变化,进行控制(时间等),类似flash的补间动画。但只有两个关键贞。开始,结束。 Animation:对元素某个属性或多个属性的变化,进行控制(时间等),类似flash的补间动画。可以设置多个关键贞。 Transition与Animation区别: transition需要触发一个事件,而animation在不需要触发任何事件的情况下也可以显式的随着时间变化来改变元素css的属性值,从而达到一种动画的效果。 Transition: transition属性是一个简单的动画属性,非常简单非常容易用。可以说它是animation的简化版本,是给普通做简单网页特效用的。
    transition和animation都随着时间改变元素的属性值

    transition注重过渡 需要一个触发事件如鼠标移动等 transition只有开始和结束两帧 即from…to

    animation可以一帧一帧执行 不需要事件的触发

    http状态码

    在这里插入图片描述

    cookie sessionStorage localStorage

    在这里插入图片描述
    cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递
    cookie数据还有路径(path)的概念,可以限制。cookie只属于某个路径下。
    存储大小限制也不同
    cookie数据不能超过4K,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如回话标识。
    webStorage虽然也有存储大小的限制,但是比cookie大得多,可以达到5M或更大
    数据的有效期不同
    sessionStorage:仅在当前的浏览器窗口关闭有效;
    localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
    cookie:只在设置的cookie过期时间之前一直有效,即使窗口和浏览器关闭
    作用域不同
    sessionStorage:不在不同的浏览器窗口都是共享,即使是同一个页面;
    localStorage:在所有同源窗口都是共享的;
    cookie:也是在所有同源窗口都是共享的

    冒泡排序、快速排序

    都是交换排序 所以时间复杂度都是O(n2)
    冒泡:通过从头的交换找出相对最大的,排到后面
    快速:设置某个标准,划分比他大和比他小的两部分;一直循环迭代到左右两边只有1个值

    cookie的安全性

    在这里插入图片描述

    cookie防xxs攻击

    对重要的cookie设置httpOnly,防止客户端通过document.cookie读取cookie

    删除cookie

    设置往前一点的时间

    var date = new Date();
    date.setDate(date.getDate() - 1);//真正的删除
    

    let(块中) var(上下文) const(只读)

    在这里插入图片描述

    操作系统:进程调度

    个人认为实用性排序:634215
    1、先来先服务,就是按照顺序来;
    2、短作业优先,就是按照时间花费排序,最短的最先做;
    3、优先权调度,就是在上面两个方式上,如果遇到优先权高的,就do it,或者提前设置任务优先权,然后越高越优先;
    4、高响应比优先度,因为短作业优先算法不能照顾长的作业,也就是长的作业一直要等到最后做,所以改进方式就是,长作业的优先度和长作业的等待时间成正比,有长作业超过此时的短作业的优先度就do it;
    5、时间片轮转法,就是给每个作业分配相同的时间片,就比如45分钟的课分5份9分钟,固定时间内分别做一个作业,再循环;
    6、多级反馈队列调度,设置多个就绪任务队列,赋予不同优先级,从高到低排,但是越高优先度的分配的执行时间片越小,如果第一个优先级最高的任务在第一个短的时间片没做完,那么转而跳到第二个优先级的任务和第二个相对较长的时间片,在这个时间里面先做第二个任务,如果第二个任务做完有剩余时间,那么就做之前的第一个没做完的任务,如果第一个任务在这个时间内还是没做完,那么转而到第三个任务和时间片以此类推,也就是说这个优先度高但是执行时间长的任务在不影响其他任务完成的情况下,用每个时间片的剩余时间执行。

    进程和线程区别

    1、进程:系统进行资源分配和调度的基本单位
    线程:操作系统能够进行运算调度的最小单位
    2、进程:进程是程序的基本执行实体
    线程:程序独立调度和分派的基本单位
    3、进程:描述系统内部各道程序的活动规律引进的一个概念
    通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。
    在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。

    XMLHttpRequest

    XMLHttpRequest
    在不重新加载页面的情况下更新网页
    在页面已加载后从服务器请求数据
    在页面已加载后从服务器接收数据
    后台向服务器发送数据

    var url = "http://49.232.13.120:1111/getpassword"
    	var request = new XMLHttpRequest();
    	try{
    		request.open("GET",url);
    		request.send();
    	}
    	catch(e){
    		alert("哼唧 = =# 服务器繁忙请重试的啦!");
    	}
    

    GET POST PUT

    http请求方法
    GET 发送一个请求来取得服务器上的某一资源
    POST 向URL指定的资源提交数据或附加新的数据
    PUT 跟POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有

    http和https

    链接
    超文本传输协议
    加不加密
    http1.0只能传html 后面可以传js css了

    箭头函数和this

    • 箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。
    //ES5 Version
    var getCurrentDate = function (){
      return new Date();
    }
    
    //ES6 Version
    const getCurrentDate = () => new Date();
    

    在本例中,ES5 版本中有function(){}声明和return关键字,这两个关键字分别是创建函数和返回值所需要的。在箭头函数版本中,我们只需要()括号,不需要 return 语句,因为如果我们只有一个表达式或值需要返回,箭头函数就会有一个隐式的返回。

    //ES5 Version
    function greet(name) {
      return 'Hello ' + name + '!';
    }
    
    //ES6 Version
    const greet = (name) => `Hello ${name}`;
    const greet2 = name => `Hello ${name}`;
    

    我们还可以在箭头函数中使用与函数表达式和函数声明相同的参数。如果我们在一个箭头函数中有一个参数,则可以省略括号。

    const getArgs = () => arguments
    
    const getArgs2 = (...rest) => rest
    

    箭头函数不能访问arguments对象。所以调用第一个getArgs函数会抛出一个错误。相反,我们可以使用rest参数来获得在箭头函数中传递的所有参数。

    const data = {
      result: 0,
      nums: [1, 2, 3, 4, 5],
      computeResult() {
        // 这里的“this”指的是“data”对象
        const addAll = () => {
          return this.nums.reduce((total, cur) => total + cur, 0)
        };
        this.result = addAll();
      }
    };
    

    箭头函数没有自己的this值。它捕获词法作用域函数的this值,在此示例中,addAll函数将复制computeResult 方法中的this值,如果我们在全局作用域声明箭头函数,则this值为 window 对象。

    • this

    在这里插入图片描述

    改变函数内部this指针的指向函数有哪几种,他们的区别是什么

    bind 返回一个新的函数, 第一个参数是改变this指向的对象 直接传参
    apply 对函数的直接调用, 第一个参数是改变this指向的对象 第二个参数用数组包裹
    call 对函数直接调用,第一个参数是改变this指向的对象 直接传参

    一个图片url访问后怎样下载

    右击可下载
    跨域情况下 关闭画布污染策略 canvas.drawImage canvas.toDataURL
    在这里插入图片描述

    节流和防抖

    链接

    闭包(调用父函数变量)

    闭包形成条件
    条件一 函数嵌套
    条件二 子函数访问父函数变量
    条件三 外部访问子函数 可以获取函数作用域的变量

    优点:可以从函数外部访问函数内部变量、保留变量不会被销毁,缺点:不会被垃圾回收机制回收

    移动端布局

    移动端布局方式(一般采用自适应布局),移动端适配:
    a.流体布局+少量响应式
    b.基于rem的布局
    c.弹性布局。响应式布局很少应用在移动端,因为工作量大难以维护。
    流体布局:尺寸使用百分比而不是像素,能针对浏览器的窗口宽度进行伸缩。
    基于rem的布局 :rem是相对于根元素的字体大小单位,是一个相对元素
    弹性布局:Flex容器、Flex项目、水平的主轴(main axis)、垂直的交叉轴(cross axis)。
    设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。
    容器上设置的属性:
    flex-direction
    flex-wrap
    flex-flow
    justify-content
    align-items
    align-content
    http://www.runoob.com/w3cnote/flex-grammar.html

    项目上设置的属性
    order
    flex-grow
    flex-shrink
    flex-basis
    flex
    align-self

    type="submit"表单提交理解

    type="submit"表单提交理解

    MVC和MVVM&MVP

    参考链接

    • MVC的controller:
      数据和视图的协调者,也就是在Controller里面把Model的数据赋值给View来显示(或者是View接收用户输入的数据然后由Controller把这些数据传给Model来保存到本地或者上传到服务器)
      MVP(Model-View-Presenter)是MVC的改良模式,由IBM的子公司Taligent提出。和MVC的相同之处在于:Controller/Presenter负责业务逻辑,Model管理数据,View负责显示只不过是将 Controller 改名为 Presenter,同时改变了通信方向。

    • MVP特点:

    M、V、P之间双向通信。
    View 与 Model 不通信,都通过 Presenter 传递。Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。
    View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
    Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,这样就可以重用。不仅如此,还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试–从而不需要使用自动化的测试工具。

    • 在MVP中,View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部。
    • 在MVC中,View会直接从Model中读取数据而不是通过 Controller。

    MVP优点:

    模型与视图完全分离,我们可以修改视图而不影响模型;
    可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
    我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
    如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。
    MVP缺点:

    视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更。

    MVP应用:
    可应用与Android开发。

    三张图

  • 相关阅读:
    <unittest学习8>unittest生成测试报告
    <unittest学习7>unittest的封装方法
    <unittest学习6>unittest多种加载用例方法
    <unittest学习5>unittest的几种执行方式和java的junit的很像
    <unittest学习4>跳过用例
    实验3.1
    I
    大数据运维---Zookeeper学习
    裸金属纳管
    一次Linux系统被攻击的分析过程
  • 原文地址:https://www.cnblogs.com/SiriusZHT/p/14310773.html
Copyright © 2020-2023  润新知