js笔记【自用】

每行代码分号以及换行会被认为一行代码,若是:
alert()alert()
这样浏览器认为当行代码没结束,报错。
var a = prompt(“请输入密码”,[默认是String]);//只能接受String
短路语法
①逻辑与&&
将逻辑与比喻成串联电路,判断过程,想象成电流通过的过程。
 
电流通过:如果a为真,电流能够通过流通到b,结果就是b;如果a为假,电流不能通过,停留在a,结果为a。
1	console.log(true && "你好");
2	console.log(true && 0);
3	console.log("" && 0);
4	console.log(undefined && "hello");
5	console.log("hello" && false);
6	console.log(Infinity && 4);
 
②逻辑或||
将逻辑或比喻成并联电路,判断过程,想象成电流通过的过程。


 
电流经过时:如果a为真,电流直接从a完成循环,结果为a;如果a为假,电流从a不能经过,流经到b,我们结果是b。
1	console.log("hello" || false);
2	console.log("hello" || true);
3	console.log(false || true);
4	console.log(false || false);
5	console.log("" || 4);
6	console.log(0 || "你好");
7	console.log(NaN || "你好");
8	console.log(Infinity || undefined);
 
总结:(逻辑与 && ) 如果a能被转换为false,那么返回a;否则,返回b。
   	(逻辑或 || ) 如果a能被转换为true,那么返回a;否则,返回b。
逻辑运算顺序:先非,与,最后或。
练习1:false || !false && false || true;
false || !false && false || true;
1	=  false || true && false || true
2	= false || false || true
3	= false || true
4	= true
练习2:4 && "hello" || !false || !true && null;
sum = 4 && "hello" || !false || !true && null;
1	    = 4 && “hello”  || true || false && null
2	    = “hello” || true || false
3	    = “hello” || false
4	    = “hello”

闭包
函数本身就是一个闭包。函数定义的时候,就能记住它的外部环境和内部语句,每次执行都会参考定义时的密闭环境。
闭包天生存在,并不需要什么特殊的结构才存在,只不过我们必须要刻意地把函数放到其他的作用域中调用,才能明显的观察到闭包性质。
函数的闭包,记住了定义时所在的作用域,这个作用域中的变量不是一成不变的。
function outer(){
	var a = 1;
	function inner(){
		a = a + 1;
		console.log(a);
	}
	return inner;
}

var inn1 = outer();
var inn2 = outer();

inn1();//2
inn1();//3
inn1();//4
inn2();//2  每次执行都会参考定义时的密闭环境,因此定义时a是1,调用一次后就是2

Number
Number();parseInt();parseFloat();//都是讲String转为number,后2个是遇到非数字则停止,
如:parseInt(1.9);//输出1 parseInt(string, radix) radix该值介于 2 ~ 36 之间可理解为自定义进制
十进制可以省略写开头0,十六进制0x或0X,八进制0x或0X
如:parseFloat(0.1234e2.34);//输出0.1234*(10*10)  忽略.34  只取第一个浮点左右有效数字
true false null 参与运算是被隐式转换为1 0 0
underfined参与运算时输出NaN
	纯数字字符串和数字进行数学运算时,会进行隐式转换(加法还是连接作用)
	boolean和null进行数学运算时,会进行隐式转换,加法也会隐式转换。
	NaN,Infinity参与数学运算时不会进行隐式转换。
比较运算符:得到的都是boolean类型
	纯数字字符串参与比较运算时,会进行隐式转换。
	boolean和null进行比较运算时也会隐式转换,但是null在等于或者是全等于时不是转换为0。
	NaN,Infinity参与比较运算时不会进行隐式转换。
1	null >= 0;     //true
短路语法:
逻辑与&&:串联电路。当a为真,取值是b;当a为假时,取值是a;
逻辑与||:并联电路。当a为真,取值是a;当a为假时,取值是b;
Js浮点数计算误差分析:
我们要站在计算机的角度思考0.1+0.2的问题,计算机懂的是二进制,而不是十进制,先把0.1和0.2转为二进制看看:
0.1	---- 0.0001 1001 1001 1001(循环下去)
0.2	---- 0.0011 0011 0011 0011(循环下去)
现实中有循环的数字,但计算机不允许,所以就是那几处理时会舍入处理,双精度小数部分最多支持52位,所以两者相加得到如下:
	0.01001100110011001100110011001100110011001100转为二进制就成了0.30000000000000004
处理方法:把需要的数字升级(乘以10的n次幂)程计算机能够精确是别的整数,等计算完毕再降级(除以10的n次幂),这是大部分编程语言处理精度问题的通用方法
//加法函数,用来得到精确的加法结果 
//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。 
//调用:accAdd(arg1,arg2) 
//返回值:arg1加上arg2的精确结果 
function accAdd(arg1,arg2){ 
	var r1,r2,m; 
	try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} 
	try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} 
	m=Math.pow(10,Math.max(r1,r2));
	return (m.mul(arg1)+m.mul(arg2))/m; 
}
//减法函数,用来得到精确的减法结果 
//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的减法结果。 
//调用:accSub(arg1,arg2) 
//返回值:arg1减去arg2的精确结果
function accSub(arg1,arg2){
     var r1,r2,m,n;
     try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
     try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
     m=Math.pow(10,Math.max(r1,r2));
     //last modify by deeka
     //动态控制精度长度
     n=(r1>=r2)?r1:r2;
     return ((m.mul(arg1)-m.mul(arg2))/m).toFixed(n);
}
//乘法函数,用来得到精确的乘法结果 
//说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 
//调用:accMul(arg1,arg2) 
//返回值:arg1乘以arg2的精确结果 
function accMul(arg1,arg2) 
{ 
	var m=0,s1=arg1.toString(),s2=arg2.toString(); 
	try{m+=s1.split(".")[1].length}catch(e){} 
	try{m+=s2.split(".")[1].length}catch(e){} 
	return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m) 
}
//除法函数,用来得到精确的除法结果 
//说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 
//调用:accDiv(arg1,arg2) 
//返回值:arg1除以arg2的精确结果 
function accDiv(arg1,arg2){ 
	var t1=0,t2=0,r1,r2; 
	try{t1=arg1.toString().split(".")[1].length}catch(e){} 
	try{t2=arg2.toString().split(".")[1].length}catch(e){} 
	with(Math){ 
		r1=Number(arg1.toString().replace(".","")) 
		r2=Number(arg2.toString().replace(".","")) 
		return (r1/r2)*pow(10,t2-t1); 
	} 
}
//给Number类型增加一个add方法(加法),调用起来更加方便
Number.prototype.add = function (arg){ 
	return accAdd(arg,this); 
}
//给Number类型增加一个sub方法(减法),调用起来更加方便
Number.prototype.sub = function (arg){ 
	return accSub(arg, this); 
} 
//给Number类型增加一个mul方法(乘法),调用起来更加方便
Number.prototype.mul = function (arg){ 
	return accMul(arg, this); 
} 
//给Number类型增加一个div方法(除法),调用起来更加方便
Number.prototype.div = function (arg){ 
	return accDiv(this, arg); 
}


事件
(js事件一般on开头,jQuery事件相反没有on开头)
4,失去焦点和获得焦点
$('chk').focus();//jQuery事件
$('chk').blur();//jQuery事件
οnclick=""//js事件
οndblclick=""//js事件
参考:js事件参考手册  &  jQuery事件参考手册
另外,html的a标签也可以调用函数,如下:
<a href="javascript:void(0);" οnclick="functionname()" >aaa</a>
		<a href="javascript:functionname('dd')" >bbb</a>
		<a href="javascript:;"οnclick="functionname()" >ccc</a>
		<a href="#"οnclick="functionname()" >ddd</a>
<a href="http://www.baidu.com" οnclick="functionname()" >aaa</a>//先执行事件再跳转,
<a href="http://www.baidu.com" οnclick="return functionname()" >aaa</a>//当函数返回false时候,将不再跳转
			var div = document.getElementsByTagName('div')[0];
			div.onclick = function(){
				this.style.backgroundColor = 'green';//只能绑定一个,多次写后者生效
			}
			div.addEventListener('click',function(){
				console.log(1111);//匿名函数可绑定多个,按顺序执行
			},false);
函数的执行符
/*
			 * 打印testM输出M  和 方法体
			 * 打印testM()输出M 和 underfined
			 * */
			var testM = function(){
				alert('M');
			}
			function testN(){
				alert(testM);
alert(testM());
			}
函数可以作为参数传递
自定义类:
		person=new Object();//等同于person={};
		person.firstname="Bill";
		person.lastname="Gates";
		person.age=56;
		person.eyecolor="blue";
		alert(person.firstname + " is " + person.age + " years old.");
自定义对象:
			person=new Object();
			person.firstname="Bill";
			person.lastname="Gates";
			person.age=56;
			person.eyecolor="blue";
			alert(person.firstname + " is " + person.age + " years old.");
switch
	switch(表达式){
	    case 值1:
	       执行体1;
	       break;
	    case 值2:
	       执行体2;
	       break;
	 ……
	    default:执行体;  //前面case 值都不匹配时 ,执行的语句。也可以不写,直接跳出
	         break;(这个break可有可无)	
	}
注意:切记不可case 1 || 3 || 5 || 7 || 8 || 10 || 12;//计算机遇见表达式,会先计算。该表达式计算后输出是1
do while
do while语句和for语句不同,需要将循环变量设置在do while语句外。否则会重置变量。造成死循环。
1	var i = 3 ;
2	do{
3		console.log(i);
4		i += 4;
5	}while(i < 15)
while
1	// 变量需要书写在循环外
2	var i = 3 ;
3	while(i < 13){
4	    console.log(i);
5	    i += 4;
6	}
break &continue
我们可以给外层循环添加一个标签,让break引用
1	waiceng: for(var i = 0 ; i < 5 ; i ++){
2		for(var j = 0 ; j < 5 ; j ++){
3			if(j == 2){
4				break waiceng;//break只能管理i,不能管理j
5			}
6			console.log(i,j);
7		}}
遇见continue,结束该次循环,立即执行下一次循环。也是只能控制本层的循环不能控制外层循环。
如果想控制外层循环需要使用标签。
1	waiceng: for(var i = 0 ; i < 5 ; i ++){
2		for(var j = 0 ; j < 5 ; j ++){
3			if(j == 2){
4				continue waiceng;//continue只能管理i,不能管理j
5			}
6			console.log(i,j);
7		}}
引用数据类型
在进行赋值时,而是将变量的指针(地址),赋值给另一个变量。当一个变量改变时,另一个变量也会受影响。

1	var fun1;
2	function fun(){
3		console.log(1);
4	}
5	fun1 = fun;
6	fun1.xixi = "嘻嘻";
7	fun.haha = "哈哈";
8	
9	console.log(fun.xixi);
10	console.log(fun1.haha);
 
如果代码中有变量名,函数名相同时
函数名会优先提升。也就是说将这个相同的标识符给了函数。
String		
举例统一基于var str =("hello world");
var str = 'hello';str.charAt(4);//获取指定位置字符,返回o
str.substr(start,[length]);//在字符串中抽取从 start 下标开始的指定数目的字符
str.substring(start,[stop]);提取字符串中介于两个指定下标之间的字符
以下两种查找指定字符串内容方法可以不写下标,默认从左往右查找,
若没有找到返回-1 (类似java中IO流读完字节时返回-1)
str.indexOf('l',[4]);//[从下标4开始]找字符'l'的位置,返回9
str.lastIndexOf(findstr,[index]);//与indexOf相反,从右至左
str.replace(findstr,tostr); 返回替换后的结果
replace
var str = "test-test";//replace的用法
console.log(str.replace("test", "ok"));//ok-test只替换发现的第一个
console.log(str.replace(/test/, "ok"));//ok-test只替换发现的第一个
	console.log(str.replace(/test/g, "ok"));//ok-ok全局替换
	console.log(str.replace("test", "ok").replace("test", "ok").replace("test", "ok"));//ok-ok

str.match(regexp); 用于匹配到的正则或者字符串,返回包含匹配的字符串的数组, 不书写g只会输出匹配到的第一个字符串。
var str = "kkkagbkkkagbkkkabgk";
console.log(str.match("agb"));//["agb", index: 3, input: "kkkagbkkkagbkkkabgk", groups: undefined]
match还可以进行全局匹配;返回所有匹配到的字符串组成的数组。
var str = "a  afjjga       abvvvva       absjkf";
// var reg = /a\s+a/;
var arr = str.match(/a\s+a/g);
console.log(arr);//  ["a  a", "a       a", "a       a"]
str.split(bystr,[howmany]); bystr分割用的字符串 howmany指定返回数组的最大长度,可以省略
var str1 = "jkajkaaajgbkjaaaaaaaaaaakjaag";
var reg = /a+/;
console.log(str1.split(reg));//  ["jk", "jk", "jgbkj", "kj", "g"]
str.reverse(); 反转内容,并不生成新的String
str.search(regexp); 返回匹配的字符串或RegExp的首字符下标,没有全局查找,默认搜索第一个符合的
str.cahrCodeAt(index); 返回指定下标的Unicode编码
Boolean
//underfined null NaN “” 0 false都是false
等值符和等同符区别
等值符:==(会自动转换类型,如:1==”1”,因为会将”1”强转为Number(“1”),那就是数字1了)
等同符:===(如:1===1,类型,值都要相同)
三目运算符:表达式?条件1:条件2;
variable = boolean_expression ? true_value : false_value ;
该表达式主要是根据 boolean_expression 的计算结果有条件地为变量赋值。如果 Boolean_expression为 true,就把 true_value 赋给变量;如果它是 false,就把 false_value 赋给变量。
换言之,三目运算符的结果是一个返回值,然后可以赋值给变量而已。
underfined和defined区别
var z;
console.log(typeof x);//undefined
console.log(x);//报出异常 x is not defined 之后的代码不会执行
console.log(z); 
其他方法
console.log(typeof(a));//输出变量a的类型

js中"=="是类型相同,值不同; "==="是类型和值都相同

js中表达式(如if(a>0){})可以是任意表达式, 即可以是任何类型, 将所有类型分为两组:
true和"非空值"都被认为是true
false和例中5个特殊类型都被认为是false,分别为:[0 null "" undefined NaN]

isNaN 是不是非数字 

alert(parseFloat("12.3a1b2c3"));//左至右开始转换为整数,打印12.3,类似方法还有parseInt
var num = 23.5678;
num.toFixed(2); //23.57 没有参数则默认参数为0, 注意是转为字符串

Array
var arr = [1,2,3];
var arr = new Array();
var arr = new Array([1,2,3]);
var arr = [[],[],[]];

数组倒转与排序
str,sort([sortFunc()]);  
function sortFunc(a,b){rerturn a-b}
若是不手动指定排序方法,默认按照字符串排序,哪怕是排序数字,32也会在132之前
console.log(JSON.stringify(arr));//数组转json
1. 将string字符串转换为JSON对象:		JSON.parse(jsonStr)
2. 将JSON对象转换为字符串string:		JSON.stringify(obj)

arr.toString();//? - str
arr.push('a');//添加元素至末尾
arr.splice(index,n,['b','c']);//删除下标从index开始的n个元素,[并逐个添加元素至末尾]
arr.slice(start,[end]);//返回start开始到end的数组,end可选
var jsonStr = JSON.stringify(param);
var jsonLength = 0;
for(var temp in param){
	jsonLength++;
}
for(var i = 0;i<jsonLength;i++){
			
}
Math
Math.PI   
Math.E   
Math.round(3.56);//4 返回与 x 最接近的整数
Math.sqrt(x)开方
Math.max(a1,a2,a3)取最大
alert(Math.ceil(123.4));//124向上取整
alert(Math.floor(123.4));//123向下取整
alert(Math.pow(num.power));//num的power的次方
alert(Math.round(123.5));//124四舍五入
alert(Math.random()*9000+1000);//一个随机的整数部分为4位的数
Date
getDate()   setDate()  
getTime()  setTime()

创建正则表达式
var regex = /^\d{3,6}$/flags;  常用
var regex = new RegExp("regex",["flags"]);
flags标识有:
g: 设定为全局模式,第n次调用该方法,返回第n个匹配字符串
非全局模式下,始终从str中找到第一个匹配字符串
i: 忽略匹配中的大小写检测
RegExp.exec(str); 检测str中指定的RegExp,并返回RegExp
RegExp.test(str);   检测字符串是否有指定的RegExp,返回ture和false

js函数没有重载,因为所有传递的参数都保存再argument数组对象中,哪怕没有参数
可访问argument[i]
argument.length

全局对象:window
5个Browser对象:history,location,screen,document,navigator
 
几个全局(window可不写)方法:
window.alert("你好"); 确认框
window.confirm("您是否确定吗"); 确定取消框
window.prompt("请输入一句话");  输入消息确定框
window.open();
window.close();
几个全局方法(函数):
toString(), parseInt(), parseIFloat(), 
周期定时器
var id = setInterval(执行方法,间隔时间(ms));
clearInterval(id);
一次性定时器
var id = setTimeout(执行方法,间隔时间(ms)):
clearTimeout(id);
alert(screen.availWidth+":"+screen.availHeight+":"+screen.width":"screen.height);
history方法
history.forword();        history.back();        history.go(-2);
1,window.location.href=“url”:改变url地址;
2,window.location.replace(“url”):将地址替换成新url,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,你不能通过“前进”和“后 退”来访问已经被替换的URL,这个特点对于做一些过渡页面非常有用!
3,window.location.reload():强制刷新页面,从服务器重新请求!
navigator属性
navigator.userAgent;  返回用户浏览器关于            

p.nodeName;
p.nodeType; 节点类型: 元素1 属性2 文本3 注释8 文档9
双标签都有内容 p.innerHTML;  获取/设置HTML           p.innerText;   获取/设置中间的纯文本
表单控件都有值 ul.value;

根据属性名 获取/设置/移除 标签属性值
img.getAttribute("src");           
img.setAttribute("src","../images/01.jpg")
img.removeAttribute("src");    

三个特殊的设置元素属性
img.className           img.id         img.style

改变HTML;样式
p.style.color="red";
p.style.fontSize="20px";


节点 创建 追加 插入 移除 查询

var input = document.createElement("input");  创建新的空节点(input)
父节点.appendChild(被移除的子节点);  节点挂到DOM树下(获取父节点)
父节点.insertBefore(被移除的子节点, 弟弟节点);  节点插入到DOM树下(获取父亲ul,弟弟li)
父节点.removeChild(被移除的子节点);  从DOM树移除节点
还可以设置节点信息:
input.type = "text";
input.value = "值";
input.style.color = "red";

7, οnclick="add_shoppingcart(this);"  this指向当前按钮对象
//调用此函数时传入了this,声明参数来接收它,参数名不能叫this(关键字)
function add_shoppingcart(button){}
8, window.οnlοad="a();" 加载页面自动执行a();
9, οnmοuseοver="鼠标覆盖事件"  οnmοuseοut="鼠标离开事件"
10, οnclick=("鼠标点击时间") = οnmοusedοwn=("鼠标按下事件") + οnmοuseup=("鼠标松开事件");

创建JS对象
1, 直接创建js对象(JSON方法)
var student = {"name":"zhangsan","age":24,"sayjob":function(){alert('grammer')}};
alert(student.name);
alert(student.age);
student.job(); 
2, 工厂方法 :可以重复返回多个对象
	function createObject(){  
	    var object=new Object();  
	    object.username="Tom";  
	    object.password="123";  
	    object.get=function(){  
	        alert(this.username+","+this.password);  
	    }  
	  
	    return object;  
	}  
  
	var o1=createObject();  
	var o2=createObject();  
	o2.username="james";  
	o1.get();  // Tom 123
	o2.get();  // james 123
改进版:因为js的函数定义是指向一个应用的对象,所以每次构建一个object对象,都会构建一个get方法的对象,现在将get方法分离,那么就是多个object对象共用一个get对象,这样就可以节省内存空间
	function get(){  
	  	alert(this.username+","+this.password);  
	}    
	function createObject(username,password){  
        var object=new Object();  
        object.username=username;  
        object.password=password;  
        object.get=get;  
        return object;  
    }  
    var o1=createObject('tom',123);  
    var o2=createObject('james',123);  
    o1.get();  
o2.get();
这种方法的缺点就是不能传递参数,只能在创建后修改属性。另外使用这种方法定义的对象都贡献同样的属性,因为他们都共用了object对象中的prototype对象,所以所有的对象贡献原型中的属性,其中一个更改了属性,也会反映到其他对象中去。

为了解决原型方法中对象贡献属性,可以采用构造方法+原型的方法去构建对象。把属性用构造方法定好。具体方法就用原型设置。
function  Person(name){   
        this.name=name; 
        this.password='888888';  
    }  
    Person.prototype.getInfo=function(){  
        alert(this.name+","+this.password);  
    }  
	var p1=new Person("张三");  
	p1.getInfo(); //abc,888888
	p1.password = "1991-08-02";  //abc,1991-08-02
	p1.getInfo();
3,原型方法property
因为js的所有类都是继承Object,Object中有prototype属性,因此自定义的对象也有prototype属性
function Person(){}
Person.prototype.username="Tom";  
Person.prototype.password="1325";  
Person.prototype.getInfo=function(){  
    alert(this.username+" , "+this.password);  
}  
  
var person=new Person();  
var person2=new Person();  
person.username="James";  
person.getInfo();  
person2.getInfo();
4,动态原型方法
    function Person(username,password){     
	    this.username=username;  
	    this.password=password;  
	    if( typeof Person.first=="undefined" ){//通过设置标志量让getInfo只生成一次对象。  
	        Person.prototype.getInfo=function(){  
	            alert(this.username+" , " +this.password);  
	        }  
	    Person.first=true;     
	    }  
	  
	}  
	var p1=new Person("Tom","123");     
	var p1=new Person("James","abc");  
	p1.getInfo();  
	p1.getInfo();

======绑定事件===============================================
1,直接绑定事件,直接在标签中绑定
2,后绑定事件,对象.onclick = function(event){}
注意: 时间触发后会产生一个event事件,
不同浏览器存在兼容问题,解决方法如下:
function f1(e){
	alert(e.clientX+":"+e.clientY);
}//先接收参数,然后可随意调用

=========事件源==============================================
获取触发事件的事件源,也就是事件的目标节点
IE: e.srcElement
Firefox: e.target
考虑到浏览器兼容问题,此种写法可兼顾
var obj = e.srcElement||e.target;
还可以判断事件源的节点类型: if(obj.nodeName=="INPUT"){...}; 
注意: 打印出的节点类型是大写!!! 
也可以得到事件源的值: obj.value

========取消事件冒泡========================================
假设最底层事件是f1(){}
function f1(e){
	if(){
		e.stopPropagation();	
	}else{
		e.cancelBubble = true;
	}	
}
//{"stopPropagation",function(){}}???????
下面的代码输出什么?
var y = 1;
if (function f(){}) {
    y += typeof f;
}
console.log(y);
正确的答案应该是 1undefined。
JavaScript中if语句求值其实使用eval函数,eval(function f(){}) 返回 function f(){} 也就是 true。
eval 计算表达式字符串,若没有合法表达式和语句,会抛出异常
下面我们可以把代码改造下,变成其等效代码。
var k = 1;
if (1) {
    eval(function foo(){});
    k += typeof foo;
}
console.log(k); 
上面的代码输出其实就是 1undefined。为什么那?我们查看下 eval() 说明文档即可获得答案。
该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。
恰恰 function f(){} 语句的返回值是 undefined,所以一切都说通了。

注意上面代码和以下代码不同。
var k = 1;
if (1) {
    function foo(){};
    k += typeof foo;
}
console.log(k); // output 1function
闭包
老生常谈的问题了,闭包是在一个函数里声明了另外一个函数,并且这个函数访问了父函数作用域里的变量。
下面给出一个闭包例子,它访问了三个域的变量
它自己作用域的变量
父函数作用域的变量
全局作用域的变量
var globalVar = "abc"; 
(function outerFunction (outerArg) {   
    var outerFuncVar = 'x';    
(function innerFunction (innerArg) {  
    var innerFuncVar = "y"; 
        console.log(          
            "outerArg = " + outerArg + "\n" +
            "outerFuncVar = " + outerFuncVar + "\n" +
            "innerArg = " + innerArg + "\n" +
            "innerFuncVar = " + innerFuncVar + "\n" +
            "globalVar = " + globalVar);
    }
}
输出很简单:
outerArg = 7
outerFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc
闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

注意:1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
注意:2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
注意:3)外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

通过闭包,父函数中变量的状态被保留了,每一次调用都是在上一次调用的基础上进行计算。从中可以看到,闭包使得父函数的内部环境,一直存在。所以,闭包可以看作是函数内部作用域的一个接口。
闭包的另一个用处,是封装对象的私有属性和私有方法。
function Person(name) {
  var _age;
  function setAge(n) {
    _age = n;
  }
  function getAge() {
    return _age;
  }
  return {
    name: name,
    getAge: getAge,
    setAge: setAge
  };
}
var p1 = Person('张三');
p1.setAge(25);
p1.getAge(); // 25
代码示例1:
var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
alert(object.getNameFunc()());//The Window
代码示例2:
var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  alert(object.getNameFunc()());//mMy Object
不写var则声明的是全局变量
function f1(){
    n=999;
}
f1();//需要调用一次,让n=999执行一次
alert(n); // 999
RepExg
\t	/\t/	制表符  	
\n	/\n/	回车符		
\f	/\f/	换页符		
\b	/\b/	空格
exec(): 用于字符串的匹配,返回值是第一次匹配字符串组成的数组。没有全局匹配
var str = "abbcjjjabbbbbbbcjjj";
var reg = /bcjj/;
var arr = reg.exec(str);
console.log(arr);//["bcjj", index: 2, input: "abbcjjjabbbbbbbcjjj", groups: undefined]
test():检索字符串中指定的值。返回 true 或 false。
	var str = "gabbbbbbcg";
var reg = /ab+c/;
console.log(reg.test(str));
arguments
存储的是函数执行时传递的实际参数
function fun(){
		console.log(arguments[3]);
		console.log(arguments.length);
}
fun(1,2,3,4,5);//4  5
arguments不能通过项数拉长类数组对象的长度,但是可以通过length拉长
arguments[10] = 10;//相当于加了一个属性10,属性值是10
console.log(arguments[10]);
console.log(arguments.length);//lengh仍然5但不是所有数组的方法arguments都可以使用,如slice()
JavaScript 位运算符
 

JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别https://www.cnblogs.com/wujie520303/p/4931384.html
PS:假设某个对象中有三个属性和相对应的值,想要获取到这三个属性及相对应的值for是办不到的,只有for in才可以,所以说,for in一般都是用在遍历对象的,另外,for in也可以遍历数组,但是会存在以下几个问题。
1、index索引为字符串型数字,不能直接进行几何运算
2、遍历顺序有可能不是按照实际数组的内部顺序
3、使用for in会遍历数组所有的可枚举属性,包括原型。例如上栗的原型方法method和name属性
这也是为什么用for不用for in的区别,如果是遍历普通数组的话,用for是最好的选择,但是如果是对象,就for in就好了。之前笔者在一个案例中,因为太晚了,就不在找了,当大家有这个问题的时候,就对照自己的问题就OK了,发现,for可以用的时候,for in居然不能用,当时还不知道有这么多的内置原因,这是因为当时在遍历数组时,碰到有属性的值,比方说5个值,for出来的就是  0  1  2  3  4  而for in就是  0  1  2  3  4  length 还有这个值自带的属性等,就是还有别的属性,所以在执行到第 4 个 在向下执行的时候,for就向下执行了,而for in执行的就是 length这个属性,所以就会报错。


发布了49 篇原创文章 · 获赞 103 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/vayne_xiao/article/details/80504955
今日推荐