这个笔记不知道何时记下的反正颇有意思,很基础,很理论。javascript
JavaScript是一种轻量级的脚本语言,也是一种嵌入式(embedded)语言,是一种对象模型语言。html
脚本语言又被称为扩建的语言,或者动态语言,是一种编程语言,用来控制软件应用程序,脚本一般以文本(如ASCII)保存,只在被调用时进行解释或编译,在依靠特定的宿主环境提供API来实现操做和效果。常见的宿主环境有浏览器,服务器环境(操做系统)。
嵌入式语言一句话就是不能独立作事,插入到其余语言才能用的语言。
理论上<script><script>标签能够放HTML代码的任意位置,实际开发中对于函数的调用,代码的执行一般放入body标签下面;函数的定义,类的定义以及外部文件的引入一般放入head标签中。前端
在head标签中写引入文件的代码便可。java
变量是用来临时存储数据内容的容器,在使用过程当中能够随时改变存储的值。编程
是否编程语言的前提是是否有变量,有变量才算得上真正的编程语言。
变量命名规则:使用var关键字声明变量;数字,字母,下划线,$,且不能数字开头;能够用各类命名法。var不写则是全局变量;数组
JavaScript中中文能够做为变量名是能够的,由于JavaScript语言自己就是使用ut8编码,通常不使用中文做为变量名,由于占的空间大,显得low
数据类型:数字,字符串,布尔,对象,null,undefined浏览器
在JavaScript中数据类型粉三大类:简单类型(数字,字符串,布尔),复合类型(数组,对象,函数),特殊类型(null,undefined),注意JavaScript中没有数组类型这一说法,用typeof判断就说其是object。
对比一下PHP的数据类型:1.整形2.字符串3.浮点型4.null5.布尔类型6.资源型7.数组类型8.对象服务器
用typeof来判断数据类型,返回类型有:Number,String,boolean,undefined,function,object;框架
注意没有null这一类型,
为何null的类型是object?编程语言
这是因为历史缘由形成的。 1995年JavaScript语言的初版, 当时, 只设计了五种数据类型(对象、 整数、 浮点数、字符串和布尔值) , 彻底没考虑null, 只把它看成object的一种特殊值, 为了兼容之前的代码, 后来就无法修改了。
这并非说null就属于对象, 本质上就是一个特殊值, 表示“没有”。
而在ES6草案时, 也曾将 null 的数据类型修改成了 null ,可是由于兼容性问题, 后来又改回了object。
null和undefined的区别?
null与undefined均可以表示“没有”, 含义很是类似;宽松比较时,二者值相等,都表示空,无,没有;
可是, JavaScript的值分红原始类型和合成类型两大类, Brendan Eich(JS做者)以为表示”无”的值最好不是对象;其次, JavaScript的最第一版本没有包括错误处理机制, 发生数据类型不匹配时, 每每是自动转换类型或者默默地失败。我以为, 若是null自动转为0, 很不容易发现错误。因而又设计了一个undefined。
具体的说有如下区别:
var n=null; var d=undefined; var s=(n==d) alert(s); var f=(n===d); alert(f);
var d=document.getElementById('div'); alert(typeof(d));//object alert(d);//null
var n=Number(null); var d=Number(undefined); alert(n);//0 alert(d);//NaN
5.出现undefined的几种状况:
A.变量声明但没有赋值时
var i; alert(typeof(i));//undefined
B.函数须要传参但并无传值时
function f(x){ return x;//undefined } var p=f(); alert(p);
C.访问不存在的属性时,出现undefined
var o={}; alert(typeof(o.p));
D.函数没有返回值时,函数的返回值是undefined
function h(){}; alert(h());//undefined
加,减,乘,除,取余,自增,自减,举个有趣点的案例:
var i=10; var j=++i; var h=i++; var k=++i; //没有赋值操做前自增和后自增是没有区别的。 console.log(j);//11 console.log(k);//13 console.log(h);//11 console.log(i);//13
复合运算:
//复合赋值运算符 +=,-=,*=,/= //三目运算符 条件?代码1:代码2; 条件?true:false;
//比较运算符 < > == === <= >= != !==
逻辑运算符 ! || && 三目运算符等
逻辑与解析图:
逻辑或解析图
if else 和 switch的区别?
if结构不只能够判断固定值, 还能够判断范围区间。switch结构只能判断固定值状况。
3.循环结构:while,for,do while等
4.continue和break的区别;
continue:跳出当前循环,继续下次循环。break:跳出整个循环结构,也就至关于结束循环。
数组是一组有序数据的集合,在内存中表现为一段连续的内存地址。
数组的声明也很简单:
var arr=[1,2,3,4];var arr=new Array(1,2,3,4);
var arr=new Array(2); arr[0]=1;arr[1]=2;arr[2]=3;
多维数组:数组的元素也是一个数组,则父数组是多为数组。
var arr=[1,2,[3,4,5,[6,7]]];是个三维数组
获取数组元素:经过下标获取(数组[下标]),多为数组的话全部下标都写上,否则只的到所在行的所有元素。
数组的遍历:
最经常使用的经过for循环,根据循环语法,在循环以前先获取数组长度
var arr=['Apple','Huawei','SumSung']; var len=arr.length; for(var i=0;i<len;i++){ console.log(arr[i]); }
for...in循环遍历数组:for..in能够遍历对象,也能够遍历数组,毕竟数组也是个特殊的对象。
var arr=['Apple','Huawei','SumSung']; for(var i in arr){ //每次遍历是,系统自动将元素的索引下标放入变量i中 console.log(arr[i]); }
length属性:返回数组的成员数量即数组的长度。
数组对象的经常使用方法:
- push方法:用于在数组的末端添加一个或多个元素,并返回新元素的数组长度。注意push方法会改变原数组。
var a=[]; a.push(1); alert(a);//1 a.push('a'); console.log(a);//Array[1,'a'] a.push(true,{}); console.log(a);//Array [ 1, "a", true, {} ]
- pop方法:用于删除数组的最好一个元素,并返回该元素。注意,pop方法会改变原数组
var a=['a','b','c']; var b=a.pop();//c console.log(a);//Array['a','b'] console.log(b);//c
- join方法:用于参数分隔符,将全部数组成员一个字符串返回,若是不提供参数,默认用逗号分隔。不改变原数组。
var a=[1,2,3,4]; var b=a.join('|'); console.log(b);//1|2|3|4 var c=a.join(); console.log(c);
- concat方法:用于多个数组的合并,它将新数组的成员添加到原数组的尾部,而后返回一个新的数组,原数组不变。
var a=['hello']; var b=['world']; var d=a.concat(b); console.log(d);//Array [ "hello", "world" ] console.log(d.concat(['!'],['A']));//Array [ "hello", "world", "!", "A" ]
- shift方法:用于删除数组的第一元素,并返回给该元素。注意改变原数组。
var a=[1,2,3]; var b=a.shift(); console.log(a);//Array [ 2, 3 ] console.log(b);//1
- unshift方法:用于在数组的第一个位置添加一个元素,并返回新加元素后的数组长度。注意该方法会改变原数组。
var a=[1,2,3]; var b=a.unshift(5); console.log(a);//Array [ 5, 1, 2, 3 ] console.log(b);//4
- reverse方法:用于颠倒数组中的元素,返回改变后的数组。注意,该方法将改变原数组。
var a=[1,2,3]; var b=a.reverse(); console.log(a);//Array [ 3,2,1 ] console.log(b);//Array [ 3,2,1 ]
- slice方法:用于提取原数组中的一部分元素(至关于截取),返回一个新数组,原数组不变。它的第一个参数为起始位置(从0开始) , 第二个参数为终止位置(但该位置的元素自己不包括在内) 。若是省略第二个参数, 则一直返回到原数组的最后一个成员。
var a = ['a','b','c','d','e']; console.log(a.slice(0)) // ["a", "b", "c", "d", "e"] console.log(a.slice(1)) // ["b", "c", "d", "e"] console.log(a.slice(1,3)); // ["b", "c"]
- splice方法:用于删除原数组中的一部分元素,并能够在被删除的位置添加新数组成员,返回值是被删除的元素。注意,该方法会改变原数组。splice的第一个参数是删除的起始位置, 第二个参数是被删除的元素个数
var a = ['a', 'b', 'c', 'd', 'e', 'f']; var a1 = a.splice(4, 2); console.log(a1); //Array["e", "f"] console.log(a); // Array["a", "b", "c", "d"] var b = ['a', 'b', 'c', 'd', 'e', 'f']; var a2 = b.splice(1, 2, 1, 2); console.log(a2); //["b", "c"] // console.log(b);//["a", 1, 2, "d", "e", "f"]
- forEach方法:用于遍历数组的全部成员,执行某种操做;forEach方法的参数是一个函数,数组的全部成员会依次执行该函数,它接受三个参数,分别是当前位置的值,当前位置的编号和整个数组
var a = ['a', 'b', 'c', 'd', 'e', 'f']; a.forEach(function(v,k,h){ console.log(v); console.log(k); console.log(h); }); //第三个参数能够写能够不写,它带便遍历次数
函数就是制做工具的工具,好比计算器就是一个工具,而制做计算器的工具就是函数,也就是制做工具的工具。一次定义屡次使用。
用函数的好处:节省代码的数量,减小代码量,使代码能够重复使用,节省空间,节省时间,使程序代码具备结构化,模块化,后期维护更友好等等不少好处
屡次声明同一个函数的话,最后一次声明的函数会覆盖前面的函数,前面的声明在任什么时候候都是无效的。
递归函数:函数内部调用函数自身,称之为递归。只要是递归必须的有判断,否则它是个死循环,用别的函数解决的问题最好别用递归解决,递归占内存大,不友好。
function Recursion(x){ if(x>1){ return x+Recursion(x-1); }else{ return 1; } } console.log(Recursion(100);
函数的参数有形参和实参:
形参就是函数声明时须要接受的参数,能够理解成暂时的占位符,并没有实际意义实参就是调用函数是传递进函数的具体的实际数据,也就是给占替代位符的的值
函数体内部的return语句:表示将数据返回给调用者。return后面即便有语句,也不会执行,也就是return后面不执行.return语句无关紧要,没有则不反悔任何值或者说返回undefined。
函数中的arguments对象:arguement是函数调用时的实参列表;只是实参列表
function Argu(a){ console.log(arguments); } Argu(1,2,3);
aruguments对象带有一个callee属性,返回他所对应的原函数。callee表明当前运行的函数
function Argu(a){ console.log(arguments.callee); } Argu(1,2,3);
函数能够没有名字吗?固然能够:(function(){})();
为何要有自调用匿名函数?
由于有名函数有缺点,可能运行时会出现命名冲突,若是在编写程序时,直接采起自调用匿名函数,则不会产生命名冲突问题。市场上不少框架,如JQuery.js,ext.js等都是采用匿名函数进行封装。
使用自调用匿名函数结合aruguments对象实现递归:
var a = (function (n) { if (n > 1) { return n + arguments.callee(n - 1); } else { return 1; } })(100); console.log(a);
做用域指的是变量存在的范围。JavaScript中做用域有两种局部做用域和全局做用域。
局部做用域:变量只在函数的内部存在。在函数内使用var声明的变量是局部变量,是人为的声明。全局做用域:变量在整个程序中存在,全部地方均可以读取。全局变量一个是函数外声明的变量;还有一个是函数内不使用var的变量(仅仅带便变量被赋值),也就是若是不是人为定义,系统会定义,系统定义的变量在整个程序中存在,不加var会污染全局。
function a(){ b=1 } a(); console.log(b);
局部变量会替代全局变量:函数内部声明的变量会在函数内部区域覆盖同名的全局变量。
这说明javascript的函数在查找自身函数定义开始,从“内”向“外”查找。
var a=3; function fun(){ var a=2; console.log(a); } fun();//2 console.log(a);//3
若是函数内部不使用var关键字,那么函数内部的赋值将会影响全局变量。实际上,JavaScript默认哟偶一个全局的对象窗口,全局做用域的变量其实是被绑定到窗口对象上的一个属性,所以,直接访问全局对象a和访问window.a是彻底同样的
var a=3; function fun(){ a=2; console.log(a); } fun();//2 console.log(a);//2
做用域解释图:
JavaScript的函数定义有个特色,他会先扫描整个函数体呃逆的语句,把全部声明的变量提高到函数的顶部,注意只是把声明提高了,并不会提高变量的赋值。
function fun(){ console.log(a);//undefined var a=2; //JavaScript解析引擎来讲至关于 /** *var a; *var b=1+a; *alert(b); *a=2; **/ } fun();
函数自己也是一个值,也有本身的做用域;函数的做用域与变量同样,就是它声明时所做的做用域,与其运行时所在的做用域无关
函数执行时的做用域是定义时的做用域,而不是调用时的做用域。
var a=3; var x=function(){ console.log(a); } function f(){ var a=4; x(); } f();//3
再看这个:
var x=function(){ console.log(a); } function y(f){ var a=2; f(); } y(x);//ReferenceError: a is not defined //函数执行时的做用域是定义时的做用域,而不是调用是的,因此,这代码运行结果是这样。
继续看代码
function fun(){ var a=2; function bar(){ console.log(a); } return bar; } var a=4; var f=fun(); f();//2
JavaScript代码运行,分为编译阶段和执行阶段:
编译阶段:声明变量,声明函数(display),语法检查等操做,一旦出错不会执行下一阶段,除了错误提示不输出别的内容执行阶段:变量的赋值,函数的调用,代码的执行等操做,这一阶段出错的话出错以前的内容执行;
<script> console.log(1); console.log(s); console.log(3); //执行结果是:1 错误提示:找不到变量s //缘由代码编译阶段没有问题,执行阶段因为发生了错误,错误后面不会执行 </script> <script> console.log(3); console.log(4) console.log(4); //执行结果是:错误提示:有语法错误请检查 //缘由:代码编译阶段就出错再也不执行执行阶段 </script>
在html中<script></script>是一段独立的代码,这一段代码出错不会影响下一个<script></script>代码段的执行;无论前面的代码段错误出如今编译阶段仍是执行阶段都不会影响下一段代码的执行。
为何呢?
虽然script代码段在一个页面,可是script代码并非一块儿执行,而是分开解析与执行。JavaScript解析引擎从上而下读取第一个代码段-->放入内存-->编译阶段-->执行阶段-->下一个JavaScript代码段-->放入内存...等操做;
总之一句话,JavaScript解析引擎执行完一段代码再执行下一段代码,每一段代码都是独立的存在。所以,前一个代码不管发生什么错误都不会影响下一个代码段的执行
看图: