BOM

BOM

BOM   浏览器对象模型    B - Browser    O - Object     M - Model

BOM包含: history、location、navigator、screen 对象

location对象

1、hash: 返回hash值

    https://xxx.com/#sdfsdf       // '#sdfsdf'

2、host: 返回主机地址  'xxx.com'

3、hostname: 返回主机名  'xxx.com'

4、href: 整个url地址  "https://xxx.com/search?q=BOM"

5、origin: 起源  'https://xxx.com'

6、pathName: 路由名

    "https://xxx.com/search?q=BOM"   '/search'

7、port: 端口

8、protocol: 协议  'https'

9、search: 参数 '?q=BOM'

10、reload(): 刷新浏览器

    location.reload(); // 重新加载(有可能从缓存中加载)
    location.reload(true); // 重新加载(从服务器重新加载)

screen

1、width、height: 整天个屏幕的宽、高

2、avaiWidth、avaiHeight: 返回显示屏幕的宽、高 除dock和系统上面的菜单栏

3、pixelDepth: 返回显示屏幕的颜色分辨率

4、updateInteval: 设置或返回屏幕刷新率

history

1、length: 历史记录的个数

2、go(): 指定跳转的历史、-1后退一页,1前进一页

3、back()、forward(): 后退和前进一页
1、appCodeName: 浏览器代码名 'Mozilla'

2、appName: 浏览器名称    'Netscape'

3、appVersion: 浏览器版本  '5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'

4、browserLanguage: 浏览器语言

5、cookieEnabled: 是否启用了cookie 返回Boolean

    如果浏览器关闭cookie,当获取cookie时, document.cookie 返回的是空字符串

6、cpuClass: 返回浏览器系统的cpu等级

8、onLine: 是否处于脱机模式,Boolean

9、platform: 浏览器的操作平台

10、systemLanguage: 系统语言

11、userAgent: 客户机发送服务器的 user-agent 头部的值

12、userLanguage: 返回 OS 的自然语言设置


** 检测插件  ie无效
function hasPlugin(name){
    name = name.toLowerCase();
    for (var i = 0; i < navigator.plugins.length; i ++){
        if (navigator.plugins[i].name.toLowerCase().indexOf(name) > -1){
            return true;
        }
    }
    return false;
}

** 检测Flash
function hasPlugin(name){
    name = name.toLowerCase();
    for (var i = 0; i < navigator.plugins.length; i ++){
        if (navigator.plugins[i].name.toLowerCase().indexOf(name) > -1){
            return true;
        }
    }
    return false;
}

function hasIEPlugin(name){
    try{
        new ActiveXObject(name);
        return true;
    }catch(ex){
        return false;
    }
}

function hasFlash(){
    var result = hasPlugin("Flash");
    if (!result){
        result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash");
    }
    return result;
}

console.log(hasFlash()) //true

window 对象

1、window.open(url, target, param): 打开一个新窗口

2、window.close(): 关闭一个窗口

3、setInterval()、clearInterval()

4、setTimeout()、clearTimeout()

5、screenLeft、screenTop: 浏览器当前窗口居屏幕的左、上角的位置  

    兼容:
    screenLeft || screenX
    screenTop || screenY

6、innerWidth、innerHeight: 浏览器可视区的宽高、包括滚动条

    let winHeight = window.innerHeight;

7、moveTo(x, y): 移动到屏幕左上角的位置

8、moveBy(0, 100): 向下移动100像素

9、resizeTo(x,y)、resizeBy(w, h)

offset 页面元素偏移量

1、offsetWidth、offsetHeight: 获取当前元素宽高,相当于 width + padding + border

2、offsetLeft、offsetTop: 获取元素到父级元素定位的左、上偏移,如果父级不是定位就以body元素为定位

3、offsetParent: 获取最近一个带有定位的父级元素

4、clientWidth、clientHeight: 元素本身的宽高、不包括padding和border

    兼容
    document.documentElement.clientWidth || document.body。clientWidth
    document.documentElement.clientHeight || document.body。clientHeight

scroll 滚动类

窗口滚动条或带滚动条元素

1、scrollWidth、scrollheight: 对象内部实际内容的宽、高

2、scrollTop、scrollLeft: 被卷部分的顶部和左侧部分

    只挂载到了Element元素中,window和document下都没有

    let topValue = document.documentElement.scrollTop || document.body.scrollTop;       // 获取整个页面巻上去的高度和兼容方法

    let topValue = document.querySelector('#sider').scrollTop;      // 针对某个元素


3、onscroll: 侦听滚动条事件

client 鼠标所在的可视区坐标

1、clientX、clientY: 获取鼠标可视区的位置  clientX = width + padding

2、clientLeft、clientTop: 获取鼠标在可视区域的位置

3、pageX、pageY: 获取鼠标在页面中的位置, pageX = clientX + 页面滚动出的距离

node.onclick = function(evt){
    let evt = evt || window.evnet;
    console.log(evt.pageX, evt.pageY);
    console.log(evt.pageX, evt.pageY);
}

事件

1、target: 点击的目标阶段事件,ie8之前使用srcElement

    var oT = evt.target || srcElement; console.log(oT);     // <p>xxxx</p>

2、currentTarget: 事件流的捕获,目标及冒泡阶段

3、addEventListener()、attachEvent(): 注册事件

    addEventListener('click', fn, false);

正则表达式

特殊字符和转义序列

1、[...] 位于括号内的任意字符            

    /[abcde]/.test('aboot');     // 只要含有任意一个字符返回 true

    /a[bo]t/.test('abot');        // false 中间只能含有其中一个字符,匹配'abt'或'aot'

2、[^...] 不在括号中之中的任意字符

    /a[^bo]t/.test('ast');        // true a|t之间不含有b、o期中一个字符

*3、. 除了换行和Unicode行止符之外的任意字符

    /a.t/.test('a*t');        // true , 'a\nt'换行false,使用 \.来进行转义

4、\w 任何ASCII字符,等于[a-zA-Z0-9_]

    /\w/.test('think');        // true, 不含有其它字符

5、\W 任何非ASCII字符单字字符,等于[^a-zA-Z0-9_]

    /\w/.test('think');        // false, 至少需要有一个特殊字符

6、\s 任何空格

    /\s/.test('I think');    // true

7、\S 不包含空格

    /\s/.test('I think');    // false, 非空格为true

8、\d 任何数字,等于[0-9]

9、\D 除了数字之外的任意字符

10、\b 单词边界

    例: 匹配 hi 这个词,如果写成 /hi/ 这样 'wordhibiry are you' 也会匹配,如果加\b会单词的分界空格处来匹配, /hi\b/.test('word hi biry are you');  true

11、\B 非单词边界 

指定匹配的位置

1、^ 匹配字符串的开头

    /^ab/.test('absolute');        // true 以ab开头

2、$ 匹配字符串的结尾

    /te$/.test('absolute');        // true 以te结尾

* 3、? ! 一个反前向声明者,含义与反前向声明相反

选择、分组和引用

1、| 用于分隔选择的字符,相当于或

    /oa|on|op/.test('option');    // true,只要带有oa、on、op都匹配

2、(...) 分组,相当于并且

    /(\d+&)([a-zA-Z]+%)/.test('1234&abcde%');        // true, 必须包含数据+&,并且还包含英文字母+%

* 3、(?...) 只组合,把项组合到一个单元,但不记忆与该组匹配的字符

    (?:):

    (?!):

    (?<=):

    (?<!):

重复

1、{ } 匹配一个字符的重复  **** 注意{3,10} 逗号后不能有空格, 如{3, 10}        

    /^\d{1,3}$/: 最少2个数字,最多4个数字

    /^\d{4,}$/: 最少有4个数字

    /^\d{4}$/: 只能有4个数字

2、* 表示0次或多次重复,等价于{0, }    /^\d*$/

3、?最少0次, 最多1次重复,等价于{0,1}   

4、+ 表示最少出现1次,等价于{1,}

5、\1、\2 重复的子项

    var reg = /(a)(b)(c)\1/;
    var str = "abca";

    // 返回 true: \1是重复第一个子项(a),相当于/(a)(b)(c)(a)/.     \2就是第二项(b)
    console.log(reg.test(str));

修饰符,高级匹配

1、g 匹配的是全局,检索字符串的所有匹配

    如果不加g只匹配第一个后就退出

    let reg = /你妈的|去你妈|傻逼/g;
    let content = '你妈的房子傻逼是用来住的你妈的不是用来炒的去你妈的吧';
    content = content.replace(reg, '***');
    console.log(content)            // ***房子***是用来住的***不是用来炒的***的吧

2、i 匹配忽略大小写

    /java/i.test('JavdaScript');        // true

3、m 进行多行匹配

常用方法

1、match(reg) 将匹配结果返回一个数组

    var arr = '123kasdo34kk234k234234k'.match(/\d+/g);        // 如果不加g,只返回第一个
    console.log(arr);        // ["123", "34", "234", "234234"]

2、test() 如果没有匹配返回false否则返回true

3、search(reg) 查找并返回所在的位置,如果没有匹配的返回-1

    var result = '房地产行业究竟是白银时代还是钻石时代'.search(/钻石/); 
    console.log(result);        // 返回 8

4、content.replace(reg, str) 用于执行检索和替换操作

5、exec() [ɪɡ'zek] 如果找到返回一个数组并存放匹配的结果,如果没有找到返回null

    var result = /白银|钻石/g.exec('房地产行业究竟是白银时代还是钻石时代'); 
    console.log(result);        // ['']

整理经验

1、如果检查全部需要前后加匹配

    /\d+/  只对字符中存在数字就匹配

    /^\d+$/  对字符中全部为数字的进行匹配


2、test()、exec()是对每一个字符串进行匹配,如果为true就不会往下执行,并返回true

    例如: 匹配字符中不能带有.字符
    /[^\.]/.test('123123.');    // 返回true,因为第一个字符就不是.返回true不在往下执行

    /[\.]/.test('23412.34');    // 如果存在就返回true
    或者
    /^[^\.]$/g.test('asdfa.sdf') // 返回true

3、| 或符号只能用到()中,不能在[]中使用

常用示例

1、密码强度

    // 弱密码 - 纯数字、纯字母或纯特殊字符
    /^(?:\d+|[a-zA-Z]+|[!@#$%^&*]+)$/

    // 中密码 - 字母+数字,字母+特殊字符,数字+特殊字符
    /^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)[a-zA-Z\d!@#$%^&*]+$/

    // 强密码 - 必须有数字、小写字母、大写字母和特殊字符
    /^(?=.*((?=[!@#$%^&*_]+)[^A-Za-z0-9]))(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\u4e00-\u9fa5]{8,16}$/


2、手机号码验证

    /^(139|138|137|136|135|134|178|170|188|187|183|182|159|158|157|152|150|147|139|186|185|170|156|155|130|131|132|189|180|170|153|133)(\d){8}$/.test('13012345678')

    移动号段: /^(139|138|137|136|135|134|178|170|188|187|183|182|159|158|157|152|150|147|139)(\d){8}$/;     

    联通号段: /^(186|185|170|156|155|130|131|132)(\d){8}$/

    电信号段: /^(189|180|170|153|133)(\d){8}$/


3、验证Email - /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/

4、验证中文 - /^[\u4e00-\u9fa5]+$/

5、域名验证 - /^(http(s)?:\/\/)(www)?\.\w+\.(com|cn|net|org)$/

6、手机号前带86或是+86 - /^((\+86)|(86))?(13)\d{9}$/

7、电话号码与手机号码同时验证 - /(^(\d{3,4}-)?\d{7,8})$|(13[0-9]{9})/

8、验证IP地址 - /^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/;    //  匹配0-255, 匹配'255.255.255.255'

9、邮政编码 - /[1-9]{1}(\d+){5}/

10、身份证号码 - /\d{18}|\d{15}/

11、双字节字符串(汉字) - /[^\x00-\xff]*/

12、去除两端空格 - /^\s*|\s*$/

数字正则

    /^\d+$/ - 非负整数(正整数 + 0)

    /^[1-9](\d)+$/ - 正整数(不可以以0开头)  

    /^-(\d)+$/ - 非正整数(负整数 + 0) 

    /^-[1-9]?(\d){0,}$/ - 负整数(-12345), 不可以-012312

    /^[1-9]?(\d)+\.(\d)+$/ - 浮点数   

    /^[+-]?\d+(\.\d{1,2})?$/ - 可以是整数 或 浮点数,并且小数点只能后两位

    ^(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*))$    //正浮点数   
    ^((-\\d+(  //非正浮点数(负浮点数 + 0)   
    ^(-(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*)))$  //负浮点数  

    /^[A-Za-z]+$/ - 由26个英文字母组成的字符串   

    /^[A-Z]+$/ - 由26个英文字母的大写组成的字符串   

    /^[a-z]+$/ - 由26个英文字母的小写组成的字符串  

    /^[A-Za-z0-9]+$/ - 由数字和26个英文字母组成的字符串   

    /^\w+$/ - 由数字、26个英文字母或者下划线组成的字符串

DOM

DOM介绍

DOM 文档对象模型     D - Document      O - Object      M - Model

Node 对象属性

1、nodeType: 节点类型

    e.target.nodeType 来获取节点的类别

    1、Element 1

    2、Attr  2

    3、Text  3

    4、注释  8

    5、Document 9


2、nodeName: 节点名称   返回的是大写 'DIV'

3、nodeValue: 节点的类型

    元素节点的 nodeValue 是 undefined 或 null
    文本节点的 nodeValue 是文本本身
    属性节点的 nodeValue 是属性值

    <p>dfsdfsdf</p>

    let oP = document.querySelector('p');   
    // 这里注意oP是元素如果直接写成oP.nodeValue返回是null,写成oP下的第一个节点才找到文本元素
    oP.firstChild.nodeValue;            

4、parentNode: 返回当前节点的父节点   e.target.parentNode.nodeName

    document.querySelector('ul').parentNode     // <div class="box">...</box>

5、childNodes、children: 返回所有子节点元素,不包括孙节点

    <ul id="list">
        <li>111</li>
        <li>222</li>
        <li>
            <ul>
                <li>333</li>
                <li>444</li>
            </ul>
        </li>
    </ul>

    let oList = document.querySelector("#list");
    let lis = oList.children;
    for(let i=0; i<lis.length; i++){
        console.log(lis[i].nodeName);   // output LI LI LI
    }

    ** childeNodes与children区别 ** 

        childeNodes: 包括空行的文本节点, 如果是空行的节点返回是一个text节点
        children: 不包括空行之类的节点

6、hasChildNodes(): 判断是否有子节点,返回Booleanw值

7、firstChild、lastChild: 返回子节点的第一个节点、最后一个节点

    firstChild 相当于 children[0]

    lastChilde 相当于 children[node.children.length-1]

    <div id="car"><p>aaa</p><div>bbb</div><span>ccc</span></div>

    let oCars = document.querySelector("#car");
    console.log(oCars.firstNode, oCars.lastNode);   //<p>aaa</p> 、 <span>ccc</span>

8、previousSibling、nextSibling: 当前节点的前一个节点、后一个节点

    注意: 如果是空行返回的是 text

9、innerHTML: 获取或修改HTML元素内容

    Element.innerHTML = '<div>xxxxx<div>';

10、innerText: 获取或修改的是除去html的文本

11、outerHTML、outerText: 与innerHTML、innerText相当,不同的是它包含当前节点元素,inner只包含子节点元素

12、offsetParent: 获取当前元素定位的父元素  找到基于设置position的父元素

     document.querySelector('ul').offsetParent

Node 对象的方法

一、节点操作方法

    1、getElementById(): 获取指定ID的元素

    2、getElementsByTagName(): 获取指定标签名称的所有元素

    3、getElementsByClassName(): 获取指定类名的元素

    4、appendChild(): 追加子节点  注意这里插入的是一个节点,而不是HTML的字符串 parent.appendChild(children);

    5、removeChild(): 删除子节点,不能删除孙子节点    (removeNode 只支持IE)

        删除节点 并返回删除的节点
        let oSubCar = document.querSelector('#subCar');
        document.querySelector('body').removeChild(oSubCar);        // <div id="subCar">...</div>

    6、cloneNode(Boolean): 复制节点  如果参数为true复制指定节点下包括所有子节点,如果不写只复制当前节点不手包子节点

        <div class="car">
            <ul id="box">
                <li>aaa</li>
                <li>bbb</li>
                <li>ccc</li>
            </ul>
        </div>
        <div id="subCar"></div>

        <script>
            // 将id=box所有的节点插入到id=subCar中
            let boxList = document.querySelector('#box').cloneNode(true);
            var oSubCar = document.querySelector('#subCar');
            oSubCar.appendChild(boxList);
        </script>

    7、hasAttributes(): 判断当前节点是否拥有属性

        <div id="miniCar"></div>
        <div>swsss</div>

        let isAttribute = document.getElementsByTagName('div')[1].hasAttributes();
        console.log(isAttribute);   // false

    8、hasChildNodes(): 判断当前节点是否拥有子节点

    9、insertBefore(newitem, ex): 在指定节点之前插入

        insertAfter(): 这个需要自己来写没有这个方法

        let oMain = document.querySelector('#main');
        let oP = document.querySelector('p');
        let oUl = document.querySelector('.uls').cloneNode(true);
        oMain.insertBefore(oUl, oP);    将ul元素内所有节点复制并插入到oP元素之前

    10、replaceChild(newNode, oldNode): 替换节点

        document.querySelector('body').replaceChild(oMiniCar, oSubCar)


二、创建元素方法

    1、createAttribute(): 创建属性节点

    2、createElement(): 创建元素节点

    3、createTextNode(): 创建文本节点


三、操作属性方法

    1、getAttribute(): 获取属性值

    2、setAttribute(): 设置属性值

CSS样式

1、style:获取或设置style值   Element.style.color = 'blue' 

2、currentStyle、getCurrentStyle()获取样式中每个属性的值

    var oBox = document.querySelector('#box');
    var getStyle = function(obj, attr){
        return window.getComputedStyle ? window.getComputedStyle(obj, null)[attr] : obj.currentStyle[attr];
    }

    var attrTxt = getStyle(oBox, 'width');          // '100px';

    注意: (1)中style只能获取元素中的内联样式,而currentStyle、getCurrentStyle()无论是内联样式还是在class中都可以找到

3、getComputedStyle(元素, 伪类): 获取指定元素值,currentStyle(ie独有) 

    <script>
        function getStyle(element, attr) {
            if(window.getComputedStyle) {
                return window.getComputedStyle(element, null)[attr];
            } else {
                return element.currentStyle[attr];
            }
        }

        // 获取class=position-node元素上的position值
        var dom = document.querySelector(".position-node");
        var style = getStyle(dom);
        console.log(style.position);    // 返回relative
    </script>


    *** element.getComputedStyle与element.style的区别

    element.getComputedStyle: 只读
    element.style: 可读写

4、className: 获取或设置元素的类名  Element.addClass = 'classname'

其它

1、write(): 向输出流写文本或html

2、document.title: 返回标题

4、"javascript:" : 伪协议 来调用javascript http协议(http://),FTP协议(ftp://)

5、对象检测: 可以测试浏览器是否支持当前对象

    if(document.getElementById){ ...}

性能

1、createDocumentFragment: 创建文档碎片

    Example: 创建节点并插入到body中,如果不使用文档碎片,每次都需要重新插入一次

    var oFragment = document.createDocumentFragment();
    for(var i = 0 ; i < 10; i ++) {
        var p = document.createElement("p");
        var oTxt = document.createTextNode("段落" + i);
        p.appendChild(oTxt);
        oFragment.appendChild(p);
    }
    document.body.appendChild(oFragment);

事件

1、表单事件:

    submit事件

    reset事件

    click事件

    change事件

    focus事件(不冒泡) (IE和ES5支持冒泡的focusin)

    blur事件(不冒泡) (IE和ES5支持冒泡的focusout)

    input事件(ES5 textinput提供更方便的获取输入文字的方案)


2、Window事件

    load: 资源全部加载完成后触发事件(图片、css、js)

    DOMContentLoaded事件: Document对象构建完后就开始调用此事件

    readyStatechage事件:

    unload事件: 关闭borwser的时候触发

    beforeunload事件

    resize: 浏览器窗口发生改变触发

    scroll: 滚动条有变化时触发


3、鼠标事件

    click: 点击事件

    dbclick:双击事件

    mouseover: 鼠标移入事件(冒泡)

    mouseout: 鼠标移出事件(冒泡)

    mousedown: 鼠标按下事件

    mouseup: 鼠标放开事件

    contextmenu: 上下文本菜单事件

    mouseenter: 事件(不冒泡)

    mouseleave: 事件(不冒泡)

    mousewheel: 事件(FF DOMMouseScroll事件、DOM3 wheel事件)


4、键盘事件

    keydown事件

    keyup事件

    keypress事件

ES5

script标签

1、async: 异步下载当前脚本,不阻塞后续代码的执行

2、charset: 字符集

3、defer: 表示当前脚本延迟到文档完全被解析和显示后在执行 defer="defer"

4、src: 文件路径

5、language: 语言

6、type: 脚本类型

'use strict' 严格模式

作用域和作用域链

作用域: 变量的有效范围,函数从内往外搜索变量,如果内部没有变量就去外部搜索直接全局对象

作用域链: 决定哪些变量能够被当前函数访问及访问顺序

    函数对象有一个[[Scope]]属性,包含了函数被创建作用域中对象的集合,集合被称为函数的作用域链scope chain,它决定了哪些数据能被函数访问

    function doSomething(){
            var blogName="Jessica";
            function innerSay(){
                    alert(blogName);
            }
            innerSay();
    }
    alert(blogName);        //脚本错误
    innerSay();             //脚本错误

变量生命周期:全局的变量是永久的,函数内的局部变量当退出函数时,局部变量即消毁,

预解析

JS执行时先将代码中所有 var定义变量和function(){} 进行提取,函数内部变量除外。

将var的变量赋为undefined

将函数都为函数本身function getName(){},所以在调用函数时无论在前还是在后都会被调用。

Example:
    var add = 'bbb'; 
    function add(){console.log('aaa')} 
    add();      报错

闭包

闭包: 函数嵌套,内部函数调用外部函数的局部变量,内部函数执行完后自动消毁,外部函数的变量不会被回收一直保存在内存中.

<script>
    var fun = function(){
        var a = 1;
        return function(){
            a++;
            alert(a);
        }
    }

    var f = fun();        // 这里返回了匿名函数的引用,里面的局部变量就不会被消毁
    f();    // 2
    f();    // 3
    f();    // 4
</script>

数据类型

JS的七种数据类型: Number、String、Boolean、Undefined、Object、Function、Symbol

一、 获取数据类型

    获取数据的类型: 返回的值(number、string、boolean、array、object、function、undefined、symbol)

    Object.prototype.toString.call(val) - 获取JS私有的 Class 属性, 这个隐藏的属性是不能被改的

    // 判断类型
    function returnType(val) {
        let typeName;
        if (typeof val === 'object') {
            let typeName = Object.prototype.toString.call(val);

            if (typeName == '[object Array]') {
                return 'array'
            } 
            else if (typeName == '[object Object]') {
                return 'object'
            }
            else if(typeName == '[object Null]'){
                return 'null'
            }
        } 
        else {
            return typeof val;
        }
    }


二、NaN 非数值

    isNaN() 是否是一个NaN非数值, 如果是数字返回false, 否则返回true

        isNaN(NaN);     // true
        isNaN(10);      // false
        isNaN('10');    // false 转换后是一个数字
        isNaN('blue');  // true 转换后不会是一个数字
        isNaN(true);    // false true转换后为1是一个数字      


三、类型转换

    String to Number: 类型转换只支持十进制(30)、二进制(0b111)、八进制(0o13)、十六进制(0xFF)

    Number比parseInt和parseFloat更好的选择,一些古老的浏览器parseInt还支持0开头数字的八进制前缀,这是错误的,在任何环境下都建议传入parseInt第二个参数

    1、Number() 布尔转换成1或0,null返回0,undefined返回NaN

    2、parseiInt(num, 10): 第二个参数来规则用哪个进制来转换

    3、parseFloat(): 直接将字符串以十进制来转换

包装类

var str = '1234567';
str.length;        // 返回7

str原始值只是一个字符串,为什么会有属性和方法,它经历了一个过程叫『包装类』
JS在执行些方法的时候会隐式的转成 new String(str),执行完后在乐逍毁掉

函数

一、函数没有重载: 当两个函数名相同,后面的函数会覆盖掉之前的函数

    function getUserName(){
        console.log('a');
    }

    function getUserName(){
        console.log('b');
    }

    getUserName();      // 'b'


二、声明函数和匿名函数

    function person() {  ...  };          // 声明
    var person = function() {  ...  }     // 匿名

    Example:

        getName();          // b
        var getName = function(){       // 优先级要高于声明函数,但要必须执行到这里才有效
            console.log('a');
        };

        getName();          // a

        function getName(){
            console.log('b');
        }
        getName();          // a


三、函数参数

    1、形参、实参

        function add(a, b){ return a+b }    // 形参

        add(1,2)    // 实参


    2、arguments数组: 函数参数的数组

    3、callee 函数的调用当前函数的本身,可以使用arguments.caller(), 可以用于递归

        function factorial(num){
            if(num < 1){
                return 1;
            }
            else{
                return num * arguments.callee(num-1);
            }
        }

    4、caller 返回被调用函数的本身

        function outer() {
            inner();
        }

        function inner() {
            alert(arguments.callee);        // function inner(){ ... }
            alert(arguments.callee.caller); // function outer(){ ... }
        }

        outer();

四、如果函数没有return返回undefined

    var fn = function(){ }; 
    fn();       // undefined

call()、apply()、bind()

Function.prototype.call() 和 Function.prototype.apply() 用于改变函数的this指向

一、call无参

    var obj1 = {
        name: 'siguang',
        getName: function(){
            return this.name;
        }
    }
    var obj2 = {
        name: 'lulu'
    }
    console.log(obj1.getName());  // siguang

    // 注意这里是将getName中的this指定指向了obj2,并且执行了getName()函数
    var n1 = obj1.getName.call(obj2);
    console.log(n1);        // lulu


二、apply有参

    var objA = {
        num: 10,
        add: function(a, b){
            return a + b + this.num;
        }
    }
    var objB = {
        num: 20
    } 

    var n1 = objA.add(1, 2);
    console.log(n1);    // 13

    var n2 = objA.add.call(objB, 1, 2);     // 如果objA.add.apply(objB, [1,2]);
    console.log(n2)     // 23


三、bind(): 一个函数绑定之后,可以保持传递this的上下文

    bind与call、apply的用法不同,但作用是一样的.

    var obj = {
        nameStr: 20,
        getName: function(){
            setTimeout(function(){
                console.log(this.nameStr);
            }.bind(obj), 10)
        }
    }

    // 输出20,如果不加bind(),this指向window所以输出的是undeined
    obj.getName();

void(0)

这个操作符允许插入一个计算结果等效于undefined的表达式。

void操作符经常仅仅是用来获得undefined值,比如经常使用到的“void(0)”(这等效于“void 0”)

当浏览器遇到一个javascript:URI,它会运算带有URI的代码,然后将计算结果替换当前页面的内容,除非它的返回值是undefined。void操作符可以被用于返回undefined

<a href="javascript:void(0);">Click here to do nothing</a>

装箱、拆箱转换

一、装箱: 把基本类型转换为对应的对象

    var symbolObject = Object(Symbol("a"));
    console.log(typeof symbolObject);                   // object
    console.log(symbolObject instanceof Symbol);        // true 是Symbol的实例
    console.log(symbolObject.constructor == Symbol);    // true


二、拆箱

    对象到String和Number转换同都遵循『先拆箱在转换』的规则,通过拆箱把对象变成基本类型,在从基本类型转为string或number

    toString(): 将该对象的原型始以字符串形式返回   xx.toString();       // 'xx'

    valueOf(): 返回最适合该对象的类型的原始值

表达式

var testA = 3 && 2;             // 返回 2,如果左侧为真返回右侧,否则返回左侧

var testB = 0 || 3;             // 返回3,如果左侧为假返回右侧

var a = 1; console.log(!!a);    // 返回true,!!强制转换成布尔值

var a = '123.563'; console.log( +a );  // 123.563,+转换成数值类型

语句

for(var i=0; i<10; i++){}

do{....} while(express)

while(){ ... }

for( in ){}

break 退出整个循环        continue 跳出当前循环,继续执行下一个循环

switch case default

定时器的运行机制

JavaScript是通过事件循环(event loop)来实现的,事件循环机制也就是今天要说的JavaScript运行机制。

第一,判断JS是同步还是异步,同步进入主线程,异步则进入event table。

第二,异步任务在event table中注册函数,当满足触发条件后,被推入event queue(事件队列)。

第三,同步任务进入主线程后一直执行,直到主线程空闲,才会去event queue中查看是否有可执行的异步任务,如果有就推入主线程

异步为了避免一些长时间任务造成的无意义等待,和假死状态 - ajax、定时器、Promise

Example:

    // HTML5规范规定最小时间不能小于4ms(毫秒),如果小于4会被当4来处理,Chrome可以设置1ms
    console.log(1);
    setTimeout(function(){
        console.log(2);
    }, 0);
    console.log(3);         // 1、3、2

JS异步有哪些方式

1、setTimeOut()

2、Promise

3、Generator

4、async、await

5、ajax

宏任务和微任务

JS的运行机制。也就是事件循环。解释一下:

    第一,执行一个宏任务(主线程的同步script代码),过程中如果遇到微任务,就将其放到微任务的事件队列里。

    第二,当前宏任务执行完成后,会查微任务的事件队列,将全部的微任务依次执行完,再去依次执行宏任务事件队列。

    宏任务:包括整体script代码,setTimeout,setInterval

    微任务:Promise,process.nextTick。

setTimeout(() => {
    console.log(1) 
}, 3000); 

new Promise((resolve, reject) => { 
    console.log(2); 
    resolve('2') 
})
.then(function(){  
    console.log(3) 
});

console.log(4);                // output 2、4、3、1

事件

一、事件机制: 事件捕获 和 事件冒泡, IE11之前没有捕获

二、事件委托

    事件委托(也称事件代理): 将事件绑定到父元素上,利用冒泡机制来对点击的元素进行处理

    <div id="boxList">
        <ul>
            <li data-attr="a1">aaa</li>
            <li data-attr="a2">bbb</li>
            <li data-attr="a3">ccc</li>
        </ul>
    </div>

    <script type="text/javascript">
        var oList = document.querySelector('#boxList');
        oList.onclick = function(e){
            var arrtName = e.target.getAttribute('data-attr');
            console.log(arrtName);
        }
    </script>


三、自定义事件

四、onLoad与DOMContentLoaded事件的区别

    onLoad: 是当所有资源都加载完成后在执行onLoad函数内的程序

    DOMContentLoaded: 是当DOM树加载完成后就执行此函数内的程序


五、onmouseover、onmouseout与onmouseEnter、onmouseLeave

    onmouseover、onmouseout 会冒泡

    onmouseEnter、onmouseLeave 不会冒泡


六、addEventListener(事件类型, 执行函数, boolear): 第三个参数,如果是true表示在捕获取中调用事件,false冒泡时调用

    这里执行的函数不会被重载

    var oSendBtn = document.querySelector('#sendBtn');      // 点击会输出'aa', 'bb'

    oSendBtn.addEventListener('click', function(){
            console.log('aa');
    }, false);

    oSendBtn.addEventListener('click', function(){
            console.log('bb');
    }, false);

概念

一、加载非阻塞脚本:  

    浏览器遇到 <script> 标签时,页面加载都会停下来,先执行js代码,然后在继续加载(因为不知道脚本里有没有document.wirte()
    来向页面写内容,所以会需要先执行完js文件在继续)

    使用动态创建DOM元素,将脚本加载放到</body>之前来加载,这样不会影响页面的内容展示


二、按需加载: 可以分图片按需加载,js文件按需加载、数据接需加载

    图片按需加载使用的lazyload

    JS按需加载类似模块化开发,只对依赖的文件进行加载


三、图片预加载: 通过new Images()来创建图像对象提前将图片进行加载

    function preloadImg(url) {
        var img = new Image();
        img.src = url;
        if(img.complete) {
            //接下来可以使用图片了
            //do something here
        }
        else {
            img.onload = function() {
                //接下来可以使用图片了
                //do something here
            };
        }
    }

跨域的解决方法

由于同源策略,安全性,ajax不同域下的数据不可以调用

跨域的产生: 1、同域名不同端口        2、同域名不同协议        3、主域和子域之间        4、子域和子域之间

解决跨域的方法: 

一、JSONP

    JSONP利用script标签中的src属性,src属性没有跨域限制,通过url的参数将回调函数的名称和数据请求给服务器,服务器接收到url参数进行处理,并将数据挂载到回调函数的参数并执行回调函数,客户端有与回调函数名相同,来处理这些数据

    // 处理回调函数数据的函数
    function doSomething(data) {
            // 对data处理
    }
    var script = document.createElement("script");
    script.src = "http://www.b.com/b.html?callback=doSomething";
    document.body.appendChild(script);


二、document.domain: 

    适用于主域相同子域不同,比如 www.renrendai.com 和 action.renrendai.com

    例如: 两个域下各有a.html和b.html, a通过iframe嵌到另一个子域b.html是无权访问b.html文档内的元素, 所以通过document.domain来设置

    a.html: 
        document.domain = "www.we.com";
        var iframe = document.createElement("iframe");
        iframe.src = "http://a.we.com/b.html";
        document.body.appendChild(iframe);
        iframe.onload = function() {
            console.log(iframe.contentWindow....); // 在这里操作b.html里的元素数据
        }

    b.html:
        document.domain = "www.we.com";       // b页面必须要设置a.html


三、HTML5 postMessage() 处理iframe跨域问题

    如果在一个主域中的a.html嵌套个 <iframe src="http://www.b.com/b.html" frameborder="0"></iframe>

    postMessage有两个接口: postMessage(send) 发送数据和 onmessage接收数据事件通过e.data来获取到

    Example: 
        // a.html
        <iframe src="http://www.b.com/b.html" frameborder="0" id="messageId"></iframe>

        var oMessage = document.getElementById('messageId');
        window.onload = function(){
            window.addEventListener('message', function(e){
                console.log(e.data);    // 接收b的数据
            }, false);
            oMessage.postMessage('发送给b的数据', 'http://www.b.com/b.html');
        }

        // b.html
        window.onload = function(){
            window.addEventListener('message', function(e){
                console.log(e.data);    // 接收a的数据
            })
            window.parent.postMessage('发送给a的数据', 'http://www.a.html/a.html');
        }

    传统的iframe跨域使用方法: http://www.cnblogs.com/snandy/p/3900016.html


四、window.name + iframe

    window.name原理是利用同一个窗口在不同页面共用一个window.name,这个需要在a.com下建立一个代理文件c.html,使同源后a.html能获取c.html的window.name.

        // a.html
        var iframe = document.createElement("iframe");
        iframe.src = "http://www.b.com/b.html";
        document.body.appendChild(iframe); // 现在a.html里建一个引用b.html的iframe,获得b的数据

        var flag = true;
        iframe.onload = function() {
            if (flag) {
                iframe.src = "c.html";          // 这里在去加载c.html
                // 判断是第一次载入的话,设置代理c.html使和a.html在同目录同源,这样才能在下面的else取到data
                flag = false;
            } 
            else { 
                // 第二次载入由于a和c同源,a可以直接获取c的window.name
                alert(iframe.contentWindow.name);

                iframe.contentWindow.close();
                document.body.removeChild(iframe);
                iframe.src = '';
                iframe = null;
            }
        }

        // b.html
        window.name = "这是 b 页面的数据";


五、window.location.hash + iframe

    b.html将数据以hash值的方式附加到c.html的url上,在c.html页面通过loaction.hash获取数据后传到a.html

    // a.html
    var iframe = document.createElement("iframe");
    iframe.src = "http://www.b.com/b.html";
    document.body.appendChild(iframe); // 在a页面引用b
    function check() { 
        // 设置个定时器不断监控hash的变化,hash一变说明数据传过来了
        var hashs = window.location.hash;
        if (hashs) {
            clearInterval(time);
            alert(hashs.substring(1));
        }
    }
    var time = setInterval(check, 30);

    //b.html
    window.onload = function() {
        var data = "this is b's data"; 
        var iframe = document.createElement("iframe");
        iframe.src = "http://www.a.com/c.html#" + data;         
        document.body.appendChild(iframe); // 将数据附加在c.html的hash上
    }

    //c.html
    // 获取自身的hash再传到a.html的hash里,数据传输完毕
    parent.parent.location.hash = self.location.hash.substring(1);


六、CORS跨域资源共享

    1、CORS概念: 是指跨域资源共享, 用于解决前端跨域问题, 使用自定义头部让浏览器与服务器进行沟通, 来进行请求成功或失败

        原理: 服务器对header设置一个Access-Control-Allow-Origin: *, 开启跨域请求。

        *表示接受所有域名的请求。也可以指定特定的域名 Access-Control-Allow-Origin: http://www.client.com。


    2、CORS优点: 跨域最常用的是JSONP但这种方式是通过Get的方式请求src完成的,很多跨域问题JSONP无法解决,比如: 

        1)post请求跨域

        2)"script error" 的脚本错误提示

        3)canvas中无法获取跨域图片的信息,如果使用CORS上面几个问题就可以解决


    3、CORS缺点: 

        1)cookie不会随请求发送,也不会响应

        2)不能设置请求头的Content-Type字段

        3)不能访问响应头信息

面向对象

面向对象的特点: 封装、继承、多态

对象组件: 私有、公有属性、方法和特权方法

一、对象的数据属性和访问器属性(getter、setter)

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

二、constructor属性: 指向这个原型的构造函数,如果是类式继承需要修改子类的constructor的指向,如果不改子类会指向父类.

三、原型和原型链: 

    prototype原型: 在创建函数的时候JS会为这个函数自动加上prototype属性

    原型链: 每一个构造函数都有一个prototype, prototype包含一个指向构造函数的指针, 而实例包含指向原型的对象的指针, 都是通过 __proto__ 属性来指向

    1、构造函数实例化后,prototype下的所有属性和方法都为公用的一套, 这样为了节省资源提高性能

    2、优先级: 如果同时在构造函数内或prototype中定义相同的属性或方法名, 会先找到执行构造函数内的属性或方法, 如果没有在到prototype中查找。

            __proto__属性: __proto__是实例与prototype之间的链接,实例的__proto__指向构造函数的prototype.function F(){}; 

            var f = new F(); 
            console.log(f.__proto__ === F.prototype);           // true
            Object.prototype是顶级对象,所有对象都继承它

四、继承

    每个对象都是由Object.prototype对象继承的

        继承分为: 类式继承、原型链继承、拷贝继承。

        1、类式继承: 

            function Parent(){}
            Parent.prototype.say = function(){ 
                console.log('haha')
            }

            function Childer(){}

            /* 将第一个类的实例赋给第二个类的原形,类式继承的原因
            *  类的原型对象作用就是为类的原型添加公有方法,但不能直接访问这些属性和方法,必须通过原型prototype来访问
            */
            Childer.prototype = new Parent();   

            // 上一步执行后prototype的constructor会指向Parent,所以需要修正回来
            Childer.prototype.constructor = Childer;    
            Childer.prototype.getAuthor = function(){ console.log('siguang') }


        2、原型链继承: 

            // 原型链式继承
            /*
            * 流程:
            * 1、clonePlan调用blood属性会在clonePlan查找所有属性,
            * 2、如果没有找到在看clonePlan的__proto__指象哪里,这里指向了F,到F对象下的prototype下查找
            * 3、plane将prototype赋给了F的prototype所以最终找到了blood属性
            */

            function extend(obj){
                    var F = function(){};
                    F.prototype = obj;
                    return new F();
            }

            // 定义一个类
            var Plane = function(){
                    this.blood = 100;
                    this.attackLevel = 1;
                    this.defenseLevel = 1;
            }
            Plane.prototype = {
                    getBlood: function(){
                            console.log(this.blood);
                    },
                    getAttackLevel: function(){
                            console.log(this.attackLevel)
                    }
            }
            var plane = new Plane();

            // 将类通过extend函数继承过来
            var clonePlan = extend(plane);
            clonePlan.blood = 1234;
            clonePlan.attackLevel = 4567;

            clonePlan.getBlood();               // 1234
            clonePlan.getAttackLevel();         // 4567


        3、拷贝继承

            function extend(parent, childer){
                for(var key in parent){
                    childer[key] = parent[key];
                }
            }

            extend(a.prototype, b.prototype);


        4、Object.create()继承

            function Car(desc){
                this.desc = desc;
                this.color = 'red'
            }

            Car.prototype = {
                getInfo: function(){
                    return `color: ${this.color}, desc: ${this.desc}`
                }
            }

            // 注意这里的name : {value: 'lulu'} 必须是对象,必须是value在根一个值,要不报错
            var child = Object.create(Car.prototype);
            child.desc = 'aaa';
            child.color = 'bbb';

            // 改变子类不会影响到父类
            console.log(child);
            var childCar = child.getInfo();
            console.log(childCar)       // color: bbb, desc: aaa

            var oCar = new Car('ccc');
            console.log(oCar.getInfo());    /// color: red, desc: ccc


五、SuperClass.prototype = {} 与 SuperClass.prototype.getName = function(){} 区别

    一个是将对象覆盖prototype, 一个是将方法添加到prototype中

    存在的问题,SuperClass.prototype = {}这种方式,实例的对象没有constructor,

Ajax

一、XMLHttpRequrest 缓存

    缓存只有在get请求中存在,如果服务端设置了缓存,如果在缓存失效前请求就会取到缓存的数据,解决有两种方法:

    1、加If-Modified-Since头

        xhr.setRequestHeader('If-Modified-Since', '0');

        jquery中设置  $.ajax({ cache: false })

    2、给请求的URL后加参数 

        let sendUrl = "http://host/getUser"+"?"+Math.random();


// 创建一个XMLHttpRequest对象
var xhr = window.XMLHttpRequrest ? new XMLHttpRequrest() : new ActiveXObject("Microsoft.XMLHTTP");   

属性: 服务器响应

    1、reponseText: 字符串响应数据

    2、responseXML: 获取XML响应数据

    3、timout: 设置超时请求时间

    4、responseType: 设置返回数据类型

            1、text: 字符串      2、document: Document对象       3、json: json数据       4、blob: 二进制对象       5、arrayBuffer: 二进制

方法: 

    1、open(请求类型,请求地址,同步/异步): 请求类型

    2、send(): 请求发送到服务器

    3、setRequestHeader(key,value): 设置请求头

    4、getResponseHeader(header)、getAllResponseHeaders(): 获取响应头

事件: 

    1、onabort: 停止传输

    2、onerror: 错误

    3、onload: 

    4、ontimout: 超时执行的事件

    5、onreadystatechange: 请求发送到服务器时,接收一些响应

        readyState: XMLHttpRequest的状态,

            0: 请求未初始化    1、服务器连接已建立      2、请求已接收     3、请求处理中     4、请求已完成,已响应

        status:  200: 成功  404:  未找到资源

        xhr.onreadystatechange = function(e){
            if(this.readyState == 4 && this.state == 200){
                console.log(this.reponseText)
            }
        }

    6、upload: 上传 XMLHttpRequestUpload

        function uploadFile() {  
            // 创建FormData对象
            var fd = new FormData();
            // 添加值
            fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]); 

            // 创建XMLHttpRequest()请求
            var xhr = new XMLHttpRequest();  
            // 文件上传时侦听progress事件
            xhr.upload.addEventListener("progress", uploadProgress, false);  

            xhr.addEventListener("load", uploadComplete, false);    // 载入 
            xhr.addEventListener("error", uploadFailed, false);     // 错误
            xhr.addEventListener("abort", uploadCanceled, false);   // 终止

            // 请求方式和地址
            xhr.open("POST", "test2.php");  
            // 发送请求到服务器
            xhr.send(fd);  
        }

        function uploadProgress(evt) { 
            // evt.loaded 当前上传的大小, evt.total 文件总大小
            if (evt.lengthComputable) {  
                var percentComplete = Math.round(evt.loaded * 100 / evt.total);  
                document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';  
            }  
            else {  
                document.getElementById('progressNumber').innerHTML = 'unable to compute';  
            }
        }

        function uploadComplete(evt) {  
            /* This event is raised when the server send back a response */  
            alert(evt.target.responseText);  
        }

        function uploadFailed(evt) {  
            alert("There was an error attempting to upload the file.");  
        }

        function uploadCanceled(evt) {  
            alert("The upload has been canceled by the user or the browser dropped the connection.");  
        }

content-type四种类型

get请求包括请求头、状态行

post请求包括请求头、状态行、请求主体(主体类型设置就是content-type来处理)

Content-Type:

一、application/x-www-form-urlencoded: 浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据

    jquery和ajax的默认的方式 content-type:「application/x-www-form-urlencoded;charset=utf-8」

    header:
    POST http://wwwexamplecom HTTP/11 
    Content-Type: application/x-www-form-urlencoded;charset=utf-8 

    ** Form Data

        incomeTime: "16:25:13"
        serialNumber: "223"
        incomeBank: "中央银行"
        incomeAccount: "穷逼"


二、multipart/form-data: 一般用来上传文件,必须让 form 的 enctyped 等于这个值

    content-type: multipart/form-data

    POST http://wwwexamplecom HTTP/11 
    Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA 

    ** Request Payload

            ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 
            Content-Disposition: form-data; name="text" 

            title 
            ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 
            Content-Disposition: form-data; name="file"; filename="chromepng" 
            Content-Type: image/png 

            PNG  content of chromepng  
            ------WebKitFormBoundaryrGKCBY7qhFd3TrwA-- 


三、application/json: 告诉服务端消息主体是序列化后的 JSON 字符串

    POST http://wwwexamplecom HTTP/11 
    Content-Type: application/json;charset=utf-8 

    // ajax请求
    var data = {'title':'test', 'sub' : [1,2,3]};
    $ajaxpost(url, data)success(function(result){

    });

    // 发送
    POST http://wwwexamplecom HTTP/11
    Content-Type: application/json;charset=utf-8

    ** Request Payload

        {"title":"test","sub":[1,2,3]}


四、text/xml: XML文件作为编码方式的需要用到的类型

    POST http://wwwexamplecom HTTP/11
    Content-Type: text/xml

    ** Request Payload


五、HTML5中的fromData异步上传表单

    这里注意需设置 content-type:false 和 processData: false

    function upThumbSubmit() {
        if(!windowFormData) { 
            alert('your brower is too old');
            return false;
        }
        var formData = new FormData($( "#upForm" )[0]);
        var upLoadFile = documentquerySelector('upfile')files[0];
        formDataappend('file': upLoadFile);

        $ajax({
            url:'?c=api&a=upload',
            type:'post',
            data:formData,
            processData: false,        // 不会被序列化
            contentType: false,        
            dataType:'json',
            success:function(data){
                alert(data);
                return false;
            }
        });
    }

iframe父子页面的通信

Example:

    parent.html:
        <body>
            <iframe src="child.html" frameborder="0" id="child"></iframe>
        </body>

    childe.html:
        <body>
            <div id="box"></div>
        </body>

一、父页面获取子页面

    <script>
        var myIframe = document.querySelector('#child'), 
                childDocument;

        if(myIframe.document){
            childDocument = myIframe.docuemnt;
        }
        else{
            childDocument = myIframe.contentWindow.docuemnt;
        }

        childDocument.querySelector('#box').innerHTML = 'xxxx';
    </script>

    1、先获取iframe节点

        var myIframe = document.querySelector('#child');        // 或 myIframe = window.frames['child'];

    2、获取iframe页面的document对象

        // ie浏览器
        var childDocument = myIframe.docuemnt;

        // 其它浏览器
        var childWindow = myIframe.contentWindow;     // 获取iframe的window对象
        var childDocument = myIframe.contentWindow.docuemnt;    // 获取iframe的document对象
        var childDocuemnt = myIframe.contentDocument;   // 也是获取document对象  与 myIframe.contentWindow.docuemnt 相同

    3、向id='box'设置内容

        childDocument.querySelector('#box').innerHTML = 'xxxx';


二、子页面获取父页面

    1、获取父页面的document对象

        var parentDocument = window.parent.document;

    2、如果iframe嵌套多个iframe,想直接取到最顶层的iframe

        var selfDocument = window.self.document;

——————— ES5 API ————————

提供全局的JSON对象

1、JSON.parse(): 将字符串转成对象

2、JSON.stringify(): 将对象转成字符串

Array扩展

1、push(): 向数组最后插入内容   unshift():向数据最前面插入一项

2、pop(): 删除数组最后一项内容  shift(): 删除数组第一项内容

    var arr = [1, 2, 3];   
    console.log(arr.pop());     // 3
    console.log(arr)    // [1, 2]

3、reverse(): 数组顺序颠倒

4、sort(): 排序

    let arr = [1, 123, 23, 4, 125, 6, 2, 31];
    arr.sort(function(v1, v2) {
        return v1 < v2 // 从大到小排列
    })

5、concat(): 两个数组进行合并, 也可以拷贝成为一个新数组,而不是带指向

    var arrA = [1,2,3];
    var arrB = arrA.concat();
    arrB.push(5,6,7);
    console.log(arrA);  // [1,2,3]
    console.log(arrB);  // [1,2,3,5,6,7]

6、slice(开始,结束): 返回一个子数组,  如果结束参数不传为从开始取到最后的值

    let arr = [125, 123, 31, 23, 6, 4, 2, 1];
    let newArr = arr.slice(2, 5);  
    console.log(newArr, arr);        // [31, 23, 6]    [125, 123, 31, 23, 6, 4, 2, 1]

7、splice(): 用于替换、插入、删除

    splice(1,3): 删除 下标1-3的数据
    splice(3,0, 'insert'): 插入 在位置3一个'insert'字符串
    splice(2,4, 'replce'): 替换 将2-4的数组用 'replce'符

8、indexOf(): 查找数组中指定的字位的位置,未找到返回-1

    var arr = [1,2,3,4,5,6];  arr.indexOf(3);         // 返回2

9、lastIndexOf(): 查找数组中指定的字位的位置,从后向前查找,未找到返回-1


* 迭代方法

10、every(): 每一项为true,结果返回true

    // 数组中是否包含大于2的数
    var num = [1,2,3,2,1];
    var result = num.every(function(item,index,array) {    // item: 1, index: 0, array: [1,2,3,2,1]
        return (item > 2);
    })
    console.log(result);        // true


11、some(): 有一项为true就不会往下执行,并返回true

    var dwarfPlanets = ["ceres", "pluto", "haumea", "makemake", "eris"];
    var result = dwarfPlanets.some(function(element) {
        return (element === "pluto");
    });   
    console.log(result)     // true


5、filter(): 条件中返回true结果,重新返回一个新数组

    var arr = [1, 2, 3, 2, 5, 7];
    var result = arr.filter(function(item,index,array){
        return (item > 2);
    })
    console.log(result);        // [3, 5, 7];


6、forEach(): 遍历数组, forEach无法跳出循环, 只能通过try...catch

    var arr = ['lulu', 'siguang', 'mama', 'baba'];
    arr.forEach(function(item, index, arr){  // lulu  0  ["lulu", "siguang", "mama", "baba"]
        console.log('name:'+item, index, arr);
    })


7、map(): 将每次return的数据,最终组成一个数组返回

    var srcColors = [
        {r: 255, g: 255, b: 255 },
        {r: 128, g: 128, b: 128 },
        {r: 0,   g: 0,   b: 0   }
    ];

    var newColor = srcColors.map(function(item, index, arr){         
        return item.r;
    })
    console.log(newColor);        // 返回 [255, 128, 0]


8、reduce(上次执行的结果,当前值,当前索引,数组对象)、reduceRight(): 归并数组,每次循环都会返回上一次值和当前值

    var val = [1,2,3,4,5];
    var sum = val.reduce(function(prev, cur, index, arr){   // prev 第一次执行的是1, 第二次执行的就是上次1+2返回的结果
        return prev + cur;   
    })
    console.log(sum);   // 15

对象属性和方法

1、__proto__: 对象实例与prototype之间的连接,原型链

2、prototype: 原型,公用的,节省内存开支,查找先去对象本身找属性和方法,如果没有到prototype下查找

3、constructor: 保存用于创建当前对象的构造函数名

4、toString()、valueOf()

5、delete: 删除对象属性

6、hasOwnProperty(propertyName): 判断对象属性是否在对象中(而不是prototype原型中) var obj = {name: 'aaa'}; obj.hasOwnProperty('name')

    function Persion(){
        this.name = 'siguang';
    }
    Persion.protoType = {
        age: 35,
        getName: function(){
            return this.name;
        }
    }
    let oPer = new Persion();
    oPer.hasOwnProperty('name');        // true
    oPer.hasOwnProperty('age');            // false

7、isPrototypeOf(object): 判断传入的对象是否是传入对象的原型

    var o = new Object();
    Object.prototype.isPrototypeOf(o)

8、instanceof: 用来判断一个构造函数的prototype属性是否在另一个检测对象的原型链上

    class A {};
    let oA = new A():
    console.log(oA instancof A);        // true

9、in: 属性是否在对象中能访问,返回true或false

    function Persion(){
        var sex = '男';
        this.name = 'siguang';
    }
    Persion.prototype.age = 'haha';

    var p1 = new Persion();
    console.log('name' in p1);      // true
    console.log('age' in p1);       // true
    console.log('sex' in p1);       // false;


10、Object.create(o, p): 可以创建一个干净的对象,给o对象创建一个prototype,如果p对象存在

    var oA = Object.create(null);    // 创建一个干净的对象,没有__proto__属性
    var oB = {};        // 存储__proto__

    function Car(desc){
        this.desc = desc;
        this.color = 'red'
    }

    Car.prototype = {
        getInfo: function(){
            return `color: ${this.color}, desc: ${this.desc}`
        }
    }

    // 注意这里的name : {value: 'lulu'} 必须是对象,必须是value在根一个值,要不报错
    var child = Object.create(Car.prototype);
    child.desc = 'aaa';
    child.color = 'bbb';

    // 改变子类不会影响到父类
    console.log(child);
    var childCar = child.getInfo();
    console.log(childCar)       // color: bbb, desc: aaa

    var oCar = new Car('ccc');
    console.log(oCar.getInfo());    /// color: red, desc: ccc

    1) Object.create()与new Object()的区别

        var Base = function () {}
        var o1 = new Base();
        var o2 = Object.create(Base);

        Object.create(null) 是创建一个空对象,这个对象不继承Object.prototype原型链上的属性或方法


11、Object.defineProperty(obj, prop, descriptor): 对象新增或修改一个属性会执行set()、get()方法来通知

    参数: obj 目标对象     prop需要定义的属性      descriptor该属性拥有的特性,可设置的值有

    descriptor的值: 

        value 属性的值,默认为 undefined。

        writable 该属性是否可写,如果设置成 false,则任何对该属性改写的操作都无效(但不会报错),默认为 false。

        get 一旦目标对象访问该属性,就会调用这个方法,并返回结果。默认为 undefined。

        set 一旦目标对象设置该属性,就会调用这个方法。默认为 undeinfed。

        configurable 如果为false,则任何尝试删除目标属性或修改属性以下特性(writable, configurable, enumerable)的行为将被无效化,默认为 false。

        enumerable 是否能在for...in循环中遍历出来或在Object.keys中列举出来。默认为 false。

    Example:
        var obj = {};
        Object.defineProperty(obj, 'name', {
            get: function(){
                debugger;
                // this.name;  
                return 23;
            },
            set: function(newValue){
                debugger
            }
        })

        Object.defineProperty(obj, 'sex', {
            get: function(){
                debugger;
                return '女';
            },
            set: function(newValue){
                debugger
            }
        })

        obj.name = 'sss';           // 调用set()
        console.log(obj.name);      // 调用get()   23

        obj.sex = '男';
        console.log(obj.sex);       // 女


    MVVM的核心: 

        <div>
            <p>你好,<span id='nickName'></span></p>
            <div id="introduce"></div>
        </div>

        <script type="text/javascript">
            // 视图控制器
            var userInfo = {};
            Object.defineProperty(userInfo, "nickName", {
                get: function(){
                    return document.getElementById('nickName').innerHTML;
                },
                set: function(nick){
                    document.getElementById('nickName').innerHTML = nick;
                }
            });

            Object.defineProperty(userInfo, "introduce", {
                get: function(){
                    return document.getElementById('introduce').innerHTML;
                },
                set: function(introduce){
                    document.getElementById('introduce').innerHTML = introduce;
                }
            })

            userInfo.nickName = "siguang";
            userInfo.introduce = "我是"+ userInfo.nickName +",我来自黑龙江,..."
        </script>

    https://segmentfault.com/a/1190000004346467


12、Object.defineProperties: 与defineProperty相同就是可以设置多个属性

    let book = { year: 2004, edit: 1}
    Object.defainProperyies(book, {
        year:{
            get: function(){},
            set: function(){}
        },
        edit: {
            get: function(){},
            set: function(){}
        }
    })


13、Object.getPrototypeOf(object): 调用父类原型上的方法

    // 定义一个父类
    function PersonA(){
        this.methodA = function(){ 
            alert("a");
        }
    }
    PersonA.prototype.methodB = function(){
        alert('b');
    }

    // 定义一个子类
    function Man(){
        this.m1 = function(){
            //getPrototypeOf只有继承父类的时候才可以调用其方法
            Object.getPrototypeOf(this).methodA();        
        }
    }

    Man.prototype = new PersonA();
    Man.prototype.m2 = function(){
        Object.getPrototypeOf(this).methodB();
    }

    var man = new Man();
    man.m1();        // a
    man.m2();        // b


14、Object.keys(obj): 将对象obj下所有的属性的key,返回一个数组,用可以用它来判断是数组是否为空

    Object.keys(obj).length 是否等于0

15、Object.getOwnPropertyDescriptor():     

Date对象

var od = new Date();    // 创建当前中国标准时间 Thu Apr 27 2017 18:39:17 GMT+0800 (CST)
var od = new Date('2017-04-27 18:40:00');   // 指定时间 返回当前标准时间 Thu Apr 27 2017 18:40:00 GMT+0800 (CST)

1、getTime(): 返回当前毫秒数

2、setTime(): 以毫秒设置时期

    var od = new Date(); 
    od.setTime(12312312312332); 
    console.log(od);        // Mon Feb 29 2360 22:45:12 GMT+0800 (CST)

3、getFullYear()、setFullYear(): 获取或设置年份

4、getMonth()、setMonth(): 获取或设置月份,值需要+1

5、getDate()、setDate(): 获取或设置日

6、getDay(): 返回星期几,值是0-6

7、getHours(): 小时

8、getMinutes(): 分钟

9、getSeconds(): 秒

Number对象

1、toFixed(): 将值格式化小数点后几位

String对象

1、length: 字符串长度

2、charAt(): 返回指定位置的字符  'abcde'.charAt(3)  'd'

3、chartCodeAt(): 返回指定位置的字符编码

4、concat(): 两个字符串拼接

5、split(): 将字符串以什么为分割,并返回为一个数组

截取

6、slice(begin,end): 截取字符串指定开始和结束位置的字符并返回, 可以接受负数

7、substring(begin,end): 截取字符串从开始到结束,

8、substr(begin, length): 返回一个指定开始到一个结束长度的字符

位置

9、indexOf(): 查找指定字符所在的位置

10、lastIndexOf(): 从后向前查找指定字符的位置

11、trim(): 删除前后空格  str.replace(/^\s*|$\s*/g, '');

12、toLocaleUpperCase(): 转成小写字母

13、toUpperCase(): 转成大写字母

正则

14、search(reg): 搜索正则中匹配字符的位置,没有返回-1

15、match(reg): 将匹配的正则返回一个数组

    let text = "cat, bat, sat, fat";
    let om = text.match(/.at/g);        // ["cat", "bat", "sat", "fat"]

16、exec():

17、replace(reg, 替换字符): 替换指定字符

Math

1、min()、max(): 返回最小、最大值

舍入

2、ceil(): 向上舍入

3、floor(): 向下舍入

4、round(): 四舍五入

5、random(): 随机数 0-1之间

6、abs(): 绝对值

7、sin()、cos()

Global对象

encodeURI()、encodeURIComponent()

前端动画实现种类

1、纯粹的CSS3: transition/animation+transform(animate.css)

2、JS+CSS3 transition或者animation: 这里第一种一样,只是通过js里add class和remove class去增加或者移除对应的动画

3、纯粹JS控制时间轴: 第一和第二种都是自带时间轴,使用 setInterval / setTimeout / requestAnimationFrame 不断地修改 DOM 的 style 属性产生动画

整理

1、==、===

    '100' == 100;     // true;    undefined == null; 因为JS会将两个值转换为相同类型
    '100' === 100;     // false

    == 是先将数值转换后在进行比较,JS的一个设计缺陷、 === 不转换数值进行比较


2、 while和do...while 

    do...while 不管条件是否成立都会执行一次
    var cont = 0;
    do{
        cont++;
        console.log(cont);                // 1;
    }while(cont > 10);


3、break 退出循环、continue 退出当前循环开始下一循环

| http://kangax.github.io/compat-table/es5/ ES5兼容表
| https://developer.mozilla.org/zh-CN/docs/Web/API/Element/className API
| https://segmentfault.com/a/1190000000515151
| https://segmentfault.com/a/1190000005653355
| https://msdn.microsoft.com/zh-cn/library/dn342818(v=vs.94).aspx
| http://www.alloyteam.com/2016/05/javascript-timer/ js运行机制

JS作用域和整理经验

作用域

一、示例

    console.log(str);        // 输出undefined  因为读取的是解析器预先存储的str,还没有被赋值
    var str = 1;         


二、示例2

    alert(a);        // 弹出的是function a(){ alert("2")}
    var a = 1;
    function a(){
        alert("2")
    }

    预解析会保存a = undefinded,和 a = function a(){alert("2")},
    在变量与函数名相同时,输出的结果函数优先级高于变量名


三、示例3

    var a = 1;
    function a(){
        alert("2");
    }

    // 报错,因为a被定义成变量,typeof a 返回的是number,如果 var a;不能定义值那么a()是成功的
    a();


四、示例4

    var a = 1;
    function fn1(){
        alert(a);
        // 注意这里因为是使用var声明所以执行数预解析器才会把它单独存储起来,
        // 如果将var去掉,a=2改成了赋值这样会改变外部的a的值,下面输出的就是1,2
        var a = 2;
    }

    fn1();                        // undefined
    console.log(a);        // 1


五、示例5

    function foo(){
        return fn1;

        function fn1(){};
        var fn1 = 10;
    }

    var f = foo();

    // 输出 function fn1(){};    因为调用foo函数时,return  fn1因为变量还未定义所以 直接调用的函数
    alert(f);                


六、示例6

    var  myname = "global"; // 全局变量
    function fun() {
        alert(myname);             // "undefined",如果函数内不在定义myname就会找全局的变量,但函数本身已经定义了,预编译会先将变量定义成undefined        
        var myname = "local";
        alert(myname);             // "local"
    }
    fun();


七、示例7

    <script>
        window.name = 'globalName';

        var getName = function(){
            return this.name;
        }

        getName();         // 'globalName'
    </script>


八、示例8

    <script>
        window.id = 'window';

        document.getElementById('divA').onclick = function(){
            alert(this.id);            // output "divA"

            var callback = function(){
                return this.id;        // output "window"
            }
            callback();            // 指针指向window
        }
    </script>


 九、示例9

    1、var getName;
        console.log(getName)    // undefined

        getName()                // Uncaught TypeError: getName is not a function

        var getName = function() {
            console.log('wscat')
        }

    2、var getName;
        console.log(getName)    // function getName() {console.log('oaoafly')}

        getName()                // oaoafly

        function getName() {
            console.log('oaoafly')
        }


十、bind()

    <script>
        window.id = 'window';

        document.getElementById('divA').onclick = function(){
            alert(this.id);

            var obj = {
                id: 'objId',
                callback: function(){
                    return this.id;         // 'divA'
                }.bind(window)                // 通过bind来将callback内的this指向window
            }

            console.log(obj.callback());    // 'window'
        }
    </script>


十一、严格模式下的this

    <script>
        function fun(){
            'use strict'
            alert(this);        // 返回 'undefined', strict模式下this不会指向全局
        }

        fun();
    </script>


十二、箭头函数下的this指向

    let Template = {
        test(){
            console.log(this);        // this指向Template

            document.querySelector("#showThis").onclick = () =>{
                // 如果非箭头函数this应该指向 #showThis
                // 箭头函数不是指向调用者,所以指向了Template
                console.log(this);    
            }
        }
    }
    Template.test();

构造函数

1、函数本身是对象也是构造函数

2、直接挂载到函数下,是对象的属性和方法

    function Foo(){};
    Foo.username = '111';     // 注意这里Foo的属性不能为name因为被name被函数的名所占用
    Foo.getName = function(){ console.log(this.username) };

    // 调用
    Foo.getName();        // 111

3、在构造函数的内部属性和方法

    function Foo() {
        this.username = '111'
    }
    Foo.username = '222';

    // 调用
    console.log(new Foo().username);    // 111

<script>
    function Foo() {
        getName = function() {
            console.log(this);
            console.log(1);
        }

        console.log(this);
        return this;
    }
    Foo.getName = function() { // 这里只是Foo对象的方法,而不是构造函数的方法,
        console.log(2);
    }

    // Foo.prototype.getName = function() {
    //     console.log(3);
    // }

    var getName = function() {
        console.log(4)
    }

    function getName() {
        console.log(5)
    }

    Foo.getName(); // 2    Foo.getName=function(){}  是存到Foo下的方法,Foo.getName()可以取到
    getName(); // 4     如果一个作用域下有var的变量名与函数名相当,var的作用域提升高于function
    Foo().getName();     // 1  因为Foo()被调用,定义中加了return this,Foo指向的是window全局,getName没有var升明,所以为全局,所以相当于window.getName(),Foo中如果不加return this那么就会报错,因为Foo没有链式调用,所以this断了
    getName(); // 1   因为上面已经将Foo内的getName()提升成全局,所以会赋盖掉var getName、function getName定义的全局方法

    // var ofo = new Foo;
    // ofo.getName();   // 3

    // Foo既是一个对象也是一个构造函数
    new Foo.getName();             // 2  先执行Foo.getName(),因为"."运算符优先于new运算符,所以这时候Foo只是一个对象并不是构造函数的实例,所以会调用对象下的方法
    new Foo().getName();         // 1  先执行new Foo()构造函数,然后在构造函数下去找getName方法,Foo构造函数方法没有getName()所以到prototype下去找
    new new Foo().getName();     // 1  与上面相同
</script>

对象拷贝并不引用指针

有两种方法,一是使用for...in将一个对象拷贝到另一个对象

另一种方法是使用Object.assign()

let objA = {
        name: 'siguang',
        age: 30
}
let objB = Object.assign({}, objA);
objB.name = 'lulu';         // lulu
console.log(objA.name);     // siguang

对象的深拷贝和浅拷贝

浅拷贝就是对象之间还存引用关系,深拷贝就是两个对象之间没有引用关系

一、浅拷贝

    const a = {t: 1, p: 'gg'};
    const b = a;
    b.t = 3;
    console.log(a);     // {t: 3, p: 'gg'}
    console.log(b);     // {t: 3, p: 'gg'}

二 、深拷贝

    1、Object.assign() 方法是将两个对象合并,并返回一个新对象

        **** 注意assig()只能拷贝一层,多层结构还是浅拷贝 ****

        const c = {t: 1, p: 'gg'};
        const d = Object.assign({}, c);
        d.t = 3;
        console.log(c);     // {t: 1, p: 'gg'}
        console.log(d);     // {t: 3, p: 'gg'}

    2、Object.create() 将拷贝的内容入到prototype下,对象和数组都适用

        对象:

            var oA = {
                name: 'sg',
                age: 33
            }
            var oB = {};
            oB = Object.create(oA);

            oB.eat = 'bread';

        数组:

            var oA = [1,2]
            var oB = [];
            oB = Object.create(oA);

            oB.push(3);            // oB.length;   3        

    3、jQuery.extend()

        let oa = {a: 1, b: 2}; let ob = {};  
        $.extend(ob, oa); 
        ob.b = 3; 
        console.log(oa, ob);        // oa: {a: 1, b: 2}、 ob: {a: 1, b: 3}

数组的深拷贝

一、concat()方法

    var arrA = [1,2,3];
    var arrB = arrA.concat();
    arrB.push(5,6,7);
    console.log(arrA);  // [1,2,3]
    console.log(arrB);  // [1,2,3,5,6,7]

二、slice()方法

    var arrA = [1,2,3];
    var arrB = arrA.slice();
    arrB.push(5,6,7);
    console.log(arrA);  // [1,2,3]
    console.log(arrB);  // [1,2,3,5,6,7]

两种方法都是回返一个不带指向的新数组

三、使用扩展运算符...

    let a1 = [1, 2, 3];
    let a2 = [...a1];
    a2.push(4);

    console.log(a1);        // [1, 2, 3]
    console.log(a2);        // [1, 2, 3, 4]

对象处理

一、查看是否是一个空对象

    // 使用keys来查看对象中所有的kyes并返回一个数组,如果数组为度为0则对象为空
    var obj = {}; 
    var Len = Object.keys(obj);         
    console.log(Len.length);

二、查看对象中属性是否存在

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

判断数据类型

function isType(data, name){ 
    return Object.prototype.toString.call(data) === `[object ${name}]` 
}
isType({}, 'Object');            // true;

数组处理

一、数据去重

    1、普通方法

        function clearRepeat(arr){
            var newArr = [], obj = {};
            for(var i=0; i<arr.length; i++){
                if(!obj[arr[i]]){
                    obj[arr[i]] = '';        // 对象属性相同会直接覆盖
                    newArr.push(key);        
                }
            }
            return newArr;
        }

        let retArray = clearRepeat([3,2,3,4,5,5,2,2,13,3]);


    2、使用ES6的set()方法,set方法就是不允许数组内有重复的值

        let setValue = new Set([1,2,33,1,22,2,2,4,2,1,2])
        console.log(setValue, Object.prototype.toString.call(setValue));        // {size: 5, [1, 2, 33, 22, 4]}, '[Object Set]'
        let arr = [...setValue];        // [1, 2, 33, 22, 4] 需要进行解构

    http://www.jb51.net/article/46154.htm


二、数组排序

    1、使用sort方法

        var arr = [6,7,5,8,4,2342342,23,234,2,34];
        arr.sort(function(v1, v2){
            return v1 - v2        // 正序
        })
        console.log(arr);


三、返回数组中最大最小值

    let arr = [2,1,423,343,5,67,8];
    let min = Math.min.apply(null, arr);
    let max = Math.max.apply(null, arr);

编写组件并兼容AMD、ES6写法

;(function(root, factory){

    // 判断使用的支持定义模块的方式
    if(typeof define === 'function' && define.amd){
        define(factory)
    }
    else if(typeof exports === 'object'){
        module.exports = factory();
    }
    else{
        root.NProgress = factory();
    }

})(this, function(){
    console.log(`输出内容`);
})

千分位函数

Vue.filter('thousand', function (num, fixed) {
    let n = Number(num)
    if (isNaN(n)) return 0;
    if (fixed && String(n).split('.').length === 2 && String(n).split('.')[1].length > fixed) {
        n = num.toFixed(fixed)
    }
    const str = (n || 0).toString()
    return str.indexOf('.') > -1 ? str.replace(/(\d)(?=(?:\d{3})+\.)/g, '$1,') : str.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
});

小技巧

1、获取arguments参数中的不同

    function execute(name){
        return [].slice.call(arguments, 1);
    }
    execute(1,2,3,4);        // 返回 [2, 3, 4];

2、case语句

    function showTest(type) { 
        switch(type) { 
            case "a":                    // type为a/b/c都执行console.log('ok')
            case "b":
            case "c":
                console.log('ok');
                break;

            default:
                console.log('error');
                break;
        }
    }

兼容不支持的方法

1、 Object.create不支持的处理

    Object.create = Object.create || function(obj){
        var F = function(){};
        F.prototype = obj;
        return new F();
    }

2、bind()

    Function.prototype.bind = Function.prototype.bind || function(){
        var self = this,
                context = [].shift.call(arguments),
                args = [].slice.call(arguments);

        return function(){
            return self.apply(context, [].concat.call(args, [].slice.call(arguments)))
        }
    }

| https://juejin.im/entry/58db95eaac502e0058f8472e
| http://www.iamaddy.net/2015/04/front-end-engineering/ // 前端的发展