JS变量
类型
a、值类型:Number、String、Boolean、Null、Undefined、Symbol(ECMAScript中定义)存在栈中(占据空间固定,按值访问)
b、引用类型:Object、Array、Function等
存在堆中(值大小会变化,变量存储的是其指针)
1
2
3
4
5
6
7
8
9
10
11
12
13
14//对象深度复制问题
window.deepClone = function(obj){
var newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return obj;
} else if(window.JSON){
newobj = JSON.parse(JSON.stringify(obj));
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
}
}
return newobj;
};c、判断
1、typeof [{},[],null,new Function(),new Date()] // object 能有效判断string,number,symbol,boolean,undefined,function 2、A instanceof B 判断A是否B的实例 [] instanceof Array; //true [] instanceof Object; //true 注意网页中多个框架(iframe)情况,各自有不同的构造函数 ES5提供了Array.isArray(arr)方法确认某个对象本身是否为Array类型 3、constructor 在Fn的prototype属性下并指向Fn本身(只能函数和其直接构造函数) null,undefined不存在constructor, constructor不稳定,当重写prototype后,原有的constructor引用会丢失,constructor会默认为Object var f = new F(); f.constructor === F //true 因为f是F的实例,F.prototype上的constructor传递到了f上 4、toString 对于Object对象,直接调用toString(),就能返回字符串[object Object],其他需要用call/apply Object.prototype.toString() ; // [object Object] Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(new RegExp()) ; // [object RegExp] Object.prototype.toString.call(document) ; // [object HTMLDocument] Object.prototype.toString.call(window) ; //[object global] window 是全局对象global的引用
1
2
3
4
5
6
7
8
9function type(sth){
var ty=Object.prototype.toString.call(sth);
var res=ty.slice(8,ty.length-1);
return res;
}
var o={};
var arr=[1,2];
console.log(type(o)); // Object 实测object也可调用call判断
console.log(type(arr)); // Arrayd、原文链接参考
计算
强制类型转换1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//字符串拼接
var a=10+10 // 20
var b=10+'10' // 1010
//==
100 == '100' // true
0 == '' // true
null == undefined //true
//if判断(除以下六种情况,全部转换为true)
if(undefined || null || 0 || NaN || '' || false){
alert(true);
}
// === 和 == 使用,除以下情况外,尽量全部用 ===
if(obj.a == null){
//jquery源码写法,相当于(obj.a === null || obj.a === undefined)
}JS内置函数及对象
函数:Object,Array,Boolean,Number,String,Function,Date,RegExp,Error等
对象:JSON,MathJSON.stringify({a:10,b:20}) //对象转字符串 JSON.parse('{"a":10,"b":20}') //字符串转对象
数组API:
forEach 遍历所有元素 every 判断所有元素是否都符合条件 some 判断是否有元素符合条件 sort 排序 map 对元素重新组装,生成新数组 filter 过滤符合条件的元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35var arr = [1,3,2];
arr.forEach(function(item,index){
console.log(index,item);
})
var res = arr.every(function(item,index){
if(item < 4){
return ture; //若所有元素都小于4,返回true
}
})
console.log(res); //true
var res = arr.some(function(item,index){
if(item < 2){
return ture; //若有元素小于2,返回true
}
})
console.log(res); //true
arr.sort(function(a,b){ //此方法会改变自身
//从小到大(默认)
return a - b;
//从大到小
//return b - a;
})
console.log(arr); //[1,2,3]
var arrm = arr.map(function(item,index){ //此方法返回新数组,原数组不变
return '<h1>' + item + '</h1>';
})
console.log(arr); //[1,2,3]
console.log(arrm); //["<h1>1</h1>","<h1>2</h1>","<h1>3</h1>"]
var arrf = arr.filter(function(item,index){ //此方法返回新数组,原数组不变
if(item >= 2){
return true;
}
})
console.log(arr); //[1,2,3]
console.log(arrf); //[2,3]对象API:
1
2
3
4
5
6
7
8
9
10
11var obj = {
x:1,
y:2,
z:3
}
var key;
for(key in obj){
if(obj.hasOwnProperty(key)){
console.log(key,obj[key]);
}
}
原型
构造函数
1
2
3
4
5
6
7
8function Foo(name){ //构造函数一般大写
this.name = name;
this.other = 'otherAttr';
// return this //默认有此行
}
var f = new Foo('zhangsan');
//new Foo()的时候,Foo里面的this变为空对象,属性赋值后返回this(this指向创建的新对象f)
f instanceof Foo //判断f的直接构造函数是否为Foo原型规则
所有引用类型(数组,对象,函数),都有对象特性:可自由扩展属性
所有引用类型(数组,对象,函数),都有__proto__属性:属性值是普通对象
所有的函数,都有一个prototype属性:属性值是普通对象
所有引用类型(数组,对象,函数),__proto__属性值指向它的构造函数的”prototype”属性值
当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它构造函数的prototype)中找1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32循环遍历自身属性
var item;
for(item in foo){
//高级浏览器已经在for in中屏蔽了来自原型的属性,但还是建议加上以下判断
if(foo.hasOwnProperty(item)){
console.log(item);
}
}
//原型继承实例,封装DOM查询
function Emt(id){
this.emt = document.getElementById(id);
}
Emt.prototype.html = function(val){
var emt = this.emt;
if(val){
emt.innerHTML = val;
return this //此句可用于链式操作
}else{
return emt.innerHTML;
}
}
Emt.prototype.on = function(type,fn){
var emt = this.emt;
emt.addEventListener(type,fn);
return this //此句表示其后还可跟链式调用
}
var div1 = new Emt('div1');
//console.log(div1.html());
//链式操作
div1.html('<h1>Hello</h1>').on('type',function(){
alert('clicked');
})
作用域和闭包
执行上下文
范围:一段< script>或一个函数
全局:变量定义、函数声明 (一段< script>)
函数:变量定义、函数声明、this、arguments (函数)
执行前,变量定义和函数声明被提前,this要在执行时才能确认1
2
3
4
5
6
7
8
9
10var a = {
name:'A';
fn:function(){
console.log(this.name);
}
}
a.fn() //this === a
a.fn().call({name:'B'}) //this ==={name:'B'}
var fn1 = a.fn
fn1() // this === windowthis:作为构造函数执行,作为对象属性执行,作为普通函数执行(window),call apply bind
1
2
3
4
5
6//call,apply,bind都能改变this指向(bind必须用函数表达式形式)
var fn2 = function(name){
alert(name);
console.log(this) //this === {y:20}
}.bind({y:20})
fn2('zhangsan')作用域
无块级,只有函数和全局作用域1
2
3
4
5
6
7
8
9
10
11
12
13
14if(true){
var name = 'zhangsan'; //name不属于if代码块私有,在if外面能访问到此变量
}
console.log(name) //zhangsan
var a = 100; //全局变量
var b = 200;
function fn(){
var a = 200; //函数内部变量,与全局变量a互不影响
console.log('fn',a); // fn 200
//b在此函数作用域中未定义(会去父级作用域找),它是自由变量
console.log(b); // 200
}
console.log('global',a); // global 100
fn();闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//函数作为返回值
function F1(){
var a = 100;
return function(){
console.log(a); //100
}
}
var f1 = F1();
var a = 200;
f1(); //100
//函数作为参数传递
function F2(fn){
var a = 200;
fn();
}
F2(f1); //100异步和单线程
1
2
3
4
5
6
7
8
9
10//同步会阻塞程序运行(区别与异步)
console.log(1);
alert(2); //程序在此卡住,什么时候点击,什么时候继续
console.log(3)
//异步不会阻塞
console.log(1);
setTimeout(function(){ //程序跳过定时任务,继续执行后面代码,空闲时提出来执行
console.log(2);
},1000)
console.log(3);单线程特点:一次只能干一件事
在可能发生等待的情况并且等待过程不能像alert一样阻塞程序运行的时候需要异步定时任务:setTimeout,setInterval 网络请求:ajax请求,动态<img>加载 事件绑定
JS-Web-API
- JS基础
ECMA262标准
特点:表面看并不能用于工作中开发代码类型,原型,作用域,异步
- JS-web-api
W3C标准中关于JS的规定有:
JS内置全局函数和对象DOM操作 BOM操作 事件绑定 ajax请求(包括http协议) 存储
JS变量中提到的和window,document,navigator等
- JS(浏览器执行的JS)构成
JS基础(ECMA262标准)
JS-web-api(W3C标准)
(服务器执行的js,如nodejs包含”ECMA262标准”,但不包含”W3C标准”) DOM
本质:浏览器把拿到的html文件结构化成浏览器和JS都可识别的模型,即为DOM
数据结构:树结构
节点操作:获取DOM节点 document.getElementById('id') //元素 document.getElementsByTagName('body')[0]; //集合 document.getElementsByClassName('.con'); //集合 document.querySelectorAll('p'); //集合 prototype(JS对象属性) var pList = document.querySelectorAll('p'); var p = pList[0]; //p为js对象 console.log(p.style.width); //获取样式 p.style.width = '100px'; //修改样式 console.log(p.className); //获取class p.className = 'p1'; //修改class //获取nodeName和nodeType console.log(p.nodeName); //P console.log(p.nodeType); Attribute(改html文档标签属性) var pList = document.querySelectorAll('p'); var p = pList[0]; //p为js对象 p.getAttribute('data-name'); p.setAttribute('data-name','imooc'); p.getAttribute('style'); p.setAttribute('style','font-size:30px;');
结构操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//新增节点
var div1 = document.getElementById('div1');
var p1 = document.createElement('p'); //创建新节点
p1.innerHTML = 'this is p1';
div1.appendChild(p1); //添加新节点到div1
var p2 = document.getElementById('p2');
div1.appendChild(p2); //移动已存在的节点p2到div1
//获取父元素
var parent = div1.parentElement;
//获取子元素
var child = div1.childNodes; //注意text节点
var child = div1.childNodes[0].nodeType; // 3 (通用)
var child = div1.childNodes[1].nodeType; // 1
var child = div1.childNodes[0].nodeName; // #text (浏览器差异)
var child = div1.childNodes[1].nodeName; // P
//删除节点
div1.removeChild(child[1]); //注意空text节点BOM
浏览器类型
解析url
内置对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//navigator
var ua = navigator.userAgent; //此信息可被浏览器公司修改,不能保证真实性
console.log(ua); //"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36"
var isChrome = ua.indexOf('Chrome'); //简单判断浏览器
//screen(获取屏幕像素,与浏览器缩放比有关,不同浏览器又有差异)
console.log(screen.width); //1920(Edge,100%), 1536(Edge,125%), 1536(Chrome,控制台下调整缩放比无效)
console.log(screen.height); //1080(Edge,100%), 864(Edge,125%), 864(Chrome)
//location(浏览器会将url中的中文编码,以谷歌搜索vuejs为例,自定义hash:#123)
console.log(location.href); // https://www.google.com/search?q=vuejs&oq=vuejs&aqs=chrome..69i57j0j35i39j0l2j69i65.1977j0j8&sourceid=chrome&ie=UTF-8#123
console.log(location.protocol); // https:
console.log(location.host); // www.google.com
console.log(location.pathname); // /search
console.log(location.search); // ?q=vuejs&oq=vuejs&aqs=chrome..69i57j0j35i39j0l2j69i65.1977j0j8&sourceid=chrome&ie=UTF-8
console.log(location.hash); // #123
//history
history.back(); //前进
history.forward(); //后退事件
通用事件绑定:1
2
3
4
5
6
7
8
9
10
11
12
13
14var btn = document.getElementById('btn1');
//IE低版本使用attachEvent绑定事件
btn.addEventListener('click',function(event){
console.log('clicked');
})
function bindEvent(ele,type,fn){
ele.addEventListener(type,fn);
}
var a = docunment.getElementById('link1');
bindEvent(a,'click',function(e){
e.preventDefault(); //阻止默认事件
e.stopPropatation(); //阻止事件冒泡
alert('clicked');
})事件冒泡(默认)
Element.addEventListener('click',fn,false); //第三个参数不写默认为false,即默认冒泡 点击子元素,会依次触发自身和父级元素的对应事件 e.stopPropatation(); //阻止事件冒泡
事件捕获
Element.addEventListener('click',fn,true); 点击子元素,如果父元素注册了事件捕获,则会先触发父元素事件
代理(点击div1里面的多个a元素):代码简洁、减少浏览器内存占用
1
2
3
4
5
6
7var div1 = document.getElementById('div1');
div1.addEventListener('click',function(e){
var target = e.target; //获取点击的html元素
if(target.nodeName === 'A'){
alert(target.innerHTML)
}
})ajax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23var xhr = new XMLHttpRequest;
//open方法
xhr.open('get,'/api',true); //默认异步true
xhr.send(null);
//post方法
xhr.open('post','/api');
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send('username=name&&pwd=123');
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
alert(xhr.responseText);
}
}
//readyState=0,(未初始化)还未调用send()方法
//readyState=1,已调用send()方法,正在发送请求
//readyState=2,send()执行完成,已收到全部响应内容
//readyState=3,解析相应内容
//readyState=4,完成解析,可调用
//status=2XX,成功处理请求,(200)
//status=3XX,需要重定向,浏览器直接跳转
//status=4XX,客户端请求错位,(404)
//status=5XX,服务器端错误
持续更新