Toby

Toby 查看完整档案

深圳编辑  |  填写毕业院校  |  填写所在公司/组织 github.com/maidishike 编辑
编辑

关注公众号 @ 前端30K
https://github.com/maidishike
Attention to Frontend

个人动态

Toby 发布了文章 · 2020-04-05

3月前端资源分享

3月前端资源分享

文章转自:https://github.com/jsfront/mo...

1. Javascript

2.CSS

3.React, Webpack

4. Vue

5. IDE,编辑器,调试等工具类

6. 前端架构及工程化构建工具等,如:Gulp, Fis, Grunt

7. 面试 | 求职

8.PHP

9. Java

可关注公众号,不定期更新哦~

WechatIMGA.jpeg

查看原文

赞 21 收藏 15 评论 0

Toby 发布了文章 · 2020-03-26

2020前端面试,CSS会问你这些

CSS往往是我们前端开发者不太看重的一环,而且现在重构岗也越来越少,不像前几年前端领域还分为js岗和重构岗。注重基础的面试官,在CSS基础回答不上时,印象分就会有所下降。下面整理一些常问到的CSS的知识点,欢迎指正,整理不易,点个赞再走吧。。。

首先我们以一道面试题为考察点

如何实现三栏布局?

三列布局,其中一列宽度自适应,其他两列固定
首先我们来看最终实现效果,对于下方几种实现方式,可以先自己试试,再往下看

  • 首先对样式进行reset
<style>
    * {
        margin: 0;
        padding: 0;
    }
    div {
        min-height: 100px;
    }
    h2, h4 {
        text-align: center;
    }
    .left, .right {
        width: 300px;
        background: rgba(0, 0, 0, 0.3);
    }
    .center {
        background: rgba(0, 0, 0, 0.2);
    }
    .layout {
        margin: 10px 0;
    }
</style>
  • 浮动布局
<div class="layout float">
    <style media="screen">
        .float .left {
            float: left;
        }

        .float .right {
            float: right;
        }
    </style>
    <section class="float-layout">
        <div class="left"></div>
        <div class="right"></div>
        <div class="center">
            <h4>浮动三栏布局</h4>
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
        </div>
    </section>
</div>
  • 绝对定位布局
<div class="layout absolute">
    <style>
        .absolute div {
            position: absolute;
        }

        .absolute .left {
            left: 0;
            width: 300px;
        }

        .absolute .center {
            left: 300px;
            right: 300px;
        }

        .absolute .right {
            right: 0;
            width: 300px;
        }
    </style>
    <section class="absolute-layout">
        <div class="left"></div>
        <div class="center">
            <h4>绝对定位解决方案</h4>
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
        </div>
        <div class="right"></div>
    </section>
</div>
  • flex布局
<div class="layout flexbox">
    <style>
        .flexbox .flex-layout {
            display: flex;
        }

        .flexbox .left {
            width: 300px;
        }

        .flexbox .center {
            flex: 1;
        }

        .flexbox .right {
            width: 300px;
        }
    </style>
    <section class="flex-layout">
        <div class="left"></div>
        <div class="center">
            <h4>flexbox解决方案</h4>
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
        </div>
        <div class="right"></div>
    </section>
</div>
  • table布局
<div class="layout table">
    <style>
        .layout.table .table-layout {
            width: 100%;
            height: 100px;
            display: table;
        }

        .layout.table .table-layout>div {
            display: table-cell;
        }
    </style>
    <section class="table-layout">
        <div class="left"></div>
        <div class="center">
            <h4>表格布局解决方案</h4>
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
        </div>
        <div class="right"></div>
    </section>
</div>
  • grid布局
<div class="layout grid">
    <style>
        .grid .grid-layout {
            width: 100%;
            display: grid;
            grid-template-rows: 100px;
            grid-template-columns: 300px auto 300px;
        }    
        .grid .left {
            width: 300px;
        }
    </style>
    <section class="grid-layout">
        <div class="left"></div>
        <div class="center">
            <h4>网格布局解决方案</h4>
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
            这是三栏布局的浮动解决方案;
        </div>
        <div class="right"></div>
    </section>
</div>

还有许多相似的问题,比如水平垂直居中品字布局的实现方式等,都是同一个原理,主要的考察点:

1、为什么要进行reset?

2、对于float、postion的理解

3、对于flex伸缩盒的掌握

4、对于不常用的table布局有没有掌握

5、对于兼容性不好的grid新型布局是有所了解,我觉得这是一个加分项

为什么要进行样式reset?

各个浏览器的默认展示样式不一致,CSS reset的作用是让各个浏览器的CSS样式有一个统一的基准。
例如暴力的

* {
    margin: 0;
    padding: 0;
}

后来我们也出现了reset.css
Normalize.css比较官方的解决方式,当然我比较推荐Normalize.css。

那如何清除浮动?

一般我们会有两种解决方法:

  • 使用clear属性进行清除浮动;
  • 使父容器形成BFC。例如在父容器加上overflow: hidden属性是我们常用的操作;

什么是BFC?

BFC是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域,也就是说它是一个独立渲染的区域,它规定了内部的Block-level Box去如何进行布局,与外部无关。比如清除浮动,外边距塌陷等都是可以通过BFC来进行解决。
关于定义MDN说的比较清楚了。BFC链接

下列方式会创建块格式化上下文:

  • 根元素(<html>)
  • 浮动元素(元素的 float 不是 none)
  • 绝对定位元素(元素的 position 为 absolute 或 fixed)
  • 行内块元素(元素的 display 为 inline-block)
  • 表格单元格(元素的 display为 table-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)
  • 匿名表格单元格元素(元素的 display为 table、table-row、 table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 inline-table)
  • overflow 值不为 visible 的块元素
  • display 值为 flow-root 的元素
  • contain 值为 layout、content或 paint 的元素
  • 弹性元素(display为 flex 或 inline-flex元素的直接子元素)
  • 网格元素(display为 grid 或 inline-grid 元素的直接子元素)
  • 多列容器(元素的 column-count 或 column-width 不为 auto,包括 column-count 为 1)

column-span 为 all 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中(标准变更,Chrome bug)。

position属性

position的面试点应该就是在absolute的理解吧,position的定位是相对于最近的非static定位祖先元素的便宜,强调一下是非static,而不是只有relative

  • static

该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。

  • relative

该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。

  • absolute

元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。

  • fixed

元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform, perspective 或 filter 属性非 none 时,容器由视口改为该祖先。

  • sticky

元素根据正常文档流进行定位,然后相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。

flex弹性盒前,我们说下什么是盒子模型?

盒子模型包括content、padding、border、margin这几块内容

  • W3C 标准盒模型:width和height只包含content,不包含padding和border。通过box-sizing: content-box来进行设置
  • IE盒子模型:width和height包含content+border+padding。box-sizing: border-box来设置,为了计算方便,似乎更倾向于这种设置方式
<div class="box">
    <style>
        .box div {
            width: 200px;
            margin: 10px auto;
        }
        .content-box {
            box-sizing: content-box;
            width: 100%;
            border: solid rgba(0, 0, 0, 0.2) 10px;
            padding: 5px;
        }
        .border-box {
            box-sizing: border-box;
            width: 100%;
            border: solid rgba(0, 0, 0, 0.3) 10px;
            padding: 5px;
        }
    </style>
    <h4>盒子模型</h4>
    <div class="border-box"></div>
    <div class="content-box"></div>
</div>

flex伸缩盒

伸缩盒可以让响应式设计,表单的对齐,固定布局等可以很简单的实现

用法:

{
    display:flex;
    flex-direction: row | row-reverse | column | column-reverse; 排列方向
    flex-wrap: nowrap | wrap | wrap-reverse;
    align-content: flex-start | flex-end | center | space-between | space-around | stretch; 多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
    align-item: center; 垂直方向对齐方式
    justify-content: center; 水平方向对齐方式
}

想深入了解的同学可以看看
flex布局对性能的影响主要体现在哪方面?

以上是我个人理解这个题目的考察点,下面还有部分常问的CSS知识

如何计算CSS的优先级

浏览器通过优先级来判断哪些属性值与一个元素最为相关,从而在该元素上应用这些属性值。优先级是基于不同种类选择器组成的匹配规则。优先级就是分配给指定的 CSS 声明的一个权重,它由 匹配的选择器中的 每一种选择器类型的 数值 决定。

优先级规则

  • 最近的祖先样式比其他祖先样式优先级高
<div style="color: red">
    <div style="color: blue">
        <div class="son"></div> // blue
    </div>
</div>
  • "直接样式"比"祖先样式"优先级高
<div style="color: red">
    <div class="son" style="color: blue"></div> // blue
</div>
  • 优先级关系:内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器
<div class="content-class" id="content-id" style="color: black"></div> // black

#content-id {
    color: red;
}
.content-class {
    color: blue;
}
div {
    color: grey;
}
  • 内联样式表的权值最高 1000;ID 选择器的权值为 100; class 类选择器的权值为 10;html 标签选择器的权值为 1。这个只是个人理解
<div id="con-id">
    <span class="con-span"></span> // red 
</div>

// CSS
#con-id span {
    color: red; // 值为100 + 1
}
div .con-span {
    color: blue; // 值为 1 + 10
}

inline-block元素之间的间隙如何去除?

因为习惯于父子dom的编写会换行,而且换行符会占用一定的宽度,所以导致元素之间会有间隙
解决:
  • 父元素font-size设置为0;
  • 元素设置float浮动;
  • 使用注释将元素连接起来;
<div class="box parent">
    <div class="children"></div><!--
    --><div class="children"></div><!--
    --><div class="children"></div>
</div>

CSS三角形

三角形的原理是因为border并不是和我们盒模型一样是一个矩形,当设置一个div的border都是5px时,每条border都是一个梯形。
<div class="border"></div>
<style>
   .border{
       width:100px;  
       height: 100px;  
       border: 40px solid;  
       border-color: #ff0000 #0000ff #ff0000 #0000ff;
       margin: 0 auto;
   } 
</style>

当我们把height和width都设置为0

最终我们就可以设置一些border-color: transparent;达到这个效果

<div class="border"></div>
<style>
   .border{
       width: 0;  
       height: 0;  
       border: 40px solid transparent;
       border-bottom: 80px solid #ff0000;
   } 
</style>

最后,希望大家都能够找到自己满意的工作。关注我的公众号:前端30K,后续会持续更新。。。

查看原文

赞 27 收藏 24 评论 0

Toby 发布了文章 · 2020-03-22

2020前端面试,你准备好了吗?

前言

求职季又到了,最近也面试了不少web开发同学,本文也希望对正在找工作的同学有所帮助吧。请大家见谅哈。后面会持续更新,欢迎点赞~~~

职位分析

当我们收到一份面试邀请时,我们可以对jd做分析,看看工作的内容和具体的岗位要求,知己知彼百战百胜。在网上找了一份前端岗位的jd,假设我们接下来就要面试的就是这个岗位吧。

  • 工作中有web和h5两种项目,并且需要对现有系统进行重构或则性能优化的改造,这里可能会涉及到h5开发中遇到的问题,对于前端模块化和组件化的理解,如何进行性能优化等;
  • 需要有扎实的前端开发基础,包括JavaScript,Html5,Css3新特性;
  • 有Node开发经验,例如能够写node代理服务,通过node操作数据库等;
  • 对于Http协议和Web安全要掌握;
  • 有Vue.js,React,Angular中的一个项目开发经验,并且熟悉底层原理实现;
  • 软技能,包括浏览器的工作原理,Github加分项,Git加分项等。

技术栈准备

JavaScript基础

JavaScript基础可以推荐《JavaScript权威指南》、《你不知道的JavaScript》通读一两遍,可以好的梳理所学知识,知识点包括
  • js类型、typeof、instanceof,类型转换
  • 作用域与作用域链、变量提升
  • js原型链、new、继承方式
  • this指向、闭包、垃圾回收机制
  • 事件队列、事件循环
  • DOM对象
  • 事件委托、DOM事件模型
  • 原生ajax

Html5+CSS3

  • html5新特性、语义化
  • 浏览器渲染机制、重绘、重排
  • css盒子模型、flex、动画
  • css样式优先级
  • BFC

Vue

这里只列举MVVM框架中的vue

vue基础

  • vue生命周期、keep-alive
  • computed与watch
  • v-for中key的作用
  • vue组件的通信方式
  • 指令

vue底层原理

  • 双向绑定实现原理
  • v-model的实现
  • nextTick的实现
  • vnode的理解,compiler和patch的过程
  • new Vue后整个的流程
  • keep-alive的实现
  • vuex、vue-router实现原理

Http

  • http特性以及状态码
  • http的三次握手
  • http1.0、http1.1、http2.0的区别
  • http如何实现缓存
  • https的握手过程
  • 输入url后http请求的完整过程
  • get与post请求区别

web安全

  • 理解xss,csrf,ddos攻击原理以及避免方式
  • xss与csrf的区别

前端工程化

  • webpack配置,webpack4.0有哪些优化点
  • webpack如何实现代码分离
  • 如何实现一个webpack loader
  • npm包是如何实现按需引入
  • 从0到1配置工程
  • 前端模块化,CMD、AMD、CommonJS、ESM

前端性能优化

  • 前端性能优化的几种方式
  • 如何做性能优化上报
  • 如何实现一个错误监控系统
  • 什么是同源策略
  • 前后端如何通信
  • 跨域通信的几种方式

算法

  • 排序

简历和自我介绍

简历一般包括个人信息,工作经历,技术栈,项目,github和开源项目等
一般面试官都会针对于你的面试简历来初步和你沟通,所以自己把握一个面试的沟通方向是很重要的,比如你对vue很了解,那可以多和面试官聊聊vue方面的事情,就是突出自己的优点,表现出自己自信的一面。

在回答问题的时候,整体方向要对,而且回答需要更加细致,多说一些细节,是加分项。在遇到自己无法回答的问题,其实可以表现出自己好学的态度,可以向面试官适时的问一些问题。

当遇到面试许多问题没有回答不上的时候,也知道自己可能通不过这次面试,但其实收获还是挺大的,可以向面试官问如何学习,要一些资料啊,加一下微信,我觉得都是可以的。

以上就是总结的面试前的准备考点,可以针对不同的jd分析出不同的面试点,后面会用一些题目和或者资料来说出我对于这些考点的理解。希望大家都能找到理想的工作。

可关注公众号,不定期更新哦~~第二篇正在写作中

企业微信截图_afc9ffed-c525-41eb-9f7d-119f62d121a9.png

查看原文

赞 35 收藏 28 评论 0

Toby 回答了问题 · 2019-08-31

js 如何判断某一对象是否是数组

typeof a === 'object' && a instanceof Array

关注 9 回答 8

Toby 发布了文章 · 2019-08-07

红宝书笔记

红宝书笔记

1.在HTML中使用JavaScript

async:加载外部脚本文件,通知浏览器立即下载,异步执行

defer:脚本可以延迟到文档完全被解析和显示之后在执行

noscript:
浏览器不支持脚本。
浏览器支持脚本,但是脚本被禁用

2.变量、作用域和内存问题

复制变量值

  • 复制基本类型值,这两个变量相互独立,互不影响。
  • 复制引用类型(对象),值引用是一个指针,改变其中一个对象,会影响另一个对象。
function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

在函数重写obj时,这个变量引用就是一个局部对象。而这个对象会在函数执行完毕后立即被销毁。

检测类型

使用typeof检测基本数据类型,但是在检测引用类型的值是,这个操作符的用处不大,因为使用typeof无法知道它是什么类型的对象。为此,ECMAScript提供了 instanceof操作符。

var s = 'test';
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object()
console.log(typeof s); // string
console.log(typeof b); // boolean
console.log(typeof i); // number
console.log(typeof u); // undefined
console.log(typeof n); // object
console.log(typeof o); // object

延长作用域链

try-catch语句中的catch块
with语句

垃圾回收

标记清除

  • 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记

引用计数

  • 当它们被赋值为指向某个对象时,要给它们原本持有的引用所指向的对象的引用计数减1,然后给它们新指向的对象的引用计数加1。当它们的生命期结束的时候,要给它们所指向的对象的引用计数减1,当引用计数为0时,则可以将其占用的内存空间进行回收

3.引用类型

Array类型

检测数组

value instanceof Array
Array.isArray(value)

栈方法(后进先出)

  • push:将参数逐个添加到数据末尾
  • pop:从数组末尾移除最后一项

队列方法(先进先出)

  • shift:删除数组的第一项并返回该项
  • unshift:向数组前添加任意个项并返回新数组的长度

重排序方法

  • reverse:反转数组
  • sort:按升序排列数组

操作方法

  • concat:将参数添加到数组的末尾,并返回新的数组
  • slice:基于当前数组中的一或多个项创建一个新数组,slice()方法可以接受一或者两个参数,即要返回项的起始和结束为止
var colors = ['red', 'green', 'blue', 'yellow', 'purple'];
var colors2 = colors.slice(1)
var colors3 = colors.slice(4)
console.log(colors2); // ["green", "blue", "yellow", "purple"]
console.log(colors3); // ["purple"]
  • splice:返回新的数组,能够删除、插入和替换多个项
var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1); // 删除第一项
alert(colors); // green,blue
alert(removed); // red,返回的数组中只包含一项
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置1 开始插入两项
alert(colors); // green,yellow,orange,blue
alert(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项
alert(colors); // green,red,purple,orange,blue
alert(removed); // yellow,返回的数组中只包含一项

位置方法

  • indexOf:从数组开头开始向后查找位置
  • lastIndexOf:从数组末尾开始向前查找

迭代方法

  • every(): 对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
  • filter(): 对数组中的每一项运行给定函数,返回该函数会返回true 的项组成的数组。
  • forEach(): 对数组中的每一项运行给定函数。这个方法没有返回值。
  • map(): 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
  • some(): 对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。

缩小方法

  • reduce():遍历数组所有项,并返回最终的值,从第一项开始,逐个遍历到最后
  • reduceRight():从最后一项开始,逐个遍历到第一项
var values = [1, 2, 3, 4, 5];
var sum = values.reduce((prev, cur, index, array) => {
    return prev + cur;
});
console.log(sum); // 15

Function类型

函数内部属性

  • 函数内部有两个特殊的对象:argumens和this

属性和方法

每个函数都包含两个属性

  • length: 表示函数希望接收的命名参数的个数
  • prototype: 保存实例方法

每个函数都包含两个非继承而来的方法

  • call()和apply()这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值
  • apply()接收两个参数:一个是在其中运行的函数作用域,另一个是参数数组
  • call()接收的参数,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数
  • bind()方法会创建一个实例,其this值会被绑定到传给bind()函数的值
function sum (num1, num2) {
    return num1 + num2;
}
function callSum1 (num1, num2) {
    return sum.apply(this, [num1, num2]);
}
function callSum2 (num1, num2) {
    return sum.call(this, num1, num2);
}
callSum1(10, 10); // 20
callSum2(10, 10); // 20
var callSum3 = sum.bind(null)
callSum3(10, 10) // 20

单体内置对象

Global对象

  • encodeURI()和encodeURIComponet()方法可以对URI进行编码,以便发送给浏览器

encodeURI()编码后的结果是除了空格之外的其他字符都原封不动,只有空格被替换成了%20,对应decodeURI()方法

  • encodeURIComponet()方法则会使用对应的编码替换所有非字母数字字符,这也正式可以对整个URL使用encodeURI(),而只能对附加在现有URL后面的字符串使用encodeURIComponet()的原因所在。对应decodeURIComponet()方法

4.面向对象的程序设计

理解对象

属性类型

ECMAScript中有两种属性:数据属性和访问器属性

数据属性

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true
  • [[Enumerable]]:表示能否通过for-in循环返回属性。默认值为true
  • [[Writable]]:表示能否修改属性的值。默认值为true
  • [[Value]]:包含这个属性的数据值,默认值为undefined
要修改属性默认的特性,必须使用Object.defineProperty()方法。这个方法接收三个参数:属性所在对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:configurabel、enumerable、writable、和value。设置其中的一个或多个值。
var person = {}
Object.defineProperty(person, 'name', {
    writable: false,
    configurable: false,
    value: 'Nicholas'
});
console.log(person.name); // Nicholas
person.name = 'Greg';
console.log(person.name); // Nicholas
delete person.name
console.log(person.name); // Nicholas

Object.defineProperty()方法会对configurable为false的属性修改做限制

访问器属性

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。默认值为true
  • [[Enumerable]]:表示能否通过for-in循环返回属性。默认值为true
  • [[Get]]:在读取属性时调用的函数。默认值为undefined
  • [[Set]]:在写入属性时调用的函数。默认值为undefined

访问器属性不能直接定义,必须使用Object.defineProperty()来定义

var book = {
    _year: 2004,
    edition: 1
};
Object.defineProperty(book, 'year', {
    get: function() {
        return this._year
    },
    set: function(newValue) {
        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004
        }
    }
});
book.year = 2005;
console.log(book.edition); // 2

定义多个属性

ECMAScript5定义了一个Object.defineProperties()方法。利用这个方法可以通过描述符一次定义多个属性。这个方法接收两个对象参数。
var book = {};
Object.defineProperties(book, {
    _year: {
        value: 2004
    },
    edition: {
        value: 1
    },
    year: {
        get: function() {
            return this._year
        },
        set: function(newValue) {
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newValue - 2004
            }
        }
    }
});

读取属性的特性

使用Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符
var descriptor = Object.getOwnPropertyDescriptor(book, '_year')
console.log(descriptor.value); // 2004
console.log(descriptor.configurable); // false

创建对象

工厂模式

function createPerson (name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () {
        console.log(this.name);
    };
    return o;
}
var person1 = createPerson('Nicholas', 29, 'Software Engineer');
var person2 = createPerson('Greg', 27, 'Doctor');

构造函数模式

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name);
    };
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');

原型模式

理解原型对象

function Person () {}
Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var person1 = new Person();
var person2 = new Person();

在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向一个prototype属性所在函数的指针。例如,Person.prototype.constructor指向Person

我们可以通过isPrototypeof()方法来确定对象之间是否存在原型关系。从本质上讲,如果[[Prototype]]指向调用isPrototypeof()方法的对象(Person.prototye),那么这个方法就返回true。

console.log(Person.prototype.isPrototypeOf(person1)); // true
console.log(Person.prototype.isPrototypeOf(person2)); // true

ECMAScript5增加了一个新方法,叫Object.getPrototypeOf(),在所有支持的实现中,这个方法返回[[Prototype]]的值。例如:

console.log(Object.getPrototypeOf(person1) === Person.prototype); // true

虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。

function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function() {
    alert(this.name);
};
var person1 = new Person();
person1.name = "Greg";
console.log(person1.name); //"Greg" — 来自实例
delete person1.name;
console.log(person1.name); //"Nicholas" — 来自原型

通过delete操作符删除实例的属性,就恢复了对原型中name属性的连接。因此接下来再调用person1.name是,就返回了原型中name属性的值了。
Object.hasOwnProperty()方法可以检测一个属性是否存在于实例中,还是存在于原型中。

原型与in操作符

  • in操作符只要通过对象能够访问到属性就返回true,Object.hasOwnProperty()只在属性存在于实例中才返回true,因此只要in操作符返回true而Object.hasOwnProperty()返回false,就可以确定属性是原型中的属性。
function hasPrototypeProperty (object, name) {
    if (name in object) {
         return object.hasOwnProperty(name) // true:属性在实例中,false:属性在对象中
    } else {
        console.log('没有该属性');
    }
}
  • 要取得对象上所有可枚举的实例属性,可以使用ECMAScript5的Object.keys()方法
function Person () {}
Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function () {
    console.log(this.name);
};
Object.keys(Person.prototype); //  ["name", "age", "job", "sayName"]
var person1 = new Person();
person1.name = 'Rob';
person1.age = 31;
Object.keys(person1); // ["name", "age"]
  • Object.getOwnPropertyNames()可以得到所有的属性,无论它是否可枚举
Object.getOwnPropertyNames(Person.prototype); //  ["constructor", "name", "age", "job", "sayName"]

更简单的原型方法

function Person () {}
Person.prototype = {
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}

我们将Person.prototype设置为一个新的对象,本质上是完全重写了默认的prototype对象。但是这样有一个例外,constructor属性不再指向Person了,而是指向Object。所以我们需要将他的constructor属性设置成Person

function Person () {}
Person.prototype = {
    constructor: Person,
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}

但是这种方式重设constructor属性会导致它的[[Enumerable]]的特性被设置为true,默认情况下,原生的constructor属性是不可枚举的。

function Person () {}
Person.prototype = {
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}
Object.defineProperty(Person.prototype, 'constructor', {
    enumerable: false,
    value: Person
});

原型的动态性

重写整个原型对象会切断构造函数与最初原型之间的联系。记住:实例中的指针仅指向原型,而不指向构造函数

function Person () {}
var friend = new Person();
Person.prototype = {
    constructor: Person,
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}
friend.sayName(); // error

原生对象的原型

原型模式的重要性不仅体现在创建自定义类型方面,就连所有的原生的引用类型,都是采用这种模式创建的。所有原生引用类型(Object、Array、String,等等)都在其构造函数的原型上定义了方法。

原型对象的问题
原型模式的所有实例在默认情况下都将取得相同的属性值,最大的问题是其共享的本性所导致的。

function Person () {}
Person.prototype = {
    constructor: Person,
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    friends: ['Shelby', 'Court'],
    sayName: function () {
        console.log(this.name);
    }
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push('Van');
console.log(person1.friends); // ["Shelby", "Court", "Van"]
console.log(person2.friends); //  ["Shelby", "Court", "Van"]

组合使用构造函数和原型模式

创建自定义类型的最常见的方式,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。

每个实例都会有自己的一份实例属性的副本,但同事又共享着对方法的引用,最大的节省了内存

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['Shelby', 'Court'];
}
Person.prototype = {
    constructor: Person,
    sayName: function () {
        console.log(this.name);
    };
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');
person1.friends.push('Van');
console.log(person1.friends); // ["Shelby", "Court", "Van"]
console.log(person2.friends); //  ["Shelby", "Court"]

动态原型模式
通过在构造函数中初始化原型(仅在必要的情况下),又保持同时使用构造函数和原型模式的优点。换句话说,可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['Shelby', 'Court'];
    if (typeof this.sayName === 'function') {
        Person.prototype.sayName = function () {
            console.log(this.name);
        };
    }
}

继承

原型链

构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
function SuperType () {
    this.property = true;
}
SuperType.prototype.getSuperValue = function () {
    return this.property
};
function SubType () {
    this.subproperty = false
}
// 继承了SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
    return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue()); // true

别忘记默认原型

所用引用类型默认都继承Object,而这个继承也是通过原型链实现的。所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。

确定原型与实例的关系

instanceof操作符

console.log(instance instanceof Object); // true
console.log(instance instanceof SuperType); // true
console.log(instance instanceof SubType); // true

isPrototypeOf()方法,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型

console.log(Object.isPrototypeOf(instance)); // true
console.log(SuperType.isPrototypeOf(instance)); // true
console.log(SubType.isPrototypeOf(instance)); // true

谨慎的定义方法

子类型有时需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎样,给原型添加方法的代码一定要放在替换原型语句之后。

原型链的问题

  • 通过原型来实现继承时,原型实际上会变成另一个类型的实例,包含引用类型值的原型属性会被所有实例共享。
  • 在创建子类型的实例时,不能向超类型的构造函数中传递参数。

借用构造函数

在解决原型中包含引用类型值所带来问题的过程中,开始使用借用构造函数的技术。即在子类型构造函数的内部调用超类型构造函数

function SuperType () {
    this.colors = ['red', 'blue', 'green'];
}
function SubType () {
    // 继承了SuperType
    SuperType.call(this);
    // SuperType.apply(this);
}
var instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // ["red", "blue", "green", "black"]
var instance2 = new SubType();
console.log(instance2.colors); // ["red", "blue", "green"]

传递参数

相对于原型链而言,借用构造函数有一个很大的优势,既可以在子类型构造函数中向超类型构造函数传递参数

function SuperType (name) {
    this.name = name;
}
function SubType () {
    // 继承了SuperType
    SuperType.call(this, 'Nicholas');
    this.age = 29
}
var instance = new SubType();
console.log(instance.name); // 'Nicholas'
console.log(instance.age); // 29

借用构造函数的问题

方法都在构造函数中定义,因为函数复用就无从谈起

组合继承

既能通过在原型上定义方法实现了函数复用,又能保证每个实例都有它自己的属性

function SuperType (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
};
function SubType (name, age) {
    // 继承了SuperType
    SuperType.call(this, name);
    this.age = age
}
// 继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function () {
    console.log(this.age);
};
var instance1 = new SubType('Nicholas', 29);
instance1.colors.push('black');
console.log(instance1.colors); // ["red", "blue", "green", "black"]
instance1.sayName(); // 'Nicholas'
instance1.sayAge(); // 29
var instance2 = new SubType('Greg', 27);
console.log(instance2.colors); // ["red", "blue", "green"]
instance2.sayName(); // 'Greg'
instance2.sayAge(); // 27

5.函数表达式

定义函数的方式有两种:一种是函数声明,另一种是函数表达式。
函数声明的特征是函数声明提升,意思是在执行代码之前会先读取函数声明。

闭包

函数作用域链

当某个函数第一次被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋值给一个特殊的内部属性(即[[Scope]])。然后,使用this.arguments和其他命名参数的值来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象始终处于第三位,......直至作为作用域链终点的全局执行环境。

闭包与变量

// i 最终为10
function createFunctions () {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = function () {
            return i
        }
    }
    return result;
}
// i 为 0,1,2...9
function createFunctions () {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = function (num) {
            return function (arguments) {
                return num;
            };
        }(i)
    }
    return result;
}

关于this对象

this对象是在运行中基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过匿名函数的执行环境具有全局性,因此其this对象通常指向window。当然,再通过call()和apply()改变执行函数执行环境的情况下,this就会指向其他对象

var name = 'The Window';
var object = {
    name: 'My Object',
    getNameFunc: function () {
        return function () {
            return this.name
        }
    }
}
console.log(object.getNameFunc()()); // 'The Window'

模仿块级作用域

匿名函数可以用来模仿块级作用域并避免这个问题。用块级作用域(通常称为私有作用域)的匿名函数的语法如下所示。

(function(){

})()

私有变量

function Person(name) {
    this.getName = function() {
        retirm name;
    }
    this.setName = function(value) {
        name = value
    }
}
var person = new Person('Nicholas');
console.log(person.getName()); // 'Nicholas'
person.setName('Greg');
console.log(person.getName()); // 'Greg'

以上代码的构造函数中定义了两个特权方法:getName()和setName()。这两个方法都可以在构造函数外部使用,而且都有权访问私有变量name。但在Person构造函数外部,没有任何方法访问name。由于这两个方法是在构造函数内部定义的,它们作为闭包能够通过作用域链访问name。
静态私有变量

6.BOM

window对象

全局作用域

抛开全局变量会成为window对象的属性不谈,定义全局变量与在window对象上直接定义属相还是有一点差别:全局变量不能通过delete属性操作符删除,而直接在window对象上的定义的属性可以。

var age = 29;
window.color = 'red';
delete window.age; // 不会报错
delete window.color // 不会报错 返回true
var newValue = oldValue; // 会抛出错误,因为oldValue未定义
var newValue = window.oldValue; // 不会报错,因为这是一次属性查询

窗口关系及框架

了解frameset和frame
窗口位置

下列代码可以跨浏览器取得窗口左边和上边的位置
Opera支持screenX,screenY。其他浏览器支持screenLeft,screenTop

var leftPops = (typeof window.screenLeft === 'number') ? window.screenLeft : window.screenX;
var topPops = (typeof window.screenTop === 'number') ? window.screenLeft : window.screenY;

localtion对象

locatoin对象的属性

  • replace方法替换当前浏览窗口,reload方法刷新浏览器窗口

navigator对象
识别浏览器的信息

7.DOM

DOM是针对HTML和XML文档的一个API。DOM描绘了一个层次的节点树。

节点层次

NODE类型

每个节点都有一个nodeType属性,用于表明节点的类型。

  • Node.ELEMENT_NODE(1)
  • Node.ATTRIBUTE_NODE(2)
  • Node.TEXT_NODE(3)
  • Node.CDATA_SECTION_NODE(4)
  • Node.ENTITY_REFERENCE_NODE(5)
  • Node.ENTITY_NODE(6)
  • Node.PROCESSING_INSTRUCTION_NODE(7)
  • Node.COMMENT_NODE(8)
  • Node.DOCUMENT_NODE(9)
  • Node.DOCUMENT_TYPE_NODE(10)
  • Node.DOCUMENT_FRAGMENT_NODE(11)
  • Node.NOTATION_NODE(12)
if (someNode.nodeType == 1) {
    console.log('Node is an element');
}

nodeName和nodeValue属性

nodeName返回节点的标签名,如p,div,span等
nodeValue的值始终是null

节点关系

操作节点

  • appendChild():向childNodes列表的末尾添加一个节点
  • insertBefore():向childNodes列表某个特定位置添加一个节点。该方法接收两个参数:要插入的节点和作为参照的节点,并返回要插入的节点,如果参照节点是null,则和appendChild()执行相同的操作
  • replaceChild():替换节点。接收要插入的节点和要替换的节点两个参数。要替换的节点将被返回并从文档书中被移除。
  • removeChild():移除节点。接收一个参数,就是需要移除的节点
  • cloneNode():创建调用这个方法节点的一个完全相同的副本。接受一个布尔值参数,表示是否执行深复制
  • normalize()
  • createElement():创建元素
  • createTextNode():创建文本节点
  • createComment():创建注释节点

8.DOM拓展

选择符API

  • getElementById()方法:通过id获取
  • getElementsByName()方法:通过name属性,一般使用它获取表单元素,少用
  • getElementsByTagName()方法:通过标签名获取元素
  • getElementsByClassName()方法:通过类名获取元素
  • querySelector()方法:接收一个CSS选择符,返回与该模式匹配的第一个元素,没有则返回null
  • querySelectorAll()方法:接收一个CSS选择符,返回一个NodeList实例
  • macthsSelector()方法:接收一个CSS选择符,如果调用元素与该选择符匹配,返回true否则返回false

9.事件

事件流

事件冒泡
IE的事件流叫做事件冒泡,即事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点
事件捕获
Netscape的事件流叫事件捕获,即不太具体的节点应该更早接收事件,而最具体的节点应该最后接收事件
DOM事件流
包括三个阶段:事件捕获阶段。处于目标阶段和事件冒泡阶段

事件处理程序

DOM2级时间处理程序
addEventListener
removeEventListener
定义了两个方法用于处理指定和删除事件处理程序的操作。所有的DOM节点中都包含这两个方法,接受三个参数:事件名、事件处理程序和布尔值。最后这个布尔值如果是true,表示在捕获阶段调用事件处理程序;false表示在冒泡阶段调用事件处理程序,默认是false。
通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除。如果通过addEventListener()添加的匿名函数将无法移除。传入的函数要相同,否则无法移除
attachEvent
detachEvent
这两个方法接受两个参数:事件名(带on)和事件处理函数。
var btn = document.getElementById('myBtn');
var handler = function(){ console.log('clicked') };
btn.attachEvent('onclick', handler);
btn.detachEvent('onclick', handler); // 有效

事件对象

DOM的事件对象

事件类型

UI事件
load:当页面完全加载后在window上面触发,img图片加载完
unload:当页面完全卸载
abort:当用户停止下载过程
error:当发生JavaScript错误时在window触发
select:当用户选择文本框中的一个或者多个触发
resize:当窗口大小变化是触发
scroll:用户滚动时触发

内存和性能
事件委托利用了时间冒泡,指定一个事件处理程序,就可以管理某一个类型的所有事件

HTML5脚本编程

跨文档消息传递
核心方法是postMessage()方法,接受两个参数:一条消息和一个表示消息接收方来自哪个域的字符串。
// 注意:所有支持XDM的浏览器也支持iframe的contentWindow属性

var iframeWindow = document.getElementById('myframe').contentWindow;
iframeWindow.postMessage('A secret', 'http://www.wrox.com');

高级技巧

高级函数
安全的类型检测

function isArray (value) {
    return Object.prototype.toString.call(value) === '[object Array]';
}
function isFunction (value) {
    return Object.prototype.toString.call(value) === '[object Function]';
}
function isRegExp (value) {
    return Object.prototype.toString.call(value) === '[object RegExp]';
}

作用域安全的构造函数
防止this指向window对象

function Person (name, age, job) {
    if (this instanceof Person) {
        this.name = name;
        this.age = age;
        this.job = job;
    } else {
        return new Person(name, age, jon);
    }
}

惰性载入函数
function createXHR(){
    if (typeof XMLHttpRequest != "undefined"){
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject != "undefined"){
        if (typeof arguments.callee.activeXString != "string"){
            var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],
                i,len;
            for (i=0,len=versions.length; i < len; i++){
                try {
                    new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    break;
                } catch (ex){
                    //跳过
                }
            }
        }
        return new ActiveXObject(arguments.callee.activeXString);
    } else {
        throw new Error("No XHR object available.");
    }
}
第一种实现方法:
function createXHR () {
    if (typeof XMLHttpRequest != 'undefined') {
        createXHR = function () {
            return new XMLHttpRequest();
        };
    } else if (typeof ActiveXObjext != 'undefined') {
        createXHR = function () {
            if (typeof arguments.callee.activeXString != 'string') {
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],
                    i,len;
                for (i = 0, len = versions.length; i < len; i++) {
                    try {
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    } catch (e) {
                        // skip
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    } else {
        createXHR = function () {
            throw new Error('No XHR object available.');
        }
    }
    return createXHR();
}

第二种改法:
var createXHR = (function () {
    if (typeof XMLHttpRequest != 'undefined') {
        return function () {
            return new XMLHttpRequest();
        };
    } else if (typeof ActiveXObjext != 'undefined') {
        return function () {
            if (typeof arguments.callee.activeXString != 'string') {
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],
                    i,len;
                for (i = 0, len = versions.length; i < len; i++) {
                    try {
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    } catch (e) {
                        // skip
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    } else {
        return function () {
            throw new Error('No XHR object available.');
        }
    }
})();

函数绑定

bind函数:
function bind (fn, context) {
    return function () {
        fn.call(context, arguments)
    }
}
函数柯里化
function curry (fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments)
        var finalArgs = args.concat(innerArgs)
        return fn.apply(null, finalArgs);
    }
}
function bind (fn, context) {
    var args = Array.prototype.slice.call(arguments, 2);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments)
        var finalArgs = args.concat(innerArgs)
        return fn.apply(context, finalArgs);
    }
}
查看原文

赞 7 收藏 3 评论 0

Toby 回答了问题 · 2019-08-05

解决elementUI 树节点的选择,我怎么点击checkbox来得到数据

建议看下官网文档。有很详细的方法,可以试试check-change这个方法吧

关注 3 回答 2

Toby 回答了问题 · 2019-06-08

解决npm是否--save的使用场景是怎样?

--save一般是在env = production时用到的,也就是项目在生产环境中运行必备的模块。例如express,koa

关注 3 回答 2

Toby 回答了问题 · 2019-06-04

解决css如何根据子元素class写样式?

这个问题应该换个思路吧,挺无聊的问题了

关注 6 回答 5

Toby 收藏了文章 · 2018-02-23

面试的信心来源于过硬的基础

在过去的一年很多人不满于公司没有福利、人际关系不好相处、没有发展前途的境遇等等,想着在开年来换一份工作来重新开始自己,那么 你 准备好了吗?

下面是本人整理的一份面试材料,本想自己用的,但是新年第一天 公司突然给了我个惊喜,涨工资了!!!

1、 viewport

    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
    // width    设置viewport宽度,为一个正整数,或字符串‘device-width’
    // device-width  设备宽度
    // height   设置viewport高度,一般设置了宽度,会自动解析出高度,可以不用设置
    // initial-scale    默认缩放比例(初始缩放比例),为一个数字,可以带小数
    // minimum-scale    允许用户最小缩放比例,为一个数字,可以带小数
    // maximum-scale    允许用户最大缩放比例,为一个数字,可以带小数
    // user-scalable    是否允许手动缩放

延伸 提问

怎样处理 移动端 1px 被 渲染成 2px 问题


    1 局部处理
        meta标签中的 viewport属性 ,initial-scale 设置为 1 
        rem 按照设计稿标准走,外加利用transfrome 的scale(0.5) 缩小一倍即可;
    2 全局处理
        meta标签中的 viewport属性 ,initial-scale 设置为 0.5
        rem 按照设计稿标准走即可

2、跨域的几种方式

首先了解下浏览器的同源策略
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

那么怎样解决跨域问题的呢?

    1 通过jsonp跨域
        1.)原生实现:
         <script>
            var script = document.createElement('script');
            script.type = 'text/javascript';
        
            // 传参并指定回调执行函数为onBack
            script.src = 'http://www.....:8080/login?user=admin&callback=onBack';
            document.head.appendChild(script);
        
            // 回调执行函数
            function onBack(res) {
                alert(JSON.stringify(res));
            }
         </script>
    2、 document.domain + iframe跨域  
        此方案仅限主域相同,子域不同的跨域应用场景。
        1.)父窗口:(http://www.domain.com/a.html)

            <iframe id="iframe" data-original="http://child.domain.com/b.html"></iframe>
            <script>
                document.domain = 'domain.com';
                var user = 'admin';
            </script>
            2.)子窗口:(http://child.domain.com/b.html)
            
            <script>
                document.domain = 'domain.com';
                // 获取父窗口中变量
                alert('get js data from parent ---> ' + window.parent.user);
            </script>

        弊端:请看下面渲染加载优化

    3、 nginx代理跨域
    4、 nodejs中间件代理跨域
    5、 后端在头部信息里面设置安全域名
    
    更多跨域的具体内容请看  https://segmentfault.com/a/1190000011145364
    

3、 渲染优化

    1.禁止使用iframe(阻塞父文档onload事件);
        *iframe会阻塞主页面的Onload事件;
        *搜索引擎的检索程序无法解读这种页面,不利于SEO;
        *iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。

        使用iframe之前需要考虑这两个缺点。如果需要使用iframe,最好是通过javascript
        动态给iframe添加src属性值,这样可以绕开以上两个问题。

    2.禁止使用gif图片实现loading效果(降低CPU消耗,提升渲染性能);
    3、使用CSS3代码代替JS动画(尽可能避免重绘重排以及回流);
    4、对于一些小图标,可以使用base64位编码,以减少网络请求。但不建议大图使用,比较耗费CPU;
            小图标优势在于:
                1.减少HTTP请求;
                2.避免文件跨域;
                3.修改及时生效;

    5、页面头部的<style></style> 会阻塞页面;(因为 Renderer进程中 JS线程和渲染线程是互斥的);
    6、页面头部<script</script> 会阻塞页面;(因为 Renderer进程中 JS线程和渲染线程是互斥的);
    7、页面中空的 href 和 src 会阻塞页面其他资源的加载 (阻塞下载进程);
    
    8、网页Gzip,CDN托管,data缓存 ,图片服务器;
    9、前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
    10、用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
    11、当需要设置的样式很多时设置className而不是直接操作style。
    12、少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
    13、避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
    14、图片预加载,将样式表放在顶部,将脚本放在底部  加上时间戳。

    15、 避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div+css布局慢。
        对普通的网站有一个统一的思路,就是尽量向前端优化、减少数据库操作、减少磁盘IO。
            向前端优化指的是,在不影响功能和体验的情况下,能在浏览器执行的不要在服务端执行,
            能在缓存服务器上直接返回的不要到应用服务器,程序能直接取得的结果不要到外部取得,
            本机内能取得的数据不要到远程取,内存能取到的不要到磁盘取,缓存中有的不要去数据库查询。
            减少数据库操作指减少更新次数、缓存结果减少查询次数、将数据库执行的操作尽可能的让你的程序完成(例如join查询),
            减少磁盘IO指尽量不使用文件系统作为缓存、减少读写文件次数等。程序优化永远要优化慢的部分,换语言是无法“优化”的。
            

4、事件的各个阶段

1:捕获阶段 ---> 2:目标阶段 ---> 3:冒泡阶段
document   ---> target目标 ----> document

由此,addEventListener的第三个参数设置为true和false的区别已经非常清晰了:

true表示该元素在事件的“捕获阶段”(由外往内传递时)响应事件;

false表示该元素在事件的“冒泡阶段”(由内向外传递时)响应事件。

5、let var const

let 允许你声明一个作用域被限制在块级中的变量、语句或者表达式
    let绑定不受变量提升的约束,这意味着let声明不会被提升到当前
    该变量处于从块开始到初始化处理的“暂存死区”。

var 声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的
    由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明
    
const 声明创建一个值的只读引用 (即指针)
    这里就要介绍下 JS 常用类型 
    String、Number、Boolean、Array、Object、Null、Undefined
    其中基本类型 有 Undefined、Null、Boolean、Number、String,保存在栈中;
    复合类型 有 Array、Object ,保存在堆中;
    
    基本数据当值发生改变时,那么其对应的指针也将发生改变,故造成 const申明基本数据类型时,
    再将其值改变时,将会造成报错, 例如 const a = 3 ; a = 5 时 将会报错;
    但是如果是复合类型时,如果只改变复合类型的其中某个Value项时, 将还是正常使用;

6、箭头函数

    语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数,并且它们不能用作构造函数。
    

7、快速的让一个数组乱序

    var arr = [1,2,3,4,5,6,7,8,9,10];
    arr.sort(function(){
        return Math.random() - 0.5;
    })
    console.log(arr);

此处解释:(语言组织能力不足,请勿吐槽)

首先: 当return 的值

    小于 0 ,那么 a 会被排列到 b 之前;
    等于 0 , a 和 b 的相对位置不变;
    大于 0 , b 会被排列到 a 之前;

这里你会 发现起始 的时候数组是正序排列,每当进行一次排列的时候, 都会先随机一个随机数 
(注意这里的每一次排列 指 每一个红框指一次排列, 共9次排列 , 一次排列中可能存在多次比较);

当一次排列的 随机数大于0.5 时 将会进行第二次比较, 当第二次随机数 仍然大于0.5 时 ,
    将会再 进行一次比较, 直到 随机数大于0.5 或者排列到第一位;

当一次排列的 随机数 小于0.5时 当前比较的两项 索引将不会改变 ,继续下一次 的排列;

8、字体font-family

    @ 宋体      SimSun
    @ 黑体      SimHei
    @ 微信雅黑   Microsoft Yahei
    @ 微软正黑体 Microsoft JhengHei
    @ 新宋体    NSimSun
    @ 新细明体  MingLiU
    @ 细明体    MingLiU
    @ 标楷体    DFKai-SB
    @ 仿宋     FangSong
    @ 楷体     KaiTi
    @ 仿宋_GB2312  FangSong_GB2312
    @ 楷体_GB2312  KaiTi_GB2312  
    @
    @ 说明:中文字体多数使用宋体、雅黑,英文用Helvetica
    
    body { font-family: Microsoft Yahei,SimSun,Helvetica; } 

9、可能用到的meta标签

    
    <!-- 设置缩放 -->
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />
    <!-- 可隐藏地址栏,仅针对IOS的Safari(注:IOS7.0版本以后,safari上已看不到效果) -->
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <!-- 仅针对IOS的Safari顶端状态条的样式(可选default/black/black-translucent ) -->
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <!-- IOS中禁用将数字识别为电话号码/忽略Android平台中对邮箱地址的识别 -->
    <meta name="format-detection"content="telephone=no, email=no" />

    其他meta标签
    <!-- 启用360浏览器的极速模式(webkit) -->
    <meta name="renderer" content="webkit">
    <!-- 避免IE使用兼容模式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->
    <meta name="HandheldFriendly" content="true">
    <!-- 微软的老式浏览器 -->
    <meta name="MobileOptimized" content="320">
    <!-- uc强制竖屏 -->
    <meta name="screen-orientation" content="portrait">
    <!-- QQ强制竖屏 -->
    <meta name="x5-orientation" content="portrait">
    <!-- UC强制全屏 -->
    <meta name="full-screen" content="yes">
    <!-- QQ强制全屏 -->
    <meta name="x5-fullscreen" content="true">
    <!-- UC应用模式 -->
    <meta name="browsermode" content="application">
    <!-- QQ应用模式 -->
    <meta name="x5-page-mode" content="app">
    <!-- windows phone 点击无高光 -->
    <meta name="msapplication-tap-highlight" content="no">

10、消除transition闪屏

    .css {
        -webkit-transform-style: preserve-3d;
        -webkit-backface-visibility: hidden;
        -webkit-perspective: 1000;
    }
    过渡动画(在没有启动硬件加速的情况下)会出现抖动的现象, 以上的 解决方案只是改变 视角 来启动硬件加速的一种方式;
    启动硬件加速的 另外一种方式: 
        .css {
            -webkit-transform: translate3d(0,0,0);
            -moz-transform: translate3d(0,0,0);
            -ms-transform: translate3d(0,0,0);
            transform: translate3d(0,0,0);
        }
    
    启动硬件加速
    最常用的方式:translate3d、translateZ、transform

    opacity属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态)

    will-chang属性(这个比较偏僻),一般配合opacity与translate使用(而且经测试,除了上述可以引发硬件加速的属性外,
    其它属性并不会变成复合层),

    弊端: 硬件加速会导致 CPU性能占用量过大,电池电量消耗加大 ;因此 尽量避免泛滥使用硬件加速。

11、android 4.x bug

    1.三星 Galaxy S4中自带浏览器不支持border-radius缩写
    2.同时设置border-radius和背景色的时候,背景色会溢出到圆角以外部分
    3.部分手机(如三星),a链接支持鼠标:visited事件,也就是说链接访问后文字变为紫色
    4.android无法同时播放多音频audio
    5.oppo 的border-radius 会失效

12、JS 判断设备来源

    function deviceType(){
        var ua = navigator.userAgent;
        var agent = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];    
        for(var i=0; i<len,len = agent.length; i++){
            if(ua.indexOf(agent[i])>0){         
                break;
            }
        }
    }
    deviceType();
    window.addEventListener('resize', function(){
        deviceType();
    })


    微信的 有些不太一样
    function isWeixin(){
        var ua = navigator.userAgent.toLowerCase();
        if(ua.match(/MicroMessenger/i)=='micromessenger'){
            return true;
        }else{
            return false;
        }
    }

13、audio元素和video元素在ios和andriod中无法自动播放

    
    原因: 因为各大浏览器都为了节省流量,做出了优化,在用户没有行为动作时(交互)不予许自动播放;

    /音频,写法一
    <audio data-original="music/bg.mp3" autoplay loop controls>你的浏览器还不支持哦</audio>
    
    //音频,写法二
    <audio controls="controls"> 
        <source data-original="music/bg.ogg" type="audio/ogg"></source>
        <source data-original="music/bg.mp3" type="audio/mpeg"></source>
        优先播放音乐bg.ogg,不支持在播放bg.mp3
    </audio>
    
    //JS绑定自动播放(操作window时,播放音乐)
    $(window).one('touchstart', function(){
        music.play();
    })
    
    //微信下兼容处理
    document.addEventListener("WeixinJSBridgeReady", function () {
        music.play();
    }, false);
    
    //小结
    //1.audio元素的autoplay属性在IOS及Android上无法使用,在PC端正常;
    //2.audio元素没有设置controls时,在IOS及Android会占据空间大小,而在PC端Chrome是不会占据任何空间;
    //3.注意不要遗漏微信的兼容处理需要引用微信JS;

14、css实现单行文本溢出显示 ...

直接上效果:相对于多行文本溢出做处理, 单行要简单多,且更容易理解。

实现方法

overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
当然还需要加宽度width属来兼容部分浏览。

15、实现多行文本溢出显示...

效果:

实现方法:

display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;

适用范围:

因使用了WebKit的CSS扩展属性,该方法适用于WebKit浏览器及移动端;

注:

1、-webkit-line-clamp用来限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他的WebKit属性。常见结合属性:
2、display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。
3、-webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。

如果你觉着这样还不够美观, 那么就接着往下看:

效果:

这样 是不是你想要的呢?

实现方法:

div {
    position: relative;
    line-height: 20px;
    max-height: 40px;
    overflow: hidden;
}

div:after {
    content: "..."; position: absolute; bottom: 0; right: 0; padding-left: 40px;
    background: -webkit-linear-gradient(left, transparent, #fff 55%);
    background: -o-linear-gradient(right, transparent, #fff 55%);
    background: -moz-linear-gradient(right, transparent, #fff 55%);
    background: linear-gradient(to right, transparent, #fff 55%);
}

不要只顾着吃,要注意胃口,此方法有个弊端 那就是 【未超出行的情况下也会出现省略号】 ,这样会不会很挫!!! 没办法,只能结合JS 进行优化该方法了。

注:


1、将height设置为line-height的整数倍,防止超出的文字露出。
2、给p::after添加渐变背景可避免文字只显示一半。
3、由于ie6-7不显示content内容,所以要添加标签兼容ie6-7(如:<span>…<span/>);兼容ie8需要将::after替换成:after。

16、让图文不可复制

这点应该大家 都很熟悉了, 某些时候【你懂的】为了快捷搜索答案,可是打死也不让你复制

-webkit-user-select: none; 
-ms-user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
user-select: none;

那有些网页为了尊重原创,复制的文本 都会被加上一段来源说明,是如何做到的呢?问的好! 等的就是你这个问题 -_- 。

大致思路:


1、答案区域监听copy事件,并阻止这个事件的默认行为。
2、获取选中的内容(window.getSelection())加上版权信息,然后设置到剪切板(clipboarddata.setData())。

17、盒子垂直水平居中

这个问题好像面试必问的吔!反正我是必问的,哈哈!!! 其实无关多少种实现思路,只要你能实现就可以!

提供4种方法

1、定位 盒子宽高已知, position: absolute; left: 50%; top: 50%; margin-left:-自身一半宽度; margin-top: -自身一半高度;

2、table-cell布局 父级 display: table-cell; vertical-align: middle;  子级 margin: 0 auto;

3、定位 + transform ; 适用于 子盒子 宽高不定时; (这里是本人常用方法)
    
    position: relative / absolute;
    /*top和left偏移各为50%*/
       top: 50%;
       left: 50%;
    /*translate(-50%,-50%) 偏移自身的宽和高的-50%*/
    transform: translate(-50%, -50%); 注意这里启动了3D硬件加速哦 会增加耗电量的 (至于何是3D加速 请看浏览器进程与线程篇)

4、flex 布局
    父级: 
        /*flex 布局*/
        display: flex;
        /*实现垂直居中*/
        align-items: center;
        /*实现水平居中*/
        justify-content: center;

再加一种水平方向上居中 :margin-left : 50% ; transform: translateX(-50%);

18、改变placeholder的字体颜色大小

其实这个方法也就在PC端可以,真机上屁用都没有,当时我就哭了。 但 还是贴出来吧

input::-webkit-input-placeholder { 
    /* WebKit browsers */ 
    font-size:14px;
    color: #333;
} 
input::-moz-placeholder { 
    /* Mozilla Firefox 19+ */ 
    font-size:14px;
    color: #333;
} 
input:-ms-input-placeholder { 
    /* Internet Explorer 10+ */ 
    font-size:14px;
    color: #333;
}

19、最快捷的数组求最大值

    var arr = [ 1,5,1,7,5,9];
    Math.max(...arr)  // 9 

20、更短的数组去重写法

    [...new Set([2,"12",2,12,1,2,1,6,12,13,6])]
    
    // [2, "12", 12, 1, 6, 13]

21、 vue 父子组件嵌套时,组件内部的各个生命周期钩子触发先后顺序

首先 我们可以把 子组件当做function函数来看待,当父组件 import 子组件的时候, 就当是声明了 并加载了这个函数,
在调用的时候才会去执行这个函数(子组件)。那么父子组件中的各个声明周期钩子触发的先后顺序是怎样的呢?
如下图:

下图带222 的 是为子组件,所以一次顺序是为 先创建父组件,然后才穿件子组件,当子组件创建完成并且实体dom挂载完成后父组件才挂载完成

注:资源来源于自己长期收集整理而来,如有和其他网站和论坛相同部分,在此抱歉!

查看原文

Toby 回答了问题 · 2017-11-04

js判断后退

http://javascript.ruanyifeng....

可以使用performance api

关注 3 回答 2

认证与成就

  • 获得 723 次点赞
  • 获得 12 枚徽章 获得 0 枚金徽章, 获得 3 枚银徽章, 获得 9 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-10-13
个人主页被 2.6k 人浏览