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运行机制