前端技術小结-2019

CSS

  1. 盒模型

    在一个文档中,每个元素都被表示为一个矩形的盒子。

    确定这些盒子的尺寸, 属性(颜色,背景,边框方面)和位置是渲染引擎的目标。

    总结:margin、border、padding、content

  2. css单位

    px, rem,em, vh, vw, %

    单位 描述
    % 百分比
    px 像素 (计算机屏幕上的一个点)
    rem 1rem 等于文档跟标签(<html>)的字体尺寸
    vh 当前视口的高度
    vw 当前视口的宽度
    em 1em 等于当前的字体尺寸。2em 等于当前字体尺寸的两倍。
    cm 厘米
    mm 毫米
    ex 一个 ex 是一个字体的 x-height。 (x-height 通常是字体尺寸的一半。)
    pt 磅 (1 pt 等于 1/72 英寸)
  3. css选择器

    选择器 名称 示例 示例说明
    .class .intro 选择所有class="intro"的元素
    #id id选择器 #firstname 选择所有id="firstname"的元素
    * 通配符 * 选择所有元素
    element 标签 p 选择所有 <p> 元素
    element element 后代选择器 div p 选择<div>元素内的所有<p>元素
    element>element 子选择器 div>p 选择所有父级是<div>元素的<p>元素
    element+element 兄弟选择器 div+p 选择所有紧接着<div>元素之后的<p>元素
    [attribute] 属性选择器 [target] 选择所有带有target属性元素
    [attribute=value] 属性选择器 [target=-blank] 选择所有使用target="-blank"的元素
    :nth-child(n) p:nth-child(2) 选择每个p元素是其父级的第二个子元素
    :nth-last-child(n) p:nth-last-child(2) 选择每个p元素的是其父级的第二个子元素,从最后一个子项计数
    :nth-of-type(n) p:nth-of-type(2) 选择每个p元素是其父级的第二个p元素
    :nth-last-of-type(n) p:nth-last-of-type(2) 选择每个p元素的是其父级的第二个p元素,从最后一个子项计数
    :empty p:empty 选择每个没有任何子级的p元素(包括文本节点)
  1. bfc 清除浮动
    i:  bfc
            float为 left|right      变成了全部浮动布局,不友好
            overflow为 hidden|auto|scroll;  影响滚动
            display为 table-cell|table-caption|inline-block; 表格模式
            position为 absolute|fixed;     定位会使父容器的父容器塌陷
    
    
    i:  在父盒子里面的最后添加一个盒子并设置样式;
            <div style="clear:left;"><div>;
            缺点:数据和表现混淆
            
    
  i: 伪元素 - 对父容器添加伪类;
        .floatfix:after{
            content:"."; 
            display:block; 
            height:0; 
            visibility:hidden; 
            clear:left;
        }
        .floatfix{
            *zoom:1;
        }
  1. 层叠上下文

css属性:z-index;

  1. HTML5新增标签

语义话:利于搜索引擎的搜索

标签 示例 说明
audio 用于支持和实现视频文件的直接播放,支持缓冲预载和多种视频媒体格式,如WEBM、MP4、OGG。
video 音频标记,用于支持和实现音频文件的直接播放,支持缓冲预载和多种音频媒体格式,如MP3、OGG、WAV。
datalist <input list="browsers">
<datalist id="browsers">
    <option value="Internet Explorer">
</datalist>
表单标记,关联列表的输入框
article article的语意就像章节,它的内容是独立的,而不是仅仅的“段落”
aside aside标签定义其所处内容之外的内容。
section 定义网页的中的“区块”
header
footer 用来定义页尾
embed 插入媒体标签
input属性 date:可以选择日期;
time: 时间;
month: 年份月份;
week: 周;
search:比普通文本框增加了一个可全部删除的按钮;
range:是一个可拖动的滑动框;
url:校验url的合法性
email: 校验email的合法性;
  1. 常见页面布局
    • flex 弹性布局
    • table 表格布局
    • div + css
  2. 响应式布局

Responsive design,意在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。

    <!--1. 使用视图的meta标签来进行-->
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <!--2. 使用css媒体查询标签-->
    <style>
        @media screen and (max-width: 980px) {}
        @media only screen and (min-width: 320px) and (max-width: 767px) {}
    </style>
  1. css预处理,后处理

以最终生成 CSS 为目的的 领域特定语言。
Sass、LESS、Stylus 是目前最主流的 CSS 预处理器。

后处理:我们很久以前就在用 CSS 后处理器 了,最典型的例子是 CSS 压缩工具(如 clean-css),只不过以前没单独拿出来说过。
还有最近比较火的 Autoprefixer,以 Can I Use 上的 浏览器支持数据 为基础,自动处理兼容性问题。

  1. css3新特性

    • animation和transiton的相关属性

    animation: 动画

    属性 描述
    @keyframes 规定动画。
    animation 所有动画属性的简写属性,除了 animation-play-state 属性。
    transition-duration 定义过渡效果花费的时间。默认是 0。
    transition-timing-function 规定过渡效果的时间曲线。默认是 "ease"。
    transition-delay 规定过渡效果何时开始。默认是 0。

    transition: 过度效果;

    属性 描述
    transition 简写属性,用于在一个属性中设置四个过渡属性。
    transition-property 规定应用过渡的 CSS 属性的名称。
    transition-duration 定义过渡效果花费的时间。默认是 0。
    transition-timing-function 规定过渡效果的时间曲线。默认是 "ease"。
    transition-delay 规定过渡效果何时开始。默认是 0。
    • animate和translate
  1. display哪些取值
    div {
        display: flex/block/inline-block/inline/none/table;
    }
  1. 相邻的两个inline-block节点为什么会出现间隔,该如何解决
产生间隔的原因:
元素被当成行内元素排版的时候,原来HTML代码中的回车换行被转成一个空白符,在字体不为0的情况下,空白符占据一定宽度,所以inline-block的元素之间就出现了空隙。这些元素之间的间距会随着字体的大小而变化,当行内元素font-size:16px时,间距为8px。
解决方法:设置父元素的字体大小为0;子元素重新设置在字体大小;
  1. meta viewport 移动端适配
在head标签里面加一个meta标签,name = viewport 
<meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> 
  1. CSS实现宽度自适应100%,宽高16:9的比例的矩形
        <style>
        *{
            margin: 0px;
            padding: 0px;
        }
        /* .wrap:包裹矩形的div,用来控制矩形的大小 */
        .wrap{
            width: 20%;
        }
        /* .box 矩形div,宽度是.wrap的百分百,这主要是为了方便高度的计算 */
        .box{
            width: 100%;/*防止矩形被里面的内容撑出多余的高度*/
            height: 0px;/* 16:9padding-bottom:65.25%,4:3padding-bottom:75% */
            padding-bottom: 65.25%;
            position: relative;
            background: pink;
        }
        /* 矩形里面的内容 ,要设置position:absolute,才能设置内容高度100%和矩形一样 */
        .box p{
            width: 100%;
            height: 100%;
            position: absolute;
            color: #666;
        }
    </style>
    <body>
        <div class="wrap">
            <div class="box">
                <p>&nbsp;&nbsp;这是一个16:9的矩形</p>
            </div>
        </div>
    </body>
    

15.rem布局的优缺点

rem布局是通过对html元素设置字体大小,1rem = 很标签字体大小,通常 10rem = 1vw
优点:解决了多屏幕适配问题
缺点:

  1. 画三角形
<html>
<head>
    <style>
        #oval {
          width: 200px;
          height: 100px;
          background: red;
          border-radius: 100px / 50px;
        }
        #triangle {
            width: 0;
          height: 0;
          border-left: 50px solid transparent;
          border-right: 50px solid transparent;
          border-bottom: 100px solid red;
        }
        #triangle-topleft {
          width: 0;
          height: 0;
          border-top: 100px solid red;
          border-right: 100px solid transparent;
        }
    </style>
</head>
<body>
    <div id="oval"></div>
    <div id="triangle"></div>
    <div id="triangle-topleft"></div>
</body>
</html>

  1. 1像素边框问题
  • 1媒体查询利用设备像素比缩放,设置小数像素
    .bodrder {
            border: 1px solid #ff4400;
        }
    @media screen and (-webkit-min-device-pixel-ratio: 2) {
        .bodrder {
            border: 0.5px solid #ff4400;
        }
    }
    @media screen and (-webkit-min-device-pixel-ratio: 3) {
        .bodrder {
            border: 0.33333px solid #ff4400;
        }
    }

  • 2 viewport + rem 方案,利用viewport + rem + js 动态的修改页面的缩放比例,实现小于1像素的显示。
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">  
<meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> 
var viewport = document.querySelector("meta[name=viewport]")
if (window.devicePixelRatio == 1) {
    viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')
} 
if (window.devicePixelRatio == 2) {
    viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no')
} 
if (window.devicePixelRatio == 3) {
    viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no')
} 

var docEl = document.documentElement;
var fontsize = 10 * (docEl.clientWidth / 375) + 'px';
docEl.style.fontSize = fontsize;
  • 3设置 border-image 方案, 缺点:需要制作图片,圆角可能出现模糊
.border-image-1px {
    border-width: 1px 0px;
    -webkit-border-image: url("border.png") 2 0 stretch;
    border-image: url("border.png") 2 0 stretch;
}
  • 4 transform: scale(0.5)
/*
@media screen and (-webkit-min-device-pixel-ratio: 3) {
    .bodrder {
        border: 0.33333px solid #ff4400;
    }
}
 */
/* 2倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 2.0) {
    .border-bottom::after {
        -webkit-transform: scaleY(0.5);
        transform: scaleY(0.5);
    }
}

/* 3倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 3.0) {
    .border-bottom::after {
        -webkit-transform: scaleY(0.33333);
        transform: scaleY(0.33333);
    }
}

html5

  1. 语义化

在HTML5出现之前,我们一般采用DIV+CSS布局我们的页面。但是这样的布局方式不仅使我们的文档结构不够清晰,而且不利于搜索引擎爬虫对我们页面的爬取。为了解决上述缺点,HTML5新增了很多新的语义化标签。<article>、<section>、<nav>、<aside>、<header>、<footer>

  1. 新标签新特性

比 <div> 标签有更加丰富的含义,方便开发与维护
搜索引擎能更方便的识别页面的每个部分
方便其他设备解析(如移动设备、盲人阅读器等)

  1. input和textarea的区别

input:单行文本框,textarea:多行文本框。

  1. 用一个div模拟textarea的实现
#contenteditable {
    height: 150px;
    width: 200px;
    overflow-y: auto;
    border: 1px solid #ff4400;
}
<div id="contenteditable" contenteditable="true">
    IE6以上都兼容
</div>
  1. 移动设备忽略将页面中的数字识别为电话号码的方法
<meta name="format-detection" content="telephone=no">

JS

1、原型/原型链/构造函数/实例/继承

  • 原型

唯有函数类型天生拥有属性prototype,这个属性被称为原型。

  • 原型链

-- 函数.prototype === 原型
-- 构造方法函数.prototype===原型
-- 原型.constructor===该函数对象的构造方法
-- 实例的proto===构造方法.prototype
-- Foo.prototype === Foo.prototype .constructor.prototype === fooInstance.proto
-- fooInsatance.constructor === Foo.prototype.constructor

2、有几种方式可以实现继承

  • 1)、原型链继承, 属性无法传递,缺点:多个实例对引用类型的操作会被篡改。
        //  父类
        function Animal (name, age) {
            this.name = name;
            this.age = age;
        }
        
        //  父类原型方法
        Animal.prototype.say = function () {
            console.log('I am Animal');
        }
        
        //  子类
        function Cat (color) {
            this.color = color;
        }
        
        // 子类通过原型实现继承
        Cat.prototype = new Animal();
        
        // 子类的 ‘实例’
        var xiaohua = new Cat();
        
        xiaohua.say();      // "I am Animal"
    
  • 2)、构造函数式继承
  // 缺点:无法继承原型上的属性/方法;无法实现复用,每个子类都有父类实例函数的副本,影响性能
  function Animal(name, age) {
    this.name = name
    this.age = age
    this.sayName = function(){
      console.log(this.name)
    }
  }

  Animal.prototype.say = function () {
    console.log('I am Animal');
  }

  function Cat(name, age, color) {
    Animal.call(this, name, age)
    this.color = color
  }

  var cat1 = new Cat('xiaohua', 1, 'red')
  cat1.sayName() // I am Animal
  cat1.say() // cat1.say is not a function
  • 3)、组合继承(原型+构造函数)
  // 组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。
 //  缺点:调用了2次父类
  
 function Animal(name, age) {
    this.name = name
    this.age = age
    this.sayName = function(){
      console.log(this.name)
    }
  }

  Animal.prototype.say = function () {
    console.log('I am Animal:  ' + this.name);
  }

  function Cat(name, age, color) {
    Animal.call(this, name, age)
    this.color = color
  }

  Cat.prototype = new Animal();
  Cat.constructor = Cat;

  var cat1 = new Cat('xiaohua', 1, 'red')
  cat1.say()
  
  var cat2 = new Cat('tudou', 2, 'yellow')
  cat2.say()
  • 4)、原型式继承
// 缺点:和原型链继承一样,都会共享引用类型
    function createObj(o) {
            function F(){};
            F.prototype = o;
            return new F();
        }

        Animal = {
            name: 'name',
            age: 10,
            say: function() {
                console.log(this.name)
            },
            colors: ['green', 'red']
        }

        var cat = createObj(Animal)

        cat.name = 'xiao hua';
        cat.colors.push('yellow')
        console.log(cat.colors) //[['green', 'red', 'yellow']
        cat.say() // xiao huaa
  • 5)、寄生式继承
     // 寄生式继承  可以理解为在原型式继承的基础上增加一些函数或属性
     var Animal = {
            name: 'xiao ming',
            colors: ['gre', 'yel', 'red']
        }

        function CreateObj(o) {
            function F() { };
            F.prototype = o;
            var a = new F();
            a.sayName = function() {
                console.log('Animal:  '+ this.name)
            }
            a.sayColor = function() {
                console.log('%o', this.colors)
            }
            return a
        }

        // 上面CreateObj函数 在ECMAScript5 有了一新的规范写法,Object.create(ob) 效果是一样的 , 看下面代码
        var dog = CreateObj(Animal)

        var cat = CreateObj(Animal)

        dog.name = 'xiao huang';
        dog.sayName()
        dog.colors.push('black')

        cat.sayName()
        cat.sayColor()
  • 6)、寄生组合式继承
// 子类构造函数复制父类的自身属性和方法,子类原型只接收父类的原型属性和方法
        function Animal(name, age){
            this.name = name;
            this.age = age;
            this.colors = ['yellor','black']
        }

        Animal.prototype.say = function() {
            console.log(this.colors)
        }

        Animal.prototype.sing = function() {
            console.log('sing: animal')
        }

        function Cat(name, age) {
            Animal.call(this, name, age);
        }

        function Extend(child, parent){
            child.prototype = Object.create(parent.prototype);
            child.prototype.cunstructor = child;
        }

        Extend(Cat, Animal);

        Cat.prototype.sing = function(){
            console.log('sing: cat, cat')
        }

        var cat1 = new Cat('xiao hua', 2)
        var cat2 = new Cat('xiao long', 2)
        cat1.colors.push('sadf')
        cat1.say(); // ["yellor", "black", "sadf"]
        cat1.sing(); // 'sing: cat, cat
        
        cat2.say(); // // ["yellor", "black"]

  • 7)、混入方式继承多个对象
    不会
  • 8)、ES6类继承 extends
        class Animal {

            constructor(name, age) {
                this.name = name;
                this.age = age;
                this.colors = ['黄色', '白色', '黑色']
            }

            say() {
                console.log(`我是${this.name}, 今年${this.age}岁`)
            }

            sayColor() {
                console.log(`颜色 ${this.colors}`)
            }

            sing() {
                console.log('animal singing')
            }
        }

        class Cat extends Animal {

            constructor(name, age) {
                super(name, age)
            }

            sing() {
                console.log('cat singing')
            }        
        }

        var cat1 = new Cat('xiao hua', 2);
        var cat2 = new Cat('tu dou', 5);
        cat2.colors.push('en')
        cat1.say(); // 我是xiaohua, 今年2岁

        cat1.sayColor(); // 颜色 黄色,白色,黑色
        cat2.sayColor();
        cat1.sing(); //  cat singing

        console.log(cat1 instanceof Animal) // true

3、用原型实现继承有什么缺点,怎么解决

 缺点:和原型链继承一样,都会共享引用类型
 Object.create() 来创建父类的原型
 child.prototype = Object.create(parent.prototype);

4、arguments

、// 每一个函数都有一个arguments对象,它包括了函数所要调的参数, 是一个伪数组
 // 伪数组转化为真数组,
 function() {
     var args  = arguments;
     args = Array.prototype.slice.call(args)
     
     args = Array.from(args)
     
     // 去重
     new Set(arrs)
 }

5、数据类型判断

//    JS数据类型的判断主要有三种方法:typeof、instanceof、Object.prototype.toString.call()
        /* typeof */ 
        console.log(typeof Symbol());  // symbol 
        console.log(typeof '');  // string
        console.log(typeof 2); // number
        console.log(typeof true); // boolean
        console.log(typeof undefined); // undefined
        console.log(typeof new Function()); // function
        console.log(typeof null); // object 无效
        console.log(typeof new Date()); // object 无效
        console.log(typeof []); // object 无效
        console.log(typeof new RegExp()); // object 无效
        
        /*Object.prototype.toString.call()*/
        console.log(Object.prototype.toString.call(Symbol()))  // [object Symbol]
        console.log(Object.prototype.toString.call('')) // [object String]
        console.log(Object.prototype.toString.call(2)) // [object String]
        console.log(Object.prototype.toString.call(true)) // [object Number]
        console.log(Object.prototype.toString.call(undefined)) // [object Boolean]
        console.log(Object.prototype.toString.call(new Function())) // [object Function]
        console.log(Object.prototype.toString.call(null)) // [object Null]
        console.log(Object.prototype.toString.call(new Date())) // [object Date]
        console.log(Object.prototype.toString.call(new RegExp())) // [object RegExp]

6、作用域链、闭包、作用域

// 作用域 - 函数作用域和快作用域
函数外部无法访问函数内部的变量,函数嵌套函数的作用域称为作用域链,内部函数可以访问外部函数作用域的变量
// 作用域 私有函数

// 闭包:可以访问另一个函数中的变量的函数,创建闭包即在一个函数内创建另一个函数;  闭包就是能够读取到其他函数内部变量的函数
// 简单讲:及时指有权访问另一个函数作用域中变量的函数


7、Ajax的原生写法

        var xhr;
        if (window.XMLHttpReuest) {
            xhr = new XMLHttpRequest();
        } else {
            xhr = new ActiveXObject('Microsoft.XMLHTTP')
        }

        //  step2.使用open方法设置和服务器的交互信息:
        //  设置请求的url参数,参数一是请求的类型,参数二是请求的url,参数三指定是否使用异步,默认是true
        xhr.open('post', "", true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readState === 4) {
                if (xhr.status === 200) {
                    console.log(xhr.responseText)
                } else {
                    console.log(xhr.status)
                }
            }
        }

8、对象深拷贝、浅拷贝


// # 浅拷贝
var target = {};
var source = {a:1};
Object.assign(target ,source);
console.log(target); //{a:1}
source.a = 2;
console.log(source); //{a:2}
console.log(target); //{a:1}
// Object.assign是一个浅拷贝,它只是在根属性(对象的第一层级)创建了一个新的对象,但是对于属性的值是仍是对象的话依然是浅拷贝,


// ...扩展符

var obj = {a:1,b:{c:1}}
var obj2 = {...obj};
obj.a=2;
console.log(obj); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}

obj.b.c = 2;
console.log(obj); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}

// # 深拷贝
// JSON.stringify()
// 贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
// 无法拷贝不可枚举的属性,无法拷贝对象的原型链
// 拷贝Date引用类型会变成字符串
// 拷贝RegExp引用类型会变成空对象
// 对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
// 无法拷贝对象的循环应用(即obj[key] = obj)

var obj1 = {
    a:1,
    b:[1,2,3]
}
var str = JSON.stringify(obj1)
var obj2 = JSON.parse(str)
console.log(obj2); // {a:1,b:[1,2,3]}
obj1.a=2
obj1.b.push(4);
console.log(obj1); // {a:2,b:[1,2,3,4]}
console.log(obj2); // {a:1,b:[1,2,3]}

function deepCopy(obj) {
    if(typeof obj !== 'object') return obj;
    if(typeof obj === null) return null;
    var copyObj = {};  // 在堆内存中新建一个对象
    for (const key in obj) {
        if(typeof obj[key] === 'object') {
            deepCopy(obj)
        }else {
            copyObj[key] = obj[key]
        }
    }
}

9、图片懒加载、预加载


// 懒加载也叫延迟加载:前一篇文章有介绍:JS图片延迟加载 延迟加载图片或符合某些条件时才加载某些图片。

function loadImage(url, cb){
    var img = new Image();
    img.src = url;
    if(img.complete){
        cb(img);
        return;
    }
    img.onload = function() {
        img.onload = null;
        cb.call(img);
    }
}


// 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染


10、实现页面加载进度条


document.onreadystatechange = function() {
    if(document.readyState === 'complete'){
        /*
            uninitialized - 还未开始载入
            loading - 载入中
            interactive - 已加载,文档与用户可以开始交互
            complete - 载入完成
        */
    }
}

11、this关键字

  // 输出下面的结果
  var a = 10;
  var o = {
    a: 11,
    b: {
      fn: function () {
        console.log(this.a)
      }
    }
  }

  o.b.fn() // undefined
// 显式绑定  
    // bind,apply,call能显式改变this指向
    
// 隐士绑定  (方法调用)
// 谁调用, this指向谁,所以指向b, 对象b里面没有a,所以是undefined

12、函数式编程

函数式编程是一种编程范式,是一种构建计算机程序结构和元素的风格,它把计算看作是对数学函数的评估,避免了状态的变化和数据的可变。
// 1 函数作为参数传递
// 2 函数作为返回值输出

## 作为参数传递 - ajax回调函数

## 函数作为返回值输出
    // 预置函数
    function after(time, cd){
        return function(){
            if(--time === 0){
                cb();
            }
        }
    }
    
    let eat = after(3, function(){console.log('吃饱了')});
    eat();
    eat();
    eat();
    
    // 单例模式 (不会) 模态框弹窗的时候,不希望有两个弹窗
    // 单例模式 - 模态窗
        let singleModal = (function () {
            let _instance = null;
            class Modal {
                constructor(name) {
                    this.name = name;
                }
                say() {
                    return 'The Leader Is ' + this.name
                }
            }
            return {
                getInstance: (name) => {
                    if (!_instance) {
                        _instance = new Modal(name);
                    }
                    return _instance;
                }
            }
        })();

        let modal = singleModal.getInstance('xiao ming');

        console.log(modal.say())

        let modal2 = singleModal.getInstance('lkjlk');

        console.log(modal2.say())

        console.log(modal === modal2)
    
    // 函数柯里化
    let add = function (x) {
        return function (y) {
            return x + y;
        }
    }

    console.log(add(3)(4));
    
    
    // bind 函数实现原理也用了函数柯里化
    Function.prototype.bind= function (context){
        const self = this;
        const args = Array.prototype.slice.call(arguments);
        return function() {
            return self.apply(context, args.slice(1));
        }
    }
    
    // 反柯里化
    (function(){
        let result = Array.prototype.slice.call(arguments);
        console.log(result); // [1, 2, 3, 'hi']
    })(1,2,3,'hi')
    
    // 函数节流
        function throttle(fn, wait) {
            const _fn = fn;     // 保存需要被延迟的函数引用
            let timer = null;
            let flag = true;  // 是否首次调用
            return function () {
                const args = arguments;
                const self = this;
                if (flag) {
                    _fn.apply(self, args);
                    flag = false;
                    return;
                }

                if (timer) return false; // 如果在定时器上,说明还没执行完,不往下执行

                timer = setTimeout(() => {
                    clearTimeout(timer); // 清空上次的定时器
                    timer = null;   // 销毁变量
                    _fn.apply(self, args)
                }, wait);

            }
        }
        window.onscroll = throttle(function(){    console.log('滚动');},500);
        
        // 惰性加载

        let addEvent = function (ele, type, fn) {
            if (window.addEventListener) {
                addEvent = function (ele, type, fn) {
                    ele.addEventListener(type, fn, false);
                }
            } else if (window.attachEvent) {
                addEvent = function (ele, type, fn) {
                    ele.attachEvent('on', type, function () {
                        fn.call(ele)
                    })
                }
            }

            addEvent(ele, type, fn);
        };

        // 上面的addEvent函数还是个普通函数,还是有分支判断。不过当第一次进入分支条件后,在内部就会重写了addEvent函数下次再进入addEvent函数的时候,函数里就不存在条件判断了

13、手动实现parseInt

不会

14、为什么会有同源策略

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。

15、怎么判断两个对象是否相等

        // 判断对象相等的步骤:  
        // 先判断俩者是不是对象:    
        // 是对象后俩者长度是否一致:    
        // 判断俩个对象的所有key值是否相等相同:  
        // 判断俩个对象的相应的key对应的值是否相同:    
        // 来一个递归判断里面的对象循环1-4步骤:

        function diff(obj1, obj2) {

            var o1 = obj1 instanceof Object;
            var o2 = obj2 instanceof Object;
            if (!o1 || !o2) return obj1 === obj2;

            // 判断对象的key是否都相等
            if (Object.keys(obj1).length !== Object.keys(obj2).length) return false;

            for (var o in obj1) {
                var t1 = obj1[o] instanceof Object;
                var t2 = obj2[o] instanceof Object;
                if (t1 && t2) {
                    return diff(obj1[o], obj2[o])
                } else if (obj1[o] !== obj2[o]) {
                    return false;
                }
            }
            return true;
        }

16、事件模型

  • 事件委托、代理

事件委托还有一个名字叫事件代理, 事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件, 优点:程序中新添加的dom节点也是有事件的,提高性能;Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的

    var oUl = document.getElementById('ul');
    oUl.addEventListener('click', function(e){
        var ev = e || window.event;
        var target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase() === 'li'){
            aliert(target.innerText)
        }
    }, false)
  • 如何让事件先冒泡后捕获
    domObj.addEventListener('click', fn, false)
    // true - 事件句柄在捕获阶段执行
    // false- false- 默认。事件句柄在冒泡阶段执行
    监听两次即可

17、window的onload事件和domcontentloaded

何时触发这两个事件?

1、当 onload 事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了。

2、当 DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash。

18、for...in迭代和for...of有什么区别

for...in遍历的是集合的键(对于数组类型是索引), for...of遍历的是集合的值

19、

20、call apply区别,原生实现bind

 // call,apply,bind 三者用法和区别:角度可为参数、绑定规则(显示绑定和强绑定),运行效率、运行情况。
 // call传递参数为分别传参, apply传递参数为一个数组,bind无需传参
 // 传递参数 不用
Function.prototype.mybind = function (context) {
    let self = this,
        slice = Array.prototype.slice,
        args = slice.call(arguments);
    return function () {
        return self.apply(context, args.slice(1));
    }
}

21、async/await

/**
async/await是一个用同步思维解决异步问题的方案(等结果出来之后,代码才会继续往下执行)
使用tyr/catch来捕获异常
*/
try {
    async fetchSome(){
        const data = await $axios.post();
    }
}catch(e){
    console.error(e)
}

22、立即执行函数和使用场景

// IIFE  隔离作用域,使全局作用域不被污染或和其他类库混淆等
// 避免全局污染
var a = 2;
(function IIFE(global){
    var a = 3;
    console.log(a); // 3
    console.log( global.a ); // 2
})(window)

console.log(a); // 2

// 将window对象的引用传递进去,但将参数命名为global,对于改进代码风格是非常有帮助的。

// 这个模式的另外一个应用场景是解决undefined标识符

23、设计模式(要求说出如何实现,应用,优缺点)/单例模式实现


 // 工厂模式, jq用的说就是工厂模式
    function newObj(name, age) {
        var o = new Object();
        o.name = name;
        o.age = age;
        return o;
    }

    var obj = newObj('xiaoming',12);


    //单例模式:只允许存在一个实例的模式
    // 用途:模态框弹窗的时候,不希望有两个弹窗
    var Instance = (function(){
        var obj;
        return function() {
            if(obj === undefined) obj = new Date();
            return obj;
        }
    })();

    var ibs = Instance();

    // 观察者模式: 又称发布订阅者模式,经典案例:事件监听,一个元素同时监听多个同类型事件,元素对象即为发布者,每一个事件处理函数即为订阅者

    // 策略模式

    // 代理模式

24、iframe的缺点有哪些

一个废弃的标签

25、数组问题

  • 数组去重

 let arr = [1,1,2,3,3,3]
 /* 1 */
    let arr1 = Array.from(new Set(arr));
    // set 是一个不重复的集合, from转换为一个数组
 /* 2 */
    Array.prototype.unique2 = function () {
        return this.reduce(function (pre, cur) {
            pre.indexOf(cur) === -1 && pre.push(cur)
            return pre;
        }, [])
    }
 /* 3 */
    Array.prototype.unique3 = function () {
        var res = [];
            var json = {};
            for (var i = 0; i < this.length; i++) {
                if (!json[this[i]]) {
                    res.push(this[i]);
                    json[this[i]] = 1;
                }
            }
            return res;
    }
    let arr2 = arr.unique3()
  • 数组常用方法
const arrA = [1, 2, 3, 'g']
const arrB = [a, b, c, 99]
属性 描述 改变原数组? 示例
pop() 删除数组的最后一个元素==并返回删除的元素== 改变 arrA.pop() // 1,2,3
push() 向数组的末尾添加一个或多个元素,==并返回==新的长度 改变 arrA.push(4, 5) // 输出 arrA: 1,2,3,g,4,5
shift() 把数组的第一个元素从其中删除,==并返回==第一个元素的值 改变 arrA.shift(); // 从 arrA 删除第一个元素 "1"
unshift() 向数组的开头添加一个或更多元素,==并返回==新的长度 改变 arrA.unshift(-1, 0) // -1, 0, 1, 2, 3, 'g'
concat() 连接两个或更多的数组,并返回结果 不改变 const C = arrA.concat(arrB, [x,y])
join() 把数组中的所有元素转换为一个字符串
通过制定的符号分割
不改变 var res = arrA.join(" and ") // "1 and 2 and 3 and g"
slice() 选取数组的的一部分,并返回一个新数组==包含start,不把包含end== 不改变 const res = arrA.slice(1,3) // res: 2, 3
splice() 从数组中添加或删除元素, 并返回删除的 改变 res = arrA.splice(1,2, 999) // res: 2,3; arrA: 1, 999, 'g'
reverse() 方法用于颠倒数组中元素的顺序 改变 arrA.reverse() // "g", 3, 2, 1
sort() 对数组的元素进行排序 改变 const points = [40,100,1,5,25,10];
points.sort(function(a,b){return b-a}); // 100,40,25,10,5,1
fill() 将一个固定值替换数组的元素 array.fill(value, start, end)
arrA.fill('fi') // arrA: fi,fi,fi,fi
filter() 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素 不改变 array.filter(function(currentValue,index,arr), thisValue)
  • 查找数组重复项

  • 扁平化数组
    const towDimensionalArr = [[1, 2, 3], 4, 5, 6, [[7]], []];

    // 递归实现, for of
    function flatten(arr, result = []) {
        for (const item of arr) {
            if (Array.isArray(item)) flatten(item, result);
            else result.push(item);
        }
        return result;
    }

    console.log(flatten(towDimensionalArr));    // [1,2,3,4,5,6,7]
    
    // 生成器实现
    function* flattenIteor(arr) {
        for (const item of arr) {
            if (Array.isArray(item)) {
                yield* flattenIteor(item)
            }
            else
                yield item
        }
    }
    function flatten2(arr) {
        let result = []
        for (const val of flattenIteor(arr)) {
            result.push(val)
        }
        return result
    }
    console.log(flatten2(towDimensionalArr));

    // resuce 实现
    function flatten3(arr) {
        return arr.reduce(function (flat, toFlatten) {
            return flat.concat(Array.isArray(toFlatten) ? flatten3(toFlatten) : toFlatten)
        }, [])
    }

    console.log(flatten3(towDimensionalArr))
    
  • 按数组中各项和特定值差值排序
// 数组中的排序问题
        const sortArr = [
            { name: 'Edward', age: 21 },
            { name: 'Sharpe', age: 37 },
            { name: 'And', age: 45 },
            { name: 'The', age: -12 },
            { name: 'Magnetic' },
            { name: 'Zeros', age: 37 }
        ]


        sortArr.sort(function (a, b) {
            var nameA = a.name.toUpperCase(); // ignore upper and lowercase
            var nameB = b.name.toUpperCase(); // ignore upper and lowercase
            if (nameA < nameB) {
                return -1;
            }
            if (nameA > nameB) {
                return 1;
            }
            // names must be equal
            return 0;
        });
        
        
        // 选择排序
        const xzArr = [2, 8, 3, 7, 4, 6, 5];

        for (let i = 0; i < xzArr.length - 1; i++) {
            for (let j = i + 1; j < xzArr.length; j++) {
                if (xzArr[i] > xzArr[j]) {
                    let temp = xzArr[i];
                    xzArr[i] = xzArr[j];
                    xzArr[j] = temp;
                }
            }
        }

        console.log(xzArr)

        // 冒泡排序
        // 第一轮找到第一个最大的,放到最后,第二轮找到第二个,以此类推
        const mpArr = [4, 5, 2, 9, 3, 8, 6, 7, 1];
        function mpSort(arr) {
            for (let i = 0; i < arr.length - 1; i++) {
                for (let j = 0; j < arr.length - 1 - i; j++) {
                    let temp = arr[j];
                    if (arr[j] > arr[j + 1]) {
                        arr[j] = arr[j + 1];
                        arr[j + 1] = temp;
                    }
                }
            }
        }
        mpSort(mpArr)
        console.log(mpArr)

        // 快速排序
        function quickSort(arr) {
            if (arr.length <= 1) return arr;

            let centerIndex = Math.floor(arr.length / 2);
            let center = arr.splice(centerIndex, 1)[0];

            let left = [];
            let right = [];

            for (var i = 0; i < arr.length; i++) {
                if (arr[i] < center) left.push(arr[i])
                else right.push(arr[i])
            }

            return quickSort(left).concat([center], quickSort(right));
        }

        var quickArr = [5, 6, 2, 1, 3, 8, 7, 4];

        console.log(quickSort(quickArr))
        

26、BOM属性对象方法

27、服务端渲染
28、垃圾回收机制
29、eventloop

进程和线程
任务队列

30、如何快速让字符串变成已千为精度的数字


ES6

1、声明 let、const
2、解构赋值
3、声明类与继承:class、extend
4、Promise的使用与实现
5、generator(异步编程、yield、next()、await 、async)
6、箭头函数this指向问题、拓展运算符
7、map和set有没有用过,如何实现一个数组去重,map数据结构有什么优点?
8、ES6怎么编译成ES5,css-loader原理,过程
9、ES6转成ES5的常见例子

使用es5实现es6的class

浏览器

1、输入url到展示页面过程发生了什么?

2、重绘与回流

重绘(repaint): 当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少
回流(reflow): 当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。

会触发回流的操作:

* 页面初次渲染
* 浏览器窗口大小改变
* 元素尺寸、位置、内容发生改变
* 元素字体大小变化
* 添加或者删除可见的 dom 元素
* 激活 CSS 伪类(例如::hover)
* 查询某些属性或调用某些方法
* clientWidth、clientHeight、clientTop、clientLeft
* offsetWidth、offsetHeight、offsetTop、offsetLeft
* scrollWidth、scrollHeight、scrollTop、scrollLeft
* getComputedStyle()
* getBoundingClientRect()
* scrollTo()
回流必定触发重绘,重绘不一定触发回流。重绘的开销较小,回流的代价较高。

3、防抖与节流

4、cookies、session、sessionStorage、localStorage

5、浏览器内核


服务端与网络

1、常见状态码
2、缓存

200 From cache和200 ok
400,401,403状态码分别代表什么
浏览器缓存

3、cookie, session, token
4、前端持久化的方式、区别
5、DNS是怎么解析的
6、cdn
7、计算机网络的相关协议
8、http/https/http2.0
9、get post区别
10、ajax、 axios库
11、tcp三次握手,四次挥手流程
12、跨域
13、前端安全XSS、CSRF
14、websocket
15、Http请求中的keep-alive有了解吗
16、网络分层
17、即时通信,除了Ajax和websocket
18、模块化,commonJS,es6,cmd,amd


Vue

1、vue解决了什么问题
2、MVVM的理解
3、如何实现一个自定义组件,不同组件之间如何通信的?
4、nextTick
5、生命周期
6、虚拟dom的原理
7、双向绑定的原理?数据劫持?
8、组件通信

父->子
子->父
非父子组件

9、Proxy 相比于 defineProperty 的优势
10、watch computed区别
11、virtual dom 原理实现
12、vue-router(hash, HTML5 新增的 pushState

单页应用,如何实现其路由功能---路由原理
vue-router如何做用户登录权限等
你在项目中怎么实现路由的嵌套

13、vuex的理解


前端性能优化

页面DOM节点太多,会出现什么问题?如何优化?
如何做性能监测


git

一些基本命令


打包工具webpack

1、打包原理
2、打包插件
3、webpack热更新原理
4、优化构建速度


算法

1、排序算法
2、动态规划,参见背包问题
3、二叉树
4、加油站问题(贪心算法)
5、二分法
6、二叉树遍历
7、单链表反转
8、取1000个数字里面的质数
9、找出数组中和为给定值的两个元素,如:[1, 2, 3, 4, 5]中找出和为6的两个元素。
10、线性顺序存储结构和链式存储结构有什么区别?以及优缺点


移动端

1、自适应
2、pwa
3、移动端手势

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,146评论 0 3
  • 前端开发面试题 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增加。 题目类型: 理论知...
    怡宝丶阅读 2,574评论 0 7
  • 前端开发知识点 HTML&CSS对Web标准的理解、浏览器内核差异、兼容性、hack、CSS基本功:布局、盒子模型...
    Hebborn_hb阅读 843评论 0 1
  • CSS Q: HTML引入CSS的方式有哪些? A: HTML element的style属性,HTML内部sty...
    赵长安啊阅读 594评论 0 7
  • 一、HTML 教程 HTML教程HTML简介HTML编辑器HTML基础HTML元素HTML属性 HTML标题HTM...
    茶茶点阅读 693评论 0 0