词条javascript
《JavaScript高级程序设计》是2006年人民邮电出版社出版的图书,做者是(美)(Nicholas C.Zakas)扎卡斯。本书适合有必定编程经验的开发人员阅读,也可做为高校相关专业课程的教材。java
献给搬砖人士,求职人士很不错的基础扎实笔记算法
js诞生于1995年当时它的主要目的是处理验证操做现在发展成为一门强大的编程语言,由三部分组成:核心(ECMAScript)DOM文档对象模型、 BOM浏览器对象模型编程
js 放置在 页面的合理位置 对于优化加载有很大的帮助
切记平稳退化,若是不支持的状况下 有不少种方案 ,书中提到了数组
<noscript> 元素 </noscript>
当页面支持脚本,用户永远也看不到它,尽管他是页面的一部分。浏览器
语句结尾加上分号,在某些状况下会增进代码的性能,由于解析器没必要花时间推测应该在哪里插入分号了。
1、数据类型 性能优化
关于 undefined类型,在使用var声明变量但未对其加以初始化这个变量的值就是undefined,包含undefined值的变量与还没有定义的变量还不同。闭包
var message; alert(message) // undefined alert(age) // 产生错误
关于 NANapp
即非数值,不是一个数字。框架
NAN与任何值都不相等,包括它本身
alert(isNAN(NAN)) //是否 不是一个数字 true alert(isNAN(10)) // false alert(isNAN('ni')) // true alert(isNAN(true)) // false 由于true 能够被转换为1
typeof() 用来检测给定变量的数据类型
1.undefined 声明变量没有定义 2. null 空对象指针 3. bloolean 4. number 数值转换 Number()函数在转换字符串时比较复杂并且不够合理,推荐使用,parseInt()parseFloat() 5. string 字符串类型 toString() 有个缺点 对null 和 undefined 不起做用 6. string() 方法更全面 7. object 对象
2、语句
do-whlie语句 是一种后测试循环语句,换句话说代码至少执行一次
do{ i+=2; }whlie(i<10)
whlie语句属于前测试循环语句,相对for语句也是
var i = 0 whlie(i<10){ i+=2 }
关于break和continue语句
var num = 0; for(var i = 0;i++;i<num.length){ if(i%5==0){ break; } num++; } alert(num) //4 break 是当即退出循环强制执行循环后面的语句 var num = 0; for(var i = 0;i++;i<num.length){ if(i%5==0){ continue; } num++; } alert(num) //8 continue 退出循环后从循环顶部继续执行
函数体内能够经过arguments 对象来访问这个参数数组 类数组
经过arguments[0]访问第一个参数,arguments[1]访问第二个参数
函数没有重载,定义两个相同名字的函数,后一个会覆盖前一个 经过检查传入函数中参数的类型和数量作出不一样的反应,来模拟方法重载,以下所示。
function add(){ if(arguments.length ==1){ alert(arguments[0]+10) }else if(arguments.length ==2){ alert(arguments[0]+arguments[1]) } } add(10) //20 add(10,20) //30
js 变量包含两种数据类型 其一 基本数据类型 其二 引用数据类型
3、基本数据类型与引用类型
基本数据类型指的是简单的数据段,引用类型保存在内存对象中不能直接操做对象的内存空间,操做对象是实际上操做的是对象的引用。
var num1 = 5 var num2 = num1 num2与num1是彻底的独立的,两个变量互不影响,是副本的关系
var obj = new object ; var obj2 = obj; obj.name = 'nihao'; alert obj2.name 结果是 nihao
不一样的是 这个值的副本实际是 指向了同一个对象 当obj 添加了name属性后 能够经过 obj2 来访问
函数的参数 实际上是其函数的局部变量
每一个函数都有本身的执行环境,当代执行的时候会建立一个做用域链,对环境的全部变量作有序的访问
查询标示符 也就是 搜索 过程 若是局部环境找到了该标识符 则搜索过程中止 不然 一直追溯到全局环境的变量
做用域链 引起了闭包的概念 全局变量只能访问全局的环境 而局部环境不只能够访问本身 还能够访问其 父级
js 是一门具备垃圾 收集机制的编程语言 没必要关心内存问题 标记清除是目前主流的 垃圾收集算法给当前不使用的值加上标记而后再回收其内存 引用计数 目前再也不使用的算法,解除引用对垃圾回收机制有好处是很好的性能优化方案
引用类型,有时候也称为对象定义由于他们描述的是一类对象所具备的属性和方法。
1、object类型
建立object实例的方法:
var per = { name: '', age: 23 }
思考题---基于typeof 检测属性是否存在,使用字面量来指定不一样的数据,作不一样的显示
function show(arg){ var output = ''; if(typeof arg.name === 'string'){ output += 'nihao' + arg.name; } if(typeof arg.age === 'number'){ output+= 'Age:'+ arg.age } alert(output); } show({ name:'lish', age: 23 }) show({ name:'zbg' })
2、array类型
与其余语言的区别: 都同为数据的有序列表,可是js的数组每项能够保存任何类型的数据
建立方式 同object类型
数组的length属性 不是只读的,能够修改!
数组检测 有两个问题:instanceof、array.isArray(),若是有多个框架会有多个全局执行环境会存在不一样版本的构造函数,后者目的是肯定这个值是否是数组,不管是在那个环境建立的
转换方法: 全部对象都具备toLocaleString、toString、valueOf ,前者与后二者不一样的是为了取每一项的值调用的是每一项的toLocaleString,而不是toString。
最后使用join()重现了toString的方法,传递逗号将以逗号分割,传递双竖线将以双竖线分割
ecmascript专门为数组提供了push和pop方法,模拟栈方法,后进先出。
unshift和shift先进先出。
重排序方法:sort()
function com (val1,val2){ if(val1<val2){ return -1; }else if(val2>val2){ return 1; }else{ return 0 } } var arr = [12,2,3,34,567]; arr.sort(com) alert (arr);
操做方法: concat() 不改变原数组,复制原数组返回副本,会被添加到原数组的末尾
var arr1 = [1,23,3]; var arr2 = arr1.concat("one",[8,"two"]) arr2 => 1,23,3,one,8,two
slice()用于截取数组,不改变原数组建立一个新数组
arr.slice(1) 从下标1开始到结束 arr.slice(1,4)同理 若是是负数,用数组的长度作运算,再若是结束位置小于起始位置返回空数组
splice() 用于删除、插入、替换数组
arr.splice(0,1) 从第零个开始删除1位 arr.splice(1,0,"one") 从第一个位置开始不删除 插入一项 arr.splice(1,1,"two") 从第一个位置删除一位 插入一项
filter() 用于数组筛选
var bg = arr.filter(function(item,index,array){ return (item>2) }) console.log(bg)
map()方法 和foreach() 相似
var bg = arr.map(function(item,index,array){ return (item+2) }) console.log(bg)
归并方法 reduce()和reduceRight()
使用归并方法求数组之和
var val = [1,2,3,4,5] var sum = val.reduce(function(pre,cur,index,array){ return pre+cur }) alert(sum) 15 pre表明前一项 cur表明当前项 reduce 和 reduceRight 结果相同但取决于从哪头开始遍历数组。
3、date类型
经常使用的时间戳
`var start = +new Date()
dosomething();
var end = +new Date()
result = end-start`
4、regExp类型
匹配第一个 bat 或者 cat 不区分大小写 var pattern = /[bc]at/i; 匹配第一个[bc]at 不区分大小写 var pattren = /\[bc]\at/i; 匹配全部以 at结尾的字符不区分大小写 var partten = /.at/gi; 匹配全部以 .at 结尾的字符不区分大小写 var partten = /\.at\/gi; test()方法 var text = "000-00-0000"; var partten = /\d{3}-\d{2}-\d{4}/; if(partten.test(text)){ alert('yes') }
5、function类型
函数没有重载
var add = function(){ return num+100 } add = function(){ return num+100 } var result = add(200) //300 在建立第二个函数时,实际上覆盖了第一个函数的变量
函数声明与函数表达式 声明提早
函数声明由于在代码执行以前,引擎会声明函数并将他们放到源代码树的顶部,
而对于表达式:
alert(sum(10,10)); var sum = function(){ return num+num2 }
在执行到语句以前,变量sum中不会保存对函数的引用
做为值的函数
假想根据某个对象属性对数组进行排序
function newsort(pro){ return function(obj1,obj2){ var val1 = obj1[pro]; var val2 = obj2[pro]; if(val1<val2){ return -1; }else if(val1>val2){ return 1 }else{ return 0 } } } var data = [{name:'lj', age:23},{name:'db', age:45}]; data.sort(newsort(name)) //按姓名排 data.sort(newsort(age)) //按年龄排
函数内部属性
函数内部有两个特殊的对象:arguments this,arguments主要保存函数的参数它还有一个属性callee 是个指针 指向拥有arguments对象的函数
例如很是经典的阶乘函数
function fact(num){ if(num<=1){ return 1 } else{ return num* fact(num-1) } } 为了消除函数执行与函数名的耦合现象可使用arguments.callee(num-1) 替代 fact(num-1) 在解除了耦合状态以后 newfact能够正常计算,但fact 只能返回0 var newfact = fact; fact = fuction(){ return 0 } newfact(5) // 120 fact(5) //0
函数的属性和方法:
每一个函数都包含两个属性:length prototype 前者是接收参数的个数,后者是保存
全部实例方法的真正所在。
每一个函数也都包括两个非继承而来的方法 apply()、call(),用以改变this的指向
function sum (num1, num2){ return num1+num2 } function callsum(num1, num2){ return sum.apply(this, arguments) } alert(callsum(10,10)) //20
基本数据类型,使用new操做符建立引用类型的实例,执行离开做用域以前一直保存在内存中,而基本数据类型,只存在代码执行的瞬间而后当即被销毁
1、布尔,数字,字符串
截取给定位置的那个字符 charAt 只接受一个参数
var str = 'nihao'; alert(str.charAt(1)) //i
字符串的拼接 concat 或者 + 加号操做符
var str = 'nihao'; var newstr = str.concat('world', '!'); alert(newstr) // nihao world !
字符串的截取 slice()、substr()、substring()。接收最多两个参数
字符串的查找 indexOf match
var str = 'lele nihao,zheli shi di yi jia zhu'; var arr = []; var op = str.indexOf('e'); while(op>-1){ arr.push(op); op = str.indexOf('e', op+1); } //进入循环后每次给indexOf传递上一次的位置加1 alert(arr) trim() 会建立一个字符串的副本,删除前置及后置的全部空格 match()方法只接受一个参数 var text = 'bat cat'; var parrent = /.at/gi; var new = text.match(parrent)
字符串的替换 replace()
var text = 'bat cat'; var result = text.replace(/at/gi, 'oo')
字符串转数组的方法 split()
var text = 'arr,op,kj,hg,'; var result = text.split(',') 接受第二个参数,固定数组的length
2、URL编码方法
encodeURL() 是对整个URL进行编码, encodeURLComponent()对附加在现有URL后面的使用
3、 Math 对象
获取数组中最大值和最小值 避免过多的使用循环和在if语句中肯定数值。
var val = [1,2,3,4,5,6,7,8,9]; var max = Math.max.apply(Math, val); 这个技巧的关键,把MAth做为apply的第一个参数,从而正确的设置了this、
`Math.ceil() 向上取整
Math.floor() 向下取整
Math.round() 四舍五入取整`
random()方法
值 = Math.floor ( Math.round() * 可能值的总数 + 第一个可能的值 )
function round(low, up){ var sum = up-low+1 //总数 return Math.floor ( Math.round() *sum + low ) } var color = ['red', 'blue', 'green', 'yellow']; var arr = color[round(0, color.length-1)] console.log(arr) //多是数组中包含任意一个字符串
总结:第五章完结,在全部代码执行以前 做用域就已经存在两个内置对象 global和math
面向对象有类的概念,经过类能够建立任意多个相同属性和方法的对象。
1、建立对象
一、工厂模式,解决了建立多个类似对象的问题,却没有解决对象识别问题
二、构造函数,自己也是函数只不过能够用来建立对象,缺点每一个方法都要在每一个实例上从新建立一遍,因而把函数定义转到构造函数外面,可是若是对象定义多个方法就要定义多个全局函数,最终致使没有封装性。
function Person (name){ this.name = name, this.sayName = function(){ alert(this.name) } } //注意函数名大写,是为了区别其余函数
//再一次提到this重定向 var o = new object(); person.call(o,"li",25,"ha"); o.sayname() //li
三、原型模式,每一个函数都有一个prototype属性,她是一个指针,指向一个对象,实例共享。
function Person (name){ Person.prototype.name = name, Person.prototype.sayName = function(){ alert(this.name) } } var preson1 = new Person; var preson2 = new Person; alert(person1.sayname === person2.sayname) //true
虽然经过对象实例能够访问保存在原型中的值,但却不能经过对象实例重写原型中的值,若是同名该属性就会屏蔽原型中的那个属性
function Person (){ Person.prototype.name = 'lisj', Person.prototype.sayName = function(){ alert(this.name) } } var preson1 = new Person; var preson2 = new Person; preson1.name = 'matou' alert(person1.name) //'matou' alert(person2.name) //'lisj' 使用hasOwnProperty 检测一个属性是否存在于实例中 alert(person1.hasOwnProperty('name')) //true alert(person2.hasOwnProperty('name')) //false
四、组合使用构造函数模式和原型模式
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性
function Person (name){ this.name = name; this.friends = ['ls','df'] } Person.prototype = { constructor: person, sayname: function(){ alert(this.name) } } var preson1 = new Person; var preson2 = new Person; person1.friends.push('Van') alert(person1.friends === person2.friends) //false alert(person1.sayname === person2.sayname) //true
2、原型链实现继承,经过将一个类型的实例赋值给另外一个构造函数的原型实现
定义函数的方式经常使用有两种:一、函数声明。二、函数表达式
函数声明
function show(){}
函数表达式
var say = fuction(){}
函数声明提早
关于函数声明,执行代码前会先读取函数声明,这就意味着先后均可以调用。
而对于函数表达式 提早调用就会报错,使用前必须声明。
函数表达式与函数声明的区别
if(true){ function say(){alert(1)} } else{ function say(){alert(2)} }
注:表面上看很合理,其实是在js中属于无效语法,但引擎会尝试修正此错误。
下面的这种写法就很好的解决了这类问题
var say; if(true){ say = function(){alert(1)} } else{ say = function(){alert(2)} }
2、递归
递归函数是在一个函数经过名字调用自身的状况下构成的
function face(num){ if(num<=1){ return 1; } else{ return num* arguments.callee(num-1) } } arguments.callee 是一个指向正在执行的函数指针,用它来实现对函数的递归调用
也能够经过命名函数表达式来达成相同的效果
var face = (function f(num){ if(num<=1){ return 1; } else{ return num* f(num-1) } })
3、闭包
有权访问另外一个函数做用域中的变量的函数
关于闭包与变量,即闭包只能取得包含函数中任何变量的最后一个值,闭包保存的是整个变量对象而不是某个特殊的变量。
function nc(){ var result = new Array(); for(var i = 0;i< 10;i++){ result[i] = function(){ return i } } return result }
能够经过一个匿名函数强制让闭包的行为符合预期
function nc(){ var result = new Array(); for(var i = 0;i< 10;i++){ result[i] = function(num){ return function(){ return num } }(i) } return result }
关于闭包中使用this
var name = 'window' var obj = { name:'lsj', say:function(){ return function(){ return this.name } } } alert(obj.say()()) //window
var name = 'window' var obj = { name:'lsj', say:function(){ var that = this; return function(){ return that.name } } } alert(obj.say()()) //lsj
经过私有做用域模仿块级做用域
(function(){ })();
1、最好使用settimeout 去模拟 setinterval
var num = 0; var max = 10; function show(){ num++; if(num<max){ settiomeout(show, 500) } else{ alert('done') } } settiomeout(show, 500)
2、location.search 查询字符串参数
function get(){ var qs = (location.search.length>0? location.search.substring(1):''), args = {}, items = qs.length? qs.split('&'): [], item = =null, name = null, value = null; for(var i = 0;i++;i<items.length){ item = item[i].split('=') name = decodeURLComponent(item[0]) value= decodeURLComponent(item[1]) if(name.length){ args[name] = value } } return args } 假设查询字符串为: ?q=javascript&num=0 var result = get() alert(result['q']) //javascript
关于window路径跳转的几种方法:
location.assign('http://nihao.com') location.href = 'http://nihao.com' window.location = 'http://nihao.com' //效果相同
事件流描述的是从页面中接收事件的顺序。
IE的事件流叫事件冒泡:也就是点击事件首先在div元素上发生,再向DOM树向上传递直到document对象
网景公司提出的事件流叫事件捕获:document对象首先接收事件再从树往下传播到事件的实际目标
<input type="button" value="yes" onclick="alert(event.type)" /> <input type="text" value="yes" onclick="alert(this.value)" />
经过一个函数处理多个事件时,可使用type属性
var btn = document.getElementById('de'); var handler = function(event){ switch(event.type){ case "click": alert(1); break; case "mouseover": alert(2); break; } } btn.onclick = handler btn.onmouseover = handler
跨浏览器的事件对象兼容
var EventUtil = { getEvent:function(event){ return event? event: window.evnet }, getTarget:function(event){ return event.target || event.srcElement }, perventDefault:function(event){ if(event.perventDefault){ event.perventDefault() } else{ event.returnValue = false } }, } var a = document.getElementById('link'); a.onclick = function(event){ event = EventUtil.getEvent(event) EventUtil.perventDefault(event) } 以上代码能够确保全部浏览器中点击该连接都会阻止默认跳转
事件委托
创建在事件冒泡机制上的事件委托技术
只需在dom树中最高层次添加一个事件处理程序,这种技术占用内存少,dom引用少可以提高总体的性能。
<ul id = 'list'> <li id="one">one</li> <li id="two">two</li> <li id="three">three</li> </ul> var list = document.getElementById('list'); list.onlick = function(){ event = EventUtil.getEvent(event) var target = EventUtil.getTarget(event) switch(target.id){ case "one": alert(1); break; case "two": alert(2); break; } }