前端知识体系整理(不断更新)
数据类型:
Undefined
,
Null
,
Bollean
,
Number
,
String
Object
、Array
Date
、RegExp
typeof输出(以下六个值之一):
undefined
var x;
typeof(x); // "undefined"
boolean
var x = false;
typeof x; // "boolean"
string
var x = '';
typeof x; // "string"
number
var x = NaN;
typeof x; // "number"
object
var x = {};
var y = [];
var z = null;
typeof x; // "object"
typeof y; // "object"
typeof z; // "object"
function
var x = function() {};
typeof x; // "function"
'1'-0; // 0, equal to Number(1)
var n = 5;
console.log(n.toString(2)); // 快速进制转换
对象 -> 简单类型(参考JavaScript 类型转换)
隐式转换:除Date外,统统是先
valueOf
、再
toString
(Date
在
+
和
==
时优先转化为字串):
[] + 1; // 1
valueOf
,再toString()
,都不存在则返回NaN
:Number({}); // NaN
valueOf()
,再取valueOf()
,都不存在则抛异常:String({}); // [object Object]
createElement
,
createTextNode
,
createDocumentFragment
,
appendChild
removeChild
,
removeNode
getElementById
,
getElementsByTagName
,
getElementsByClassName
,
querySelector
,
querySelectorAll
,
parentNode
,
firstChild
,
lastChild
,
nextSibling
,
previousSibling
,
childNodes
replaceChild
,
insertBefore
getAttribute
,
setAttribute
,
data-x
,
jQuery.attr()
,
jQuery().prop()
,
jQuery().data()
,
classList
,
innerHTML
,
innerText
,
textContent
事件绑定与解绑:addEventListener(type, handler, flag)
,
attechEvent('on' + type, handler)
,
removeEventListener(type, handler)
,
detechEvent('on' + type, handler)
事件流:
function handler(e) {
var e = e || window.event;
var target = e.target || e.srcElement;
// e.currentTarget 指的是绑定事件的元素,不一定和target是同一个
}
比较(参考
全面理解面向对象的 JavaScript)
Class
的面向对象,对象由类Class
产生:如Java
、C#
prototype
的OOP,对象由构造器(构造函数)constructor
利用原型prototype
产生生成js对象:
var Preson = {
name: 'xiaoming',
age: 15
};
this.city
,在内存里生成了多次var Person = function(name, age) {
// 全部标记为私有成员
this.name = name;
this.age = age;
this.city = 'shen zhen';
};
var xm = new Person('xiaoming', 15);
var xl = new Person('xiaoli', 20);
prototype
模式:每次实例化只增加私有的对象属性(或方法)到实例中,所有实例的公有属性(或方法)指向同一个内存地址var Person = function(name, age) {
// 对象的私有成员
this.name = name;
this.age = age;
};
Person.prototype.city = 'shen zhen';// 共有成员
对象的继承
非构造函数的继承:继承可以简单使用对象之间的深、浅拷贝
构造函数的继承:大多是基于原型的继承,但是阅读性差,也不利于扩展
function A(name) {
this.name = name;
}
function B(name, age) {
A.apply(this, arguments);
this.age = age;
}
function A() {}
A.prototype.propA = 'a';
A.prototype.propB = 'b';
function B() {}
B.prototype = A.prototype; // 原型链引用,改成B.prototype = new A();可以解决引用的问题
B.prototype.propB = 'B'; // 函数重载
B.prototype.constructor = B;
var b = new B();
A、B的prototype引用同一个地址,实时上A的prototype.constructor已经被改成了B
function extend(sub, sup) {
var _f = function() {};
_f.prototype = sup.prototype;
sub.prototype = new _f();
sub.prototype.constructor = sub;
sub.super = sup.prototype;// 保存原构造函数
_f = null;
}
A.prototype.propA = 'a';
A.prototype.propB = 'b';
function B() {}
extend(B, A);
构造函数的继承,重要的是理解原型链prototype chain
,继承基本就是原型链的拷贝或者引用。
理解原型链prototype chain
:
function A() {}
function B() {}
B.prototype = new A();
function C(x, y) {}
C.prototype = new B();
var c = new C();
c.__proto__ === C.prototype;// true
B.prototype.__proto__ === A.prototype;// true
B.__proto__ === B.prototype;// true
A.__proto__ === Function.prototype;// true
A.prototype.__proto__ === Object.prototype;// true
_proto属性_:对象的__proto__
指向Object.prototype
,Function对象的__proto__
指向构造函数的prototype。
类式继承:本质上还是使用构造函数的prototype
,封装成类,典型的例子是jQuery之父John Resig的Simple JavaScript Inheritance,其他类库也有各自的实现
var Person = Class.extend({
init: function(gender) {
this.gender = gender;
}
});
var Teacher = Person.extend({
init: funciton(gender, name) {
this._super(gender);
this.name = name;
},
role: 'teacher',
speek: function() {
console.log('Hello, i am a %s.', this.role);
}
});
var Student = Person.extend({
init: funciton(gender, name) {
this._super(gender);
this.name = name;
},
role: 'student',
speek: function() {
console.log('Hello, i am a %s.', this.role);
}
});
foo(1, 2);
function foo(a, b, c) {
console.log(arguments.length);//2 实际传入的参数
console.log(foo.length);//3 期望传入的参数
}
function foo() {} // 函数申明
var foor = function foo() {};// 函数表达式
执行顺序:解析器会率先读取函数声明,所以在任何代码执行前函数申明可用
fn(2); // 4
function fn(n) {console.log(n);}
fn(2); // 4
function fn(n) {console.log(n*n);} //重载
fn(2); // 4
var fn = function(n) {console.log(++n);};// 函数表达式,按照申明的顺序执行
fn(2); // 3
arguments, callee, caller, apply, call
arguments
,类数组,类似的还有NodeList、classList等对象arguments.callee
,返回正在执行的Function
对象的一个引用function foo(n) {
console.log(arguments.callee.arguments.length);
console.log(arguments.callee.length);
}
foo(1, 2, 3);// 分别打出3,1
arguments.caller
,返回调用这个Function
对象的Function
对象的引用apply
和call
,传参不同,功能相同,都是把Function
对象绑定到另外一个对象上去执行,其内的this
指向这个对象作用域
var
声明的变量var
申明的变量,会自动升级为全局变量挂到window上var
申明的变量是window对象的一个属性闭包
function foo() {
var x = 1;
return function fn() { // closure
return x;
}
}
var bar = foo();
console.log(bar()); // get the local variables in foo
this:函数中的this
始终指向函数的调用者
function foo(x) {
this.x = x;
}
foo(1); // 调用者是window,也可以window.foo()
console.log(window.x); // 1
var o = {};
o.foo = foo;
o.foo(2); // 调用者是o
console.log(o.x); // 2
console.log(window.x); // 1
这里有一篇详细的例子
请求过程
xhr.open()
xhr.send()
xhr.abort()
HTML
的就绪状态:xhr.readyState
xhr.responseText
RUST API:POST
,
GET
,
PUT
,
DELETE
HTTP状态码
XHR2
postMessage
跨域通讯可阅读yuanyan同学的jQuery编程实践
html
结构:SEO友好,利于维护html
结构:嵌套过复杂的结构会导致浏览器构建DOM树缓慢html
最小化:html大小直接关系到下载速度,移除内联的css,javascript,甚至模板片,有条件的话尽可能压缩html,去除注释、空行等无用文本img
、link
、script
、iframe
元素的src
或href
属性被设置了,但是属性却为空):部分浏览器依然会去请求空地址@import
引入样式表:IE低版本浏览器会再页面构建好之后再去加载import的样式表,会导致白屏head
里,脚本延后引入避免css表达式:css表达式会不断的重复计算,导致页面性能下降
避免AlphaImageLoader滤镜:这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器(引自【高性能前端1】高性能CSS)
合并图片(css sprites)
尽量避免通配符选择器:CSS选择器是从右到左进行规则匹配,基于这个机制,浏览器会查找所有同类节点然后逐级往上查找,知道根节点,这样效率很低
尽量避免属性选择器(\*=
,
|=
,
^=
,
$=
,
~=
):正则表达式匹配比基于类别的匹配慢
移除无匹配的规则:缩减文档体积;浏览器会把所有的样式规则都解析后索引起来,即使是当前页面无匹配的规则
合并多条可合并的规则,使用简写:
.box {margin-top: 10px; margin-left: 5px; margin-bottom: 15px;} /* bad */
.box {margin: 10px 0 15px 5px;} /* better */
尽量减少或最少化对DOM的操作(脱离文档流对DOM进行修改)
DocumentFragement
批量修改,最后再插入文档谨慎操作节点集合NodeList(images
,
links
,
forms
,
document.getElementsByTagName
):
缓存NodeList以及NodeList.length的引用
尽量操作元素节点(DOM节点如childNodes
,
firstChild
不区分元素节点和其他类型节点,但大部分情况下只需要访问元素节点引自《高性能JavaScript》):
children
代替childNodes
childElementCount
代替childNodes.length
firstElementChild
代替firstChild
读写分离,减少layout:
x = box.offsetLeft; // read
box.offsetLeft = '100px'; // write
y = box.offsetTop; // read
box.offsetTop = '100px'; // write
这个过程造成了两次的layout,可做如下改造:
x = box.offsetLeft; // read
y = box.offsetTop; // read
box.offsetLeft = '100px'; // write
box.offsetTop = '100px'; // write
repeat
):box.style.width = '100px';
box.style.heihgt = '50px;';
box.style.left = '200px';
三个操作都会重新计算元素的几何结构,在部分浏览器可能会导致3次重排,可做如下改写:
var css = 'width: 100px; height: 50px; left: 200px;';
box.style.cssText += css;
var a = $('#box .a');
var b = $('#box .b');
可以缓存$('#box')
到临时变量:
var box = $('#box');
var a = box.find('.a');
var b = box.find('.b');
var $P = Jx().UI.Pager.create();// 同样可以先缓存结果
缓存Ajax数据,利用本地存储或者临时变量,存储不需要实时更新的数据
设置HTTP
Expires
信息
Web Worker
$('#box'); // document.getElementById | document.querySelector
$('div'); // document.getElementsByTagName
querySelector
的浏览器很慢$('input[checked="checked"]'); // 比较快
$('input:checked'); // 较慢
$.fn.find
查找子元素,因为find
之前的选择器并没有使用 jQuery 自带的 Sizzle 选择器引擎,而是使用原生API查找元素$('#parent').find('.child'); // 最快
$('.child', $('#parent')); // 较快,内部会转换成第一条语句的形式,性能有一定损耗
$('#parent .child'); // 不如上一个语句块
$('div.foo .bar'); // slow
$('.foo div.bar'); // faster
$('.foo .bar .baz');
$('.foo div.baz'); // better
document.getElementById('el')
比$('#el')
块$('div').click(function(e) {
// 生成了个jQuery对象
var id = $(this).attr('id');
// 这样更直接
var id = this.id;
});
$('#user')
.find('.name').html('zhangsan').end()
.find('.city').html('shenzhen').end()
.removeClass('none');
var box = $('.box');
box.find('> .cls1');
box.find('> .cls2');
var $el = $('.box').detach();
var $p = $el.parent();
// do some stuff with $el...
$p.append($el);
// 性能差
$.each(arr, function(i, el) {
$('.box').prepend($(el));
});
// 较好的做法
var frag = document.createDocumentFragment();
$.each(arr, function(i, el) {
flag.appendChild(el);
});
$('.box')[0].appendChild(flag);
$('ul li').on('click', fn);
// better
$('ul').on('click', 'li', fn);
使用事件代理(委托),当有新元素添加进来的时候,不需要再为它绑定事件,这里有demo可以查看效果。
keep-alive