前端口试知识点集锦

个人总结的比较周全的前端口试学问点。主假如一些个人认为口试时轻易考到以及日常平凡须要注重的一些学问点。

本人只是对这些学问举行了一个也许的总结,另有一部份手艺还没最先触及,后期会延续增添。假如须要举行深切相识可以依据学问点查询相干的手艺文章。

本文涵盖了以下各个方面的学问:

  • HTML, CSS, JS基本学问

  • 网站机能优化学问

  • 前端项目自动化构建相干学问

  • 算法相干学问

  • 收集与HTTP协定相干学问

  • 前端的平安相干学问

  • 插件编写相干学问

  • JS模块化编程相干学问

Github Repo:
https://github.com/Erichain/Front-End-Interview-Points

延续更新中。迎接fork和star举行完美。

关于前端是什么,以及须要进修什么,移步这里:

Front-End Developer Handbook

HTML部份

docType

  • 混淆情势

  • 规范情势

  • 准规范情势

标签语义化

  • 去掉也许丧失款式的时刻可以让页面显现出清楚的构造

  • 有利于SEO:和搜索引擎竖立优越沟通,有助于爬虫抓取更多的有用信息:爬虫依靠于标签来肯定上下文和各个关键字的权重

  • 轻易其他装备剖析(如屏幕阅读器、瞽者阅读器、挪动装备)以意义的体式格局来衬着网页

  • 便于团队开辟和保护,语义化更具可读性,是下一步网页的主要意向,遵照W3C规范的团队都遵照这个规范,可以削减差异化

块级标签,行内标签

  • 块级:div, ul, li, ol, table, th, tbody, tfoot, tr, pre, fieldset, form, h1-6, p等

  • a, abbr, b, br, code, em, img, input, label, select, textarea, strong等

meta标签

  • 如安在不运用JS的情况下革新页面(http-equiv=”refresh”, content=”time”)

  • 设置页面缓存

  • 挪动端设置

  • etc.

HTML代码优化

  • 标签嵌套层级不要太深,标签只管简约化.如懒加载后将data属性去除

  • 大批图片的懒加载战略,以及一些元素运用ajax在onload后实行耽误加载

  • 对一些js的异步加载

搜索引擎优化SEO

CSS部份

浮动,消灭浮动的要领和道理(4种要领)

  • 运用空标签设置clear: both;

  • 为父级元素设置overflow: hidden;(运用BFC的道理)

  • 运用伪元素,为要消灭浮动的元素增添.clearfix类(引荐)

  • 运用min-height: contain-floats;(不引荐,兼容性不好)

CSS块级格式化上下文

  • 触发前提

    • position属性不为static也许relative

    • float属性不为none

    • 非块级的块级元素(inline-block, table-cell)

    • overflow不为visible

  • 特征

    • 内部的Box会在垂直方向,从顶部最先一个接一个地安排

    • Box垂直方向的间隔由margin决议。属于统一个BFC的两个相邻Box的margin会发作叠加

    • BFC的地区不会与float box叠加

    • BFC就是页面上的一个断绝的自力容器,容器内里的子元素不会影响到外面的元素,反之亦然

    • 盘算BFC的高度时,浮动元素也介入盘算

  • 用途

    • 处置惩罚margin边距叠加题目。为元素零丁建立一个BFC来防备外边距的摺叠

    • 规划

    • 消灭浮动。为包括浮动元素的container建立BFC来消灭浮动

盒子模子(IE盒子模子的区分)

定位

  • 定位和浮动的区分

  • 什么时刻运用定位,什么时刻运用浮动

款式继续

  • 可继续的款式

    • font-size font-family color text-indent

z-index属性

IE浏览器的hack

  • 前提hack

    • <!--[if IE]><![endif]-->

  • 属性hack

    • _ IE6

    • *+IE7

    • +IE6/7

    • .IE8

  • 挑选符hack

    • *IE7

    • _IE6

CSS sprite

  • 削减要求

规划模子

  • 双飞翼规划

  • 圣杯规划

CSS优先级

  • 行内款式 > 内联款式 > 外部款式,ID > Class > Element

  • 设置了!important的款式优先级更高

Flexbox

各个单位的区分(px, em, rem, 百分比)

居中

link和@import的区分

  • link属于XHTML标签,而@import是CSS供应的

  • 页面被加载的时,link会同时被加载,而@import援用的CSS会比及页面被加载完再加载

  • @import只在IE5以上才辨认,而link是XHTML标签,无兼容题目

  • link体式格局的款式的权重 高于@import的权重

怎样将div与图片设置等宽,inline-block元素之间的闲暇怎样处置惩罚

  • 设置父元素font-size为0,再对内里的笔墨零丁设置font-size

  • 全兼容的款式处置惩罚要领

.finally-solve {
    letter-spacing: -4px; /*依据差别字体字号也许须要做肯定的调解*/
    word-spacing: -4px;
    font-size: 0;
}
.finally-solve li {
    font-size: 16px;
    letter-spacing: normal;
    word-spacing: normal;
    display:inline-block;
    *display: inline;
    zoom:1;
}

CSS优化

  • 嵌套层级不要太深,平常三层最多

  • css剖析从右向左,所以最右侧的应该是相对少一点

  • html用了base64的img的话,并不会缓存起来,可以将这个base64的图片放在css文件里,css会缓存,图片就缓存起来了

  • 只管不必子女元素挑选器,最右侧的一层不假如标签,尤其是像div这类异常经常使用的标签

  • 多运用css的继续,而不是每一次都誊写时都悉数重写一遍。写多个css属性时,能连在一起写的就连在一起写

预处置惩罚器

  • Sass

JS部份

严厉情势

  • 'use strict'

  • 不能运用eval()

  • 抑止this的行动

  • 不允许读写evalarguments的值

  • 不允许不测建立全局变量

变量

  • 运用var定义的全局变量不能运用delete删除

  • 无var建立的全局变量可以运用delete删除

  • 隐式范例转换

    • 数字与字符串相加,结果为字符串

    • 数字与字符串相减,结果为数字

    • 比较变量的是不是雷同时,要采纳=====会发作隐式范例转换

    • NaN与任何变量不相等

范例检测

  • typeof

  • instanceof

  • constructor

  • Object.prototype.toString.apply()

作用域

  • 全局作用域

  • 函数作用域

对象

  • hasOwnProperty, isPrototypeOf, propertyIsEnumerable

  • 设置属性(configurable, enumerable, writable, value)

  • 特征

    • 扩大: isExtensible, preventExtensions(是不是可以增添新的属性)

    • 密封: isSealed, seal(是不是可以删除属性,是不是可以设置属性)

    • 凝结: isFrozen, freeze(一切属性是不是可读可写)

  • 定义属性

    • defineProperty, defineProperties

数组

  • 数组的范例检测

  • 数组的要领

    • slice()

    • map()

    • every()

    • some()

    • filter()

函数

  • 柯里化

    • 观点:部份求值(Partial Evaluation),是把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,而且返回接收余下的参数而且返回结果的新函数的手艺

function currying( fn ) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var newArgs = args.concat(Array.prototype.slice.call(arguments));
        return fn.apply(null, newArgs);
    }
}
  • arguments对象

  • JS函数不存在重载,后定义的函数会掩盖先定义的函数

  • 函数挪用情势

    • 要领挪用

    • 函数挪用

    • 构造器挪用

    • apply挪用

new操纵符的道理

运用new关键字来建立实例的时刻,道理以下:

  • 起首,在构造函数内部运用Object.create(constructor.prototype)建立一个对象继续自构造函数

  • 然后,将这个对象援用到this

  • 末了,返回this

闭包

  • 观点

  • 作用

    • 建立匿名实行函数

    • 缓存变量,防备被渣滓接纳

    • 完成函数的封装

  • 运用场景

    • 内部函数接见外部函数的变量

    • 运用闭包替代全局变量

    • 封装相干功用

    • 回调函数

    • 建立私有变量和公有变量

  • 特征

  • 典范例子:列表点击,弹出每一个的index

/* 错误做法 */
var elems = document.getElementById('links').getElementsByTagName('li');

for ( var i = 0; i < elems.length; i++ ) {
    elems[i].addEventListener('click', function ( event ) {
        event.preventDefault();
        alert(i);
    }, false);
}
/* 准确的做法,运用闭包 */
var elems = document.getElementById('links').getElementsByTagName('li');

for ( var i = 0; i < elems.length; i++ ) {
    (function ( index ) {
        elems[i].addEventListener('click', function ( event ) {
            event.preventDefault();
            alert(index);
        }, false);
    
    })( i );
}

this

  • 函数的this的值永远绑定在挪用此函数的对象上

  • 可以运用applycall也许bind转变this值的指向

对象建立的情势和要领及区分

  • 工场情势

/* 瑕玷:没法检测对象的范例 */
var createPerson = function ( name, age, job ) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;

    return o;
};

var person1 = createPerson('Erichain', 21, 'Web');
  • 构造函数情势

/* 瑕玷:每一个要领要在每一个实例上从新建立一遍 */
var Person = function ( name, age, job ) {
    this.name = name;
    this.age = age;
    this.job = job;
}

var person1 = new Person('Erichain', 21, 'Web');
  • 原型情势

var Person = function () {};

Person.prototype = {
    constructor: Person, // 假如这个属性十分主要的话
    name: 'Erichain',
    age: 21,
    job: 'web'
};
var person1 = new Person();
  • 组合构造函数原型情势

  • 动态原型情势

var Person = function ( name, age, job ) {
    this.name = name;
    this.age = age;
    this.job = job;

    if ( typeof this.sayName !== 'function' ) {
        Person.prototype.sayName = function () {
            alert( this.name );
        }
    }
};
  • 寄生构造函数情势

    • 除了运用new来实例化外,与工场情势没区分

    • 不能依靠instanceof来肯定对象范例,平常不提议运用

  • 稳妥构造函数情势

原型和继续

  • 原型链

  • 借用构造函数

function Person( name ) {
    this.name = name;
}

function man() {
    // 继续自Person,可以挑选是不是传入参数
    Person.call(this, 'Erichain');
}
  • 组合继续

  • 原型式继续

  • 寄生式继续

  • 寄生组合式继续

  • new Object()Object.create()的区分

    • Object.create建立的对象直接从他的第一个参数继续,而new Object所建立的对象是从对象的原型上继续

    • 运用Object.create,可以建立一个不继续于任何东西的对象,然则,假如设置someConstructor.prototype = null,那末,这个新建立的对象会继续自Object.prototype

回调函数

变量提拔,函数声明提拔

  • 函数声明优于变量声明

  • 函数声明会掩盖变量声明,然则不会掩盖变量赋值

IIFE(马上实行函数)

  • 在闭包中保留变量状况

  • 模块化

  • IIFE和自实行函数的区分

  • IIFE的几种示意要领

(function () {})();
(function () {}());

!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();

事宜

  • 事宜流

    • 事宜捕捉

    • 处于目的

    • 事宜冒泡

  • 事宜对象(IE的区分)

  • 跨浏览器事宜处置惩罚函数

var EventUtil = {
    getEvent: function ( event ) {
        return event ? event : window.event;
    },
    getTarget: function ( event ) {
        return event.target || event.srcElement;
    },
    addHandler: function ( elem, type, handler ) {
        if ( elem.addEventListener ) {
            elem.addEventListener(type, handler, false);
        }
        else if ( elem.attachEvent ) {
            elem.attachEvent('on' + type, handler);
        }
        else {
            elem['on' + type] = handler;
        }
    },
    preventDefault: function ( event ) {
        if ( event.preventDefault ) {
            event.preventDefault();
        }
        else {
            event.returnValue = false;
        }
    },
    stopPropagation: function ( event ) {
        if ( event.stopPropagation ) {
            event.stopPropagation();
        }
        else {
            event.cancelable = true;
        }
    }
};
  • 事宜播送

  • 事宜托付

<ul id="links">
    <li id="link1">Link1</li>
    <li id="link2">Link2</li>
    <li id="link3">Link3</li>
</ul>
var links = document.getElementById('links');

// 运用之前定义的跨浏览器事宜处置惩罚顺序
EventUtil.addHandler(links, 'click', function ( event ) {
    var target = EventUtil.getTarget(event);
    event = EventUtil.getEvent(event);

    switch ( target.id ) {
        case 'link1':
            // do something
            break;
        case 'link2':
            // do something
            break;
        case 'link3':
            // do something
            break;
    }
});
  • 事宜函数的参数(注重addEventListener()的末了一个参数,假如为false示意在冒泡阶段猎取事宜,假如为true,示意在事宜捕捉阶段猎取事宜)

call, apply, bind(手动完成)

  • call(obj, args), apply(obj, array)

  • callapply支撑低版本浏览器,bind只支撑高版本浏览器

  • bind原生代码完成

if ( !Function.prototype.bind ) {
    Function.prototype.bind = function ( oThis ) {
        if ( typeof this !== 'function') {
            throw new Error('What is trying to be bound is not callable');
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBound = this,
            fNOP = function () {},
            fBound = function () {
                return fToBound.apply(
                    this instanceof fNOP ? this : oThis,
                    aArgs.concat(Array.prototype.slice.call(arguments))
                )
            };

        if ( this.prototype ) {
            fNOP.prototype = this.prototype;
        }

        fBound.prototype = new fNOP();
        return fBound;
    };
}

才能检测

BOM

  • window对象

  • location对象

  • screen对象

  • navigator对象

    • 检测插件navigator.plugins

    • 检测用户代办navigator.userAgent

  • history对象

promise

DOM 操纵

  • 查找

    • document.getElementById

    • document.getElementsByTagName

    • document.getElementsByName

    • document.getElementsByClassName

    • document.querySelector

    • document.querySelectAll

  • 节点关联

    • element.childNodes

    • element.firstChild

    • element.lastChild

    • element.previousSibling

    • element.nextSibling

    • element.parentNode

    • element.appendChild()

    • element.insertBefore()

    • element.removeChild()

    • element.replaceChild()

  • 属性操纵

    • element.getAttribute()

    • element.setAttribute()

  • 款式操纵

    • element.style[PROPERTY_NAME]

    • element.classList

    • element.classList.add

    • element.classList.remove

    • element.classList.contains

    • element.classList.toggle

  • 元素遍历

机能优化

渣滓接纳

  • 援用计数

/* 涌现轮回援用的例子 */
function () {
    var objectA = {},
        objectB = {};

    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}
  • 标记消灭

内存走漏

  • setTimeout 的第一个参数运用字符串而非函数的话,会激发内存走漏

  • 轮回援用

文雅降级和渐进加强

  • 文雅降级:Web站点在一切新式浏览器中都能一般事情,假如用户运用的是老式浏览器,则代码会搜检以确认它们是不是能一般事情。由于IE奇特的盒模子规划题目,针对差别版本的IE的hack实践过文雅降级了,为那些没法支撑功用的浏览器增添候选计划,使之在旧式浏览器上以某种情势降级体验却不至于完全失效

  • 渐进加强:从被一切浏览器支撑的基本功用最先,逐渐地增添那些只要新式浏览器才支撑的功用,向页面增添无害于基本浏览器的分外款式和功用的。当浏览器支撑时,它们会自动地显现出来并发挥作用

JSON

  • JSON.stringify() json序列化为字符串

  • JSON.parse() 将类JSON的字符串转化为JSON对象

XMLHttpRequest对象

  • 一段比较完全的运用原生Javascript完成ajax要求要领

function createRequestObject() {
    if ( window.XMLHttpRequest ) {
        return new XMLHttpRequest();
    }

    // 针对IE
    else if ( window.ActiveXObject ) {
        return new ActiveXObject('Microsoft.XMLHTTP');
    }
}

// 要求的回调函数
function requestCallBack() {
    if ( request.readyState === 4 && request.status === 200 ) {
        console.log(request.responseText);
    }
}

var request = createRequestObject();

request.onreadystatechange = requestCallBack;
// open函数的三个参数分别是要求的要领, 要求的地点, 是不是异步(true示意异步)
request.open('POST', url, true);
request.send(null);

运用Javascript盘算两个日期的时候差

机能测试东西

代码检察东西

  • JSHint

  • JSLint

  • ESLint(针对ECMAScript 2015)

代码紧缩

  • JSMin

  • YUI Compressor

  • Gzip

Javascript原生函数运用

Array.prototype.slice.call()道理

RESTful

浏览器部份

各个浏览器内核

  • IE: Trident

  • Chrome: Webkit, Blink(now)

  • Firefox: Gecko

  • Opera: Presto

sessionStorage,cookie,localStorage

  • cookie 由效劳器天生,可设置失效时候。假如是浏览器端天生的cookie,则在浏览器封闭以后失效;而localStorage除非被消灭,不然永远保留,sessionStorage则在封闭浏览器也许页面以后消灭

  • cookie的大小为4k摆布,localStorage和sessionStorage的大小平常为5MB

  • 与效劳器痛心的时刻,cookie每次都邑携带在http头中,然则其他两个不介入效劳器通讯

  • cookie中最好不要安排任何的明文的东西,其他两个的数据假如提交到效劳器肯定要校验

浏览器的多个标签页之间怎样通讯

关于浏览器缓存

前端平安

  • 防备XSS(跨站点剧本)进击

  • 防备CSRF(跨站点捏造要求进击)

  • 防备跨iframe进击

自动化

npm与bower的区分

gulp流与管道的观点

  • Unix流

  • 管道

    • 管道是一个牢固大小的缓冲区

    • 从管道读数据是一次性操纵,数据一旦被读,它就从管道中被扬弃,开释空间以便写更多的数据

    • 可以把一个历程的规范输出流与另一个历程的规范输入留衔接起来

打包后静态资本途径的修正

gulp和grunt的区分

测试东西

  • Mocha

  • Karma

  • Jasmine

收集学问部份

Ajax

同源战略

  • 同源战略指的是:协定,域名,端口雷同,同源战略是一种平安协定。 指一段剧本只能读取来自统一泉源的窗口和文档的属性

跨域处置惩罚(要领和区分)

  • JSONP

  • document.domain

  • window.name

  • HTML5的window.postMessagewindow.onmessage

HTTP基本学问

  • 前端进阶–让你晋级的收集学问

  • 三次握手

    • 客户端提议衔接探索

    • 效劳端接收到探索要求,向客户端发送确认音讯

    • 客户端获得效劳端的确认音讯以后,再次向效劳端发送确认音讯

  • 一次完全的http要求是怎样的

    • 域名剖析

    • TCP三次握手

    • 提议http要求

    • 效劳器端相应http要求,客户端获得html代码

    • 浏览器剖析html代码,并要求html代码中的资本

    • 浏览器对页面举行衬着显现给用户

框架相干学问

jQuery

Bootstrap,插件道理

  • 栅格规划完成道理

  • .img-responsive完成道理

  • 内联表单完成道理

  • Bootstrap组件完成道理

AngularJS

  • 双向绑定

    • $digest轮回

    • dirty checking

    • $watch

  • MVC

  • 自力作用域

  • 依靠注入

  • 轮回监听

  • ng-ifng-hide/show的区分

    • ng-iftrue的时刻节点才会存在于DOM中

    • ng-show/hide只是掌握节点的显现和隐蔽

  • factoryserviceprovider的区分和关联

    • 运用factory建立的效劳,是一个对象,然后,将要领和属性定义在这个对象上,在返回这个对象,便可以供外部controller挪用了

    • 运用service建立的效劳,是运用new举行实例化的,所以,要领和属性要定义在this上,而且这个效劳会自动返回this

    • 运用provider建立的效劳,是唯一可以注入到config()函数的效劳,可以用来供应模块化的设置。而且,定义在this上的属性和要领,在config函数里才可以接见,从this.$get()函数里返回的属性和要领,才被掌握器所接见

  • ng-click是不是可以运用原生函数

    • 不可以,由于对应的要领不存在于其掌握器中,除非在掌握器中声明

  • ng-repeat数组中有雷同元素的处置惩罚办法

    • 可以增添track by $index

  • $emit$broadcast$on

    • $emit由子级向父级播送,$broadcast由父级向子级播送

  • controllerAs$scope的区分

  • AngularJS的瑕玷

    • 强束缚,进修本钱高

    • 不利于SEO

    • 机能题目

      • 削减监控项

      • 主动设置索引

      • 下降衬着的数据数目

      • 数据扁平化

算法

数组降维

数组去重

  • 最简朴的要领

function removeDuplicate( arr ) {
    var len = arr.length,
        temp = [];

    for ( var i = 0; i < len; i+=1 ) {
        if ( temp.indexOf(arr[i]) === -1 ) {
            temp.push(arr[i]);
        }
    }
    return temp;
}

对象深度复制

function clone( Obj ) {   
        var buf;   
        if ( Obj instanceof Array ) {   
            buf = [];  //建立一个空的数组 
            var i = Obj.length;   
            while ( i-- ) {   
                buf[i] = clone(Obj[i]);   
            }   
            return buf;   
        }
        else if ( Obj instanceof Object ) {   
            buf = {};  //建立一个空对象 
            for ( var k in Obj ) {  //为这个对象增添新的属性 
                buf[k] = clone(Obj[k]);   
            }   
            return buf;   
        }
        else {   
            return Obj;   
        }   
    }  

各个范例的复制

function clone( obj ) {
    var dest;
    
    switch( typeof obj ) {
        case 'undefined':
            break;
            
        case 'number':
            dest = +obj;
            break;
            
        case 'string':
            dest = obj + '';
            break;
            
        case 'boolean':
            dest = obj;
            break;
        
        case 'object':
            if ( obj instanceof Array ) {
                dest = [];

                for ( var i = 0; i < obj.length; i++ ) {
                    dest[i] = obj[i];
                }
            }
            else {
                dest = {};
                for ( var i in obj ) {
                    dest[i] = obj[i];
                }
            }
        
        default:
            break;
    }

    return dest;
}

排序

  • 疾速排序

function quickSort( arr ) {
    var left = [],
        right = [],
        len = arr.length,
        breakPoint = arr[0];

    if ( len === 1 || len === 0 ) {
        return arr;
    }

    for ( var i = 1; i < len; i++ ) {
        if ( arr[i] < breakPoint ) {
            left.push(arr[i]);
        }
        else {
            right.push(arr[i]);
        }
    }

    return quickSort(left).concat(breakPoint, quickSort(right));
}
  • 冒泡排序

function bubbleSort( arr ) {
    var len = arr.length,
        temp;

    for ( var i = 0; i < len - 1; i ++ ) {
        for ( var j = 0; j < len - 1 - i; j++ ) {
            if ( arr[j] > arr[j+1] ) {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }

    return arr;
}
  • 插入排序

function insertSort( arr ) {
    var len = arr.length,
        temp;

    for ( var i = 1; i < len; i++ ) {
        var j;
        temp = arr[i];
        j = i;

        while ( j > 0 && arr[j-1] > temp ) {
            arr[j] = arr[j-1];
            j--;
        }
        arr[j] = temp;
    }
    return arr;
}

去除首尾空格

function removePlace( str ) {
    var reg = /(^s*)|(s*)$/;

    if ( str && typeof str === 'string' ) {
        return str.replace(reg, '');
    }
}

统计字符数目

function charCount( str ) {
    var obj = {},
        len = str.length,
        i = 0;

    for ( ; i < len; i++ ) {
        var val = str.charAt(i);

        if ( obj[val] && obj[val].value === val ) {
            obj[val].count++;
        }
        else {
            obj[val] = {};
            obj[val].count = 1;
            obj[val].value = val;
        }
    }

    for ( var key in obj ) {
        console.log( key + ' is ' + obj[key].count );
    }

    return obj;
}

插件编写

关于插件编写,可参考:jQuery插件库

核心轮播图

弹窗结果

多级菜单

tab切换

Lightbox

Javascript模块化

CommonJS

  • 同步的体式格局加载模块,效劳器优先

  • 运用require加载模块,运用module.exports定义模块

AMD

  • 浏览器优先的体式格局,经由过程异步加载的体式格局完成任务

  • 运用define(['module'], function ( module ) {})加载模块

  • 不兼容 io、文件体系(filesystem)和别的经由过程 CommonJS 完成的面向效劳器的功用

  • 推重依靠前置

  • 关于依靠的模块提早实行

CMD

  • 推重依靠就近

  • 关于依靠的模块耽误实行

  • 运用define(function ( require, exports, module ) {})加载模块

UMD(通用模块定义,Universal Module Definition)

  • 同时支撑 AMD 和 CommonJS 特征

Javascript设想情势

NodeJS

HTML5

CSS3

Websocket

Canvas

    原文作者:Erichain_Zain
    原文地址: https://segmentfault.com/a/1190000004996857
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞