数据类型
基本数据类型:
undefined, null, boolean, number, string
引用类型:
object, function, array, date, regexp
null == undefined //true
undefined派生于null
未初始化或未声明变量typeof都返回undefined
浮点数最高精度17位小数,永远不要测浮点值
保证浮点数计算正确性,使用内置的toPrecision()和toFixed()
任何与NaN的操作都返回NaN
isNaN(NaN); //true
NaN == NaN; //false
数字字符串之前存在+/-都被转为数字
"string".length返回字符串16位字符数,如包含双字节字符,length不准
字符串一旦创建,不能改变,除非销毁原来的字符串,再新增字符串填充
number.toString(2);
转型函数String(),处理对象不知道undefined,null
var a;String(a); //undefined
var b = null; String(b); //null
object实例有以下对象:
constructor;
__proto__;
isPrototypeOf(object);
hasOwnProperty("xxx");
toString();返回object字符串表示
valueOf();返回object自身
var arr = [];
Array.isArray(arr.valueOf()); //true
Array.isArray(arr.toString()); //false
with语句主要为了简化多次编写同一对象
with(location){
var url = href;
}
switch比较值用===
函数体内用arguments访问参数(非Array,类数组对象)
arguments.callee(); //callee为一个指向拥有这个arguments对象的函数
arguments.caller(); //caller为一个指向调用当前函数对象的函数
function a(){
alert(arguments.length);
}
函数参数按值传递,引用类型会复制引用地址
typeof对任何引用类型或null类型都会返回object
typeof undefined; //undefined
instanceof会检测是那种类型的对象,instanceof运算符可以用来判断某个构造函数的prototype属性是否存在于另外一个要检测对象的原型链
typeof null, typeof new Object(), typeof function(){}, typeof [], typeof new Date(), typeof new regExp();都返回object
检测类型用xxx instanceof Type;
js没有块级作用域,访问局部变量更快,无须向上搜索
js有CG,将变量设null切断变量与引用连接释放资源,解除引用
Array的length并非只读
Date的getMonth从0开始
this,始终指向调用函数的对象
匿名函数,定时器中的函数默认this指向window,严格模式下在找不到直接调用者是this为undefined
var x = 1;
function test(){
alert(this.x);
};
test(); //1,test函数在全局调用,this指向全局作用域
var y = {x:2, test:test};
y.test(); //2,test函数被y调用,this指向y
call, apply, bind
用来指定函数中this指向(重设作用域)
var a = {
x:1,
fn:function(arg1, arg2){
alert(this.x);
}
};
var b = a.fn;
b(); //undefined, this指向全局
b.call(a, 1, 2); //1, this指向a对象
b.apply(a, [1, 2]); //1, this指向a对象
var fn = b.bind(a); //bind返回一个函数
fn(1, 2); //1
创建对象
1.构造函数模式
function Person(name){
this.name = name;
};
var p1 = new Person("66");
任何函数,只要通过new操作符调用,就可以作为构造函数
构造函数在没有返回值的情况下,默认返回新对象实例,而通过在构造函数末尾添加return可重写构造函数返回值
问题:每个方法属性都要在每个实例上重新创建一遍
Person中prototype,实例对象p1中的__proto__都指向一个Person Prototype对象
new构建对象的本质
1.创建一个新对象
2.将构造函数作用域分配给新对象
3.执行构造函数,为对象添加属性
4.返回新对象
2.原型模式
function Person(){
};
Person.prototype.name = "77";
var p1 = new Person();
p1.name; //77
var p2 = new Person();
//prototype重赋值,切断Person与原Person prototye对象的联系
Person.prototype = {name: 66};
//77 任然指向原prototype对象
p2.name;
每个函数都有一个prototype,包含可由特定类型的所有实例共享的属性和方法
prototype就是通过调用构造函数而创建的那个对象的原型
prototype.constructor属性包含一个指向prototype所在的指针
每创建一个函数都会自动创建一个Prototype对象
Person.prototype -> Person Prototype
p.__proto__ -> Person Prototype
Person Prototype.constructor -> Person
Person.construct;//Function
Person.prototype.construct://Person原型
p.construct;//Person原型
p.__proto__.construct;//Person原型
function SuperType(){};
var s = new SuperType();
SuperType.constructor; //Function
SuperType.prototype.constructor; //SuperType
s.constructor; //SuperType
s.__proto__.constructor; //SuperType
function SubType(){};
SubType.prototype = new SuperType();
var sub = new SubType();
SubType.constructor; //Function
SubType.prototype.constructor; //SuperType
sub.constructor; //SuperType
sub.__proto__.constructor; //SuperType
确定属性存在于对象还是原型
function hasPrototypeProperty(object, name){
//hasOwnProperty实例属性返回true
//in实例属性或原型属性都返回true
return !object.hasOwnProperty(name) && (name in object);
}
继承
原型链:利用原型让一个类型继承另一个类型的属性和方法(原型指向另一类型实例,另一类型原型又指向另另一个类型实例)原型链为实现继承的主要方法
function SuperType(){}
function SubType(){}
//实现继承的本质为重写原型对象,继承原型属性方法和实例属性方法
SubType.prototype = new SuperType();
1.借用构造函数(实现对实例属性和方法的继承)
function SuperType(arg1){
this.colors = ["red"];
};
function SubType(){
//通过call调用方式创建自己的colors副本
//可给超类传递参数
SuperType.call(this, "66");
};
var s1 = new SubType();
s1.colors.push("blue");
var s2 = new SubType();
2.组合继承
原型链实现对原型属性和方法的继承(所有实例共享的属性方法),借用构造函数实现对实例属性和方法的继承(实例自己的属性方法)
function SuperType(arg1){
this.colors = ["red"];
};
SuperType.prototype.say = function(){};
function SubType(arg1){
//第二次调用SuperType()
SuperType.call(this, arg1);
};
//第一次调用SuperType()
SubType.prototype = new SuperType();
问题:会调用2次超类构造函数,一次是在创建子类型原型时,一次是在子类型构造函数内部
匿名函数(拉姆达函数)
作用:
模仿块级作用域(function(){})(),模块模式
执行环境具有全局性,this常指向全局
递归函数
应始终使用arguments.callee调用自己
作用域链
当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会创建为其创建一个作用域又称为执行上下文(Execution Context),然后每执行一个函数,会建立一个对应的作用域,从而形成了一条作用域链
全局变量默认挂载在window对象下
闭包:有权访问另一个函数作用域中变量的函数
在函数的内部创建另一个函数,就创建了一个闭包,闭包有权访问父级函数内部所有变量,通常函数作用域中所有变量会在函数执行完毕后销毁,但当函数返回了一个闭包,该函数的作用域将一直保存在内存直到闭包函数销毁
闭包应用:
1.模拟类的私有属性
function a(){
var b = 66;
return function(){
b;
}
}
2.让变量值始终保持在内存
var fs = [];
var fs2 = [];
for(var i = 0; i<10; i++){
fs.push((function(arg){
return function(){return arg};
})(i));
fs2.push(function(){return i});
}
fs[2](); //2, var i 换成let i效果同
fs2[2]();//10
闭包会携带父级函数的全部作用域链,因此比其他函数占用更多内存
IIFE(立即执行函数表达式)
1.模块封装
2.jquery等自定义插件
事件
事件冒泡,IE的事件流叫冒泡,从下往上
事件捕获,Netscape提出的另一种事件流,从上往下
DOM事件流:事件捕获,处于目标阶段,事件冒泡,IE不支持
DOM0级事件处理程序
btn.onclick = function(){};
DOM2级事件处理程序,第3个参数为true,在捕获阶段调用事件处理程序, 为false表示在冒泡阶段调用事件处理程序
btn.addEventListener("click", function(){}, false);
IE事件处理
btn.attachEvent("onclick", function(){});
btn.detachEvent("onclick", function(){});
取消冒泡
e.stopPropagation();
IE window.event.cancelBubble = true;
事件代理
JavaScript事件代理则是一种简单的技巧,通过它你可以把事件处理器添加到一个父级元素上,这样就避免了把事件处理器添加到多个子级元素上。当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。这主要得益于浏览器的事件冒泡机制。事件代理用到了两个在JavaSciprt事件中常被忽略的特性:事件冒泡以及目标元素。
function getEventTarget(e) {
e=e||window.event;
return e.target||e.srcElement;
}
页面加载事件
document.ready表示文档结构加载完毕
document.onload表示页面图片,内容都加载完毕
变量提升
javascript变量提升
提升变量自动赋值为null
同源策略
同源指域名,协议,端口相同
限制Cookie, localStrorage, indexDB,DOM,Ajax(CORS)
CORS需要浏览器服务器同时支持
简单请求(HEAD, GET, POST),浏览器发现Ajax为跨域,自动添加Origin标识本次请求来源(协议+域名+端口)
服务器端发现Origin指定源在许可范围内,会返回一个带有Access-Control-Allow-Origin字段,浏览器知道请求没问题,否则出错
Access-Control-Allow-Credentials是否允许发送Cookie,默认Cookie不包括在CORS请求中(Access-Control-Allow-Origin必须指明明确域名,服务器指定该字段为true,同时Ajax请求中要打开xhr.withCredentials = true)
非简单请求(PUT,DELETE,Content-Type为application/json),会在正式通信前,增加一次HTTP预检请求(preflight),先询问服务器域名是否在许可名单,以及可以使用哪些HTTP动词,头信息字段。服务器端许可后,会返回
Access-Control-Request-Method:PUT(许可的HTTP请求方法)
Access-Control-Request-Headers:X-Custom-Header(许可的自定义头部信息)
Access-Control-Max-Age:指定预检请求有效时间(可选)
XMLHttpRequest
var xmlhttp = null;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}
else if(window.ActiveXObject){
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
if(xmlhttp != null){
xmlhttp.onreadystatechange = stateChange;
xmlhttp.open("GET", url, true);
xmlhttp.send(null);
}
function stateChange(){
//readyState为0(uninitialized)到4(complete)变化
if(xmlhttp.readyState == 4){
if(xmlhttp.status == 200){
}
}
}
网络安全
XSS攻击(跨域脚本攻击)
栗子:在输入框输入
防范:输入过滤为安全的html,Html encode
CSRF攻击(跨站请求伪造攻击)
栗子:盗用受害人身份
防范:添加输入验证码操作,Refer Check,请求带token服务器端验token
SSL攻击(中间人攻击)
伪造服务器,伪造秘钥证书
SSL协议
1.使用证书确认用户和服务器
2.数据尾部添加校验码,防止中途篡改
3.加密传输数据和校验码,防止中途窃取