javascript是一门重要弱类型的语言,由于它是web浏览器的语言,它与浏览器的结合使他成为世界上最流行的编程语言之一。javascript
js历史html
Nombas 和 ScriptEasejava
大概在 1992 年,一家称做 Nombas 的公司开发了一种叫作 C 减减(C-minus-minus,简称 Cmm)的嵌入式脚本语言。Cmm 背后的理念很简单:一个足够强大能够替代宏操做(macro)的脚本语言,同时保持与 C (和 C ++)足够的类似性,以便开发人员能很快学会。这个脚本语言捆绑在一个叫作 CEnvi 的共享软件中,它首次向开发人员展现了这种语言的威力。node
Nombas 最终把 Cmm 的名字改为了 ScriptEase,缘由是后面的部分(mm)听起来过于消极,同时字母 C “使人惧怕”。angularjs
如今 ScriptEase 已经成为了 Nombas 产品背后的主要驱动力。web
Netscape 发明了 JavaScript正则表达式
当 Netscape Navigator 崭露头角时,Nombas 开发了一个能够嵌入网页中的 CEnvi 的版本。这些早期的试验被称为 Espresso Page(浓咖啡般的页面),它们表明了第一个在万维网上使用的客户端语言。而 Nombas 丝毫没有料到它的理念将会成为万维网的一块重要基石。编程
当网上冲浪愈来愈流行时,对于开发客户端脚本的需求也逐渐增大。此时,大部分因特网用户还仅仅经过 28.8 kbit/s 的调制解调器链接到网络,即使这时网页已经不断地变得更大和更复杂。而更加加重用户痛苦的是,仅仅为了简单的表单有效性验证,就要与服务器进行屡次地往返交互。设想一下,用户填完一个表单,点击提交按钮,等待了 30 秒的处理后,看到的倒是一条告诉你忘记填写一个必要的字段。数组
那时正处于技术革新最前沿的 Netscape,开始认真考虑开发一种客户端脚本语言来解决简单的处理问题。浏览器
当时工做于 Netscape 的 Brendan Eich,开始着手为即将在 1995 年发行的 Netscape Navigator 2.0 开发一个称之为 LiveScript 的脚本语言,当时的目的是在浏览器和服务器(原本要叫它 LiveWire)端使用它。Netscape 与 Sun 及时完成 LiveScript 实现。
就在 Netscape Navigator 2.0 即将正式发布前,Netscape 将其改名为 JavaScript,目的是为了利用 Java 这个因特网时髦词汇。Netscape 的赌注最终获得回报,JavaScript 今后变成了因特网的必备组件。
javascript的函数(主要)基于词法做用域(lexical scoping)的顶级对象。
hello world
demo.html <!DOCTYPE html> <html> <head> <title>javascript demo</title> </head> <body> <pre> <script type="text/javascript" src="demo.js"></script> </pre> </body> </html> demo.js document.writeln('hello world')
<!DOCTYPE html> <html> <head> <title>html text</title> </head> <body> <script type="text/javascript"> document.write('hello js') </script> </body> </html> <!-- javascript 生产普通文本和标签 --> <!DOCTYPE html> <html> <!-- javascript 生产普通文本和标签 --> <head> <title>html text</title> </head> <body> <script type="text/javascript"> document.write('<h1>hello js</h1>') </script> </body> </html> <!-- javascript head 部分 onload事件 --> <!DOCTYPE html> <html> <!-- javascript head 部分 onload事件 --> <head> <title>html text</title> <script type="text/javascript"> function msg(){ alert("onload event on head parts") } </script> </head> <body onload="msg()"> </body> </html> <!-- javascript 点击事件调用函数 --> <!DOCTYPE html> <html> <!-- javascript 点击事件调用函数 --> <head> <title>html text</title> <script type="text/javascript"> function myFun(){ <!--JavaScript 语句向浏览器发出的命令。语句的做用是告诉浏览器该作什么。下面的 JavaScript 语句向 id="demo" 的 HTML 元素输出文本 "Hello World",在 JavaScript 中,用分号来结束语句是可选的。--> document.getElementById('demo').innerHTML='My html' } </script> </head> <body> <p id = "demo">My link</p> <button type="button" onclick="myFun()">try it</button> </body> </html> <!-- 请使用 document.write() 仅仅向文档输出写内容。若是在文档已完成加载后执行 document.write,整个 HTML 页面将被覆盖--> <!DOCTYPE html> <html> <!-- 请使用 document.write() 仅仅向文档输出写内容。若是在文档已完成加载后执行 document.write,整个 HTML 页面将被覆盖--> <head> <title>html text</title> </head> <body> <p id = "demo">My msg</p> <button type="button" onclick="myFun()">try it</button> <script type="text/javascript"> function myFun(){ document.write('output msg,then whole page will be overide') } </script> </body> </html> <!-- 你能够在文本字符串中使用反斜杠对代码行进行换行。--> <!DOCTYPE html> <html> <head> <title>html text</title> </head> <body> <script type="text/javascript"> document.write('hi \ jim') </script> </body> </html> <!-- 变量是存储信息的容器 --> <!DOCTYPE html> <html> <head> <title>html</title> <script type="text/javascript"> function fun() { var num1 = 1; var num2 = 2; var num3 = num1 + num2; document.write(num3);//点击try it按钮,打出计算结果 3 } </script> </head> <body> <button type="button" onclick="fun()">try it</button> </body> </html> <!-- js建立数组 --> <!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> var cars = new Array(); cars[0] = 'aodi'; cars[1] = 'baoma'; cars[2] = 'benchi'; for(var i = 0;i<cars.length;i++){ document.write(cars[i]+'<br/>') } </script> </body> </html> <!-- js建立对象而且获取对象 --> <!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> var cars = { 'name1':'baoma', 'name2':'aodi', 'name3':'dazhong' } document.write(cars.name1) </script> </body> </html>
1,语法
1.1 空格
var that = this;
var 和that之间的空白不能移除,可是其余的空格都是能够移除的。
注释
js的注释有两种方法:/ / 和//
/ var rm_a = /a/.match(s) */就会致使错误,因此通常注释用//.
1.2 标识符
标识符有一个字母开头,能够选择性的加上一个或是多个字母,数字或下划线,可是不能使用下面的保留字
abstract,boolean,break,byte,case,catch,char,class,const,continue,debugger,default,delete,do,double,else,enum,export,extends,false,final,finally,float,for,function,goto,if,implements,import,in,instanceof,int,interface,long,native,new,null,package,private,protected,public,return,short,static,super,switch,synchronized,this,throw,thransient,true,try,typeof,while,with
2,对象
js中,对象是可变的键控集合(keyed collections),在js中,数组是对象,函数是对象,正则表达式是对象。
对象字面量:对象字面量提供了一种很是方便的建立新对象值的表达法,一个对象字面量就是包围在一对花括号中的零或多个"键/值"对。
var name = { "name1":"mike", "name2":"mike2" }
对象也能够嵌套使用:
var flight = { airline:"oceanic", number:125, departure:{ city:"beijing", time:"2015/01/05" }, arrival:{ city:"amrica", time:"2015/01/06" } }
2.1 对象的检索
检索对象中包含的值,能够采用在[]后缀中括住一个字符串表达式。
name["name1"] //mike1 flight.arrival.city //amrica
2.2属性值更新
name["name1"] = "Jet li"
2.3引用传递对象
对象经过引用来传递
var = {},b = {},c = {}//a,b,c 都引用一个不一样的空对象
a = b = c = {} //a b,c都引用同一个空对象
3.2 原型
http://www.crockford.com/java...
原型是一个对象,其余对象能够经过它实现属性继承。
每一个对象都链接到一个原型对象,而且他能够从中能够继承属性,原型链接在属性更新的时候是不起做用的,原型链接只用在检索的时候才会被用到,若是咱们尝试去获取对象的某个属性值,且该对象没有此属性值,那么js会尝试从原型对象上获取,若是也没找到,返回undefined,这个过程叫委托
typeof
typeof 运算符有一个参数,即要检查的变量或值
var a = "str"; alert(typeof a);//string var a = 'str'; alert(typeof 123);// number
对变量或值调用 typeof 运算符将返回下列值之一:
undefined - 若是变量是 Undefined 类型的 boolean - 若是变量是 Boolean 类型的 number - 若是变量是 Number 类型的 string - 若是变量是 String 类型的 object - 若是变量是一种引用类型或 Null 类型的
为何 typeof 运算符对于 null 值会返回 "Object"。这其实是 JavaScript 最初实现中的一个错误,而后被 ECMAScript 沿用了。如今,null 被认为是对象的占位符,从而解释了这一矛盾,但从技术上来讲,它仍然是原始值。
Undefined 类型
如前所述,Undefined 类型只有一个值,即 undefined。当声明的变量未初始化时,该变量的默认值是 undefined。
var str; console.log(str==undefined)//true var str; console.log(typeof str)//undefined
Null 类型
另外一种只有一个值的类型是 Null,它只有一个专用值 null,即它的字面量。值 undefined 其实是从值 null 派生来的,所以 ECMAScript 把它们定义为相等的。
var str = null; console.log(str==undefined)//true
尽管这两个值相等,但它们的含义不一样。undefined 是声明了变量但未对其初始化时赋予该变量的值,null 则用于表示还没有存在的对象(在讨论 typeof 运算符时,简单地介绍过这一点)。若是函数或方法要返回的是对象,那么找不到该对象时,返回的一般是 null。
Boolean 类型
它有两个值 true 和 false (即两个 Boolean 字面量)。
即便 false 不等于 0,0 也能够在必要时被转换成 false,这样在 Boolean 语句中使用二者都是安全的。
注意数值的表示法 var str = !0;console.log(str)//true var str = !1;console.log(str)//false
Number 类型
ECMA-262 中定义的最特殊的类型是 Number 类型。这种类型既能够表示 32 位的整数,还能够表示 64 位的浮点数。
直接输入的(而不是从另外一个变量访问的)任何数字都被看作 Number 类型的字面量。例如,下面的代码声明了存放整数值的变量,它的值由字面量 32 定义:
var num = 32;console.log(num)//32
JavaScript 拥有动态类型
JavaScript 拥有动态类型。这意味着相同的变量可用做不一样的类型:
Undefined 和 Null
Undefined 这个值表示变量不含有值。
能够经过将变量的值设置为 null 来清空变量。
<!--能够经过null来清空对象--> <!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> var cars='baoma'; document.write(cars+'<br/>') cars = null; document.write(cars) alert(cars==undefined)//true </script> </body> </html>
声明变量类型
当您声明新变量时,可使用关键词 "new" 来声明其类型:
<!DOCTYPE html> <html> <!-- 声明新变量时,可使用关键词 "new" 来声明其类型 --> <head> <title>html</title> </head> <body> <script type="text/javascript"> var str = new String; var bo = new Boolean; var num = new Number; var cars = new Array; var person = new Object; alert(typeof str) alert(typeof bo) alert(typeof num) alert(typeof cars) </script> </body> </html>
建立 JavaScript 对象
JavaScript 中的几乎全部事务都是对象:字符串、数字、数组、日期、函数,等等。
对象(object)定义为“属性的无序集合,每一个属性存放一个原始值、对象或函数”。严格来讲,这意味着对象是无特定顺序的值的数组。
面向对象语言的要求
一种面向对象语言须要向开发者提供四种基本能力:
封装 - 把相关的信息(不管数据或方法)存储在对象中的能力 汇集 - 把一个对象存储在另外一个对象内的能力 继承 - 由另外一个类(或多个类)得来类的属性和方法的能力 多态 - 编写能以多种方法运行的函数或方法的能力
对象由特性(attribute)构成,特性能够是原始值,也能够是引用值。若是特性存放的是函数,它将被看做对象的方法(method),不然该特性被看做对象的属性(property)。
你也能够建立本身的对象。
<!DOCTYPE html> <html> <!-- 建立 JavaScript 对象--> <head> <title>html</title> </head> <body> <script type="text/javascript"> var person= new Object(); person.name1='mike'; person.age=23; person.color1 = 'yellow'; document.write('A person named '+ person.name1+' is '+ person.age +' years old') </script> </body> </html>
访问对象的属性和方法
<!DOCTYPE html> <html> <!--访问对象的属性和方法--> <head> <title>html</title> </head> <body> <script type="text/javascript"> var str = 'Hellojs' document.write('Len: '+str.length+' <br/>Up: '+str.toUpperCase()) </script> </body> </html>
调用带参数的函数
在调用函数时,您能够向其传递值,这些值被称为参数。
变量和参数必须以一致的顺序出现。第一个变量就是第一个被传递的参数的给定的值,以此类推。
<!DOCTYPE html> <html> <!--JavaScript 调用带参数的函数--> <head> <title>html</title> <script type="text/javascript"> function fun(name,title){ alert(name+' is a great '+title) } </script> </head> <body> <button type = 'button' onclick="fun('bill','leader')">click</button> </body> </html>
带有返回值的函数
在使用 return 语句时,函数会中止执行,并返回指定的值。
<!DOCTYPE html> <html> <!--JavaScript 调用带参数的函数--> <head> <title>html</title> <script type="text/javascript"> function re(){ var num = 4; return num; } // return 返回4 function fun(){ document.getElementById('demo').innerHTML=re() } </script> </head> <body> <p id="demo">Here is the content will be changed</p> <button type = 'button' onclick="fun()">click</button> </body> </html>
局部 JavaScript 变量
在 JavaScript 函数内部声明的变量(使用 var)是局部变量,因此只能在函数内部访问它。(该变量的做用域是局部的)。
能够在不一样的函数中使用名称相同的局部变量,由于只有声明过该变量的函数才能识别出该变量。
只要函数运行完毕,本地变量就会被删除。
全局 JavaScript 变量
在函数外声明的变量是全局变量,网页上的全部脚本和函数都能访问它。
向未声明的 JavaScript 变量来分配值
若是把值赋给还没有声明的变量,该变量将被自动做为全局变量声明。
将声明一个全局变量,即便它在函数内执行。
函数支持闭包
函数支持闭包,也便是说,函数可使用函数以外定义的变量。
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> var say = 'hello world' function fun(){ alert(say) } fun() </script> <!-- 在上面这段代码中,脚本被载入内存后,并无为函数 fun() 计算变量 say 的值。该函数捕获 say 的值只是为了之后的使用,say 将在函数调用 fun() 时(最后一行)被赋值,显示消息 "hello world"。--> </body> </html>
JavaScript 运算符
若是把数字与字符串相加,结果将成为字符串。
逗号运算符
用逗号运算符能够在一条语句中执行多个运算。经常使用在变量声明中。
var iNum1 = 1, iNum = 2, iNum3 = 3;
JavaScript Switch 语句
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <p id="demo"><p> <button type="button" onclick='fun()'>try it</button> <script type="text/javascript"> function fun(){ var str ='' var day = new Date().getDay(); switch(day)//注意day返回的是星期几,也就是数字0-6 { case 1: str = 'today is mon' break case 2: str = 'today is Tus' break case 3: str = 'today is wens' break case 4: str = 'today is thus' break case 5: str = 'today is fri' break case 6: str = 'today is sat' break case 7: str = 'today is sun' break default: str='expecting weekends' } document.getElementById('demo').innerHTML=str; } </script> </body> </html>
for循环
<!DOCTYPE html> <html> <head> <title>html</title> <!-- javascript 遍历对象属性 --> </head> <body> <p id="demo"><p> <button type="button" onclick='fun()'>try it</button> <script type="text/javascript"> var i; var txt = '' function fun(){ var person = {'name':'bill','age':'23','cookie':'true','single':'true'} for(i in person){ txt+=i+'<br/>' } document.getElementById('demo').innerHTML=txt; } </script> </body> </html>
do/while
<!DOCTYPE html> <html> <head> <title>html</title> <!-- javascript do/while --> </head> <body> <p id="demo"><p> <button type="button" onclick='fun()'>try it</button> <script type="text/javascript"> var i = 0; var txt = ''; function fun(){ do { txt+= 'js running the '+i+'times'+'<br/>' i++ } while(i < 5) document.getElementById('demo').innerHTML = txt; } </script> </body> </html>
while 遍历数组
<!DOCTYPE html> <html> <head> <title>html</title> <!-- javascript do/while 遍历数组 --> </head> <body> <p id="demo"><p> <script type="text/javascript"> var i = 0; var cars = ['baoma','benchi','qq','aodi'] while(cars[i]){ document.write(cars[i]+'<br/>') i++ } </script> </body> </html>
try/catch
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script> function myFunc() { try { var x = document.getElementById('inputName').value; if (x == '') throw 'the input number should not be empty'; if (isNaN(x)) throw 'the input content should be number'; if (x < 5) throw 'the number was too small'; if (x > 10) throw 'the number was too large'; } catch (err) { var y = document.getElementById('miss'); y.innerHTML = 'error ' + err; } } </script> <input type="text" id='inputName'> <button type='button' onclick='myFunc()'>click</button> <p id='miss'></p> </body> </html>
经过标签名查找 HTML 元素
getElementsByTagName
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <div id = 'main'> <span>this is the first doc</span> <p>this is the second doc</p> <p>this is the third doc</p> </div> <script> var x = document.getElementById('main'); var y = x.getElementsByTagName('p'); document.write('The first doc is '+y[0].innerHTML) </script> </body> </html>
改变 HTML 内容
修改 HTML 内容的最简单的方法时使用 innerHTML 属性。
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <p id='main'>this is the first doc</p> <script> document.getElementById('main').innerHTML='angularjs' </script> </body> </html>
改变 HTML 样式
如需改变 HTML 元素的样式,请使用这个语法:
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <p id='main'>this is the first doc</p> <script> document.getElementById('main').style.color='red' </script> </body> </html>
点击更改html
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <p onclick="this.innerHTML='Thank you'">please click it</p> </body> </html> <!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script> function func(id){ id.innerHTML='Thank you!' } </script> <p onclick="func(this)">please click it</p> </body> </html>
打印系统时间
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <p id='demo'></p> <script> function func(){ document.getElementById('demo').innerHTML= Date(); } </script> <button type='button' onclick="func()">please click it</p> </body> </html> button和点击分离 <!DOCTYPE html> <html> <!-- 能够将点击按钮分离 --> <head> <title>html</title> </head> <body> <button id='btm'>click here</button> <script> document.getElementById("btm").onclick = function() { displayDate() } function displayDate() { document.getElementById("demo").innerHTML = Date() } </script> <p id="demo"></p> </body> </html>
onload事件
<!DOCTYPE html> <html> <!-- onload 事件检查cookie是否开启 --> <head> <title>html</title> </head> <body onload="checkCookies()"> <script type="text/javascript"> function checkCookies(){ if(navigator.cookieEnabled==true){ alert('cook enabled') }else{ alert('cookie down') } } </script> </body> </html>
onchange事件,点击离开,输入内容大写
<!DOCTYPE html> <html> <!-- onchange事件点击离开,输入的英文变大写 --> <head> <title>html</title> </head> <body> <script type="text/javascript"> function func(){ var x = document.getElementById('demo'); return x.value = x.value.toUpperCase() } </script> <input type="text" id="demo" onchange="func()"> </body> </html>
mouseover/mouseout
<!DOCTYPE html> <html> <!-- onmouseout onmouseover事件点击离开,更改样式 --> <head> <title>html</title> </head> <body> <div onmouseover="mover(this)" onmouseout="mout(this)" style="background-color: green;height:100px;width:100px;text-align: center">what 's that</div> <script type="text/javascript"> function mover(obj){ obj.innerHTML='THANK YOU' } function mout(obj){ obj.innerHTML='LEAVE' } </script> </body> </html>
mouseup/mousedown
<!DOCTYPE html> <html> <!-- onmouseup onmousedown事件点击离开,更改样式 --> <head> <title>html</title> </head> <body> <div onmouseup="mover(this)" onmousedown="mout(this)" style="background-color: green;height:100px;width:100px;text-align: center"></div> <script type="text/javascript"> function mover(obj){ obj.innerHTML='please click mouse' obj.style.backgroundColor='red' } function mout(obj){ obj.innerHTML='please release your mouse' obj.style.backgroundColor='#ccc' } </script> </body> </html>
当输入字段得到焦点时,会触发改变背景颜色的函数。
<!DOCTYPE html> <html> <!-- onfocus 当输入字段得到焦点时,会触发改变背景颜色的函数。--> <head> <title>html</title> </head> <body> <script type="text/javascript"> function func(obj){ // return obj.style.backgroundColor = 'yellow' obj.style.background='red'//使用这两种方式均可以 } </script> <input type="text" onfocus="func(this)"> </body> </html>
建立新的 HTML 元素
如需向 HTML DOM 添加新元素,你必须首先建立该元素(元素节点),而后向一个已存在的元素追加该元素。
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <div id='main'> <p id='p1'>the second para</p> <p id='p2'>the second para</p> </div> <script type="text/javascript"> var p = document.createElement('p3') var node = document.createTextNode('This is something new') p.appendChild(node) var e2 = document.getElementById('main') e2.appendChild(p) </script> </body> </html>
删除已有的 HTML 元素
如需删除 HTML 元素,你必须首先得到该元素的父元素
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <div id='main'> <p id='p1'>the first para</p> <p id='p2'>the second para</p> <p id='p3'>the third para</p> </div> <script type="text/javascript"> var a1 = document.getElementById('main'); var a2 = document.getElementById('p1') a1.removeChild(a2) </script> </body> </html>
javascript 面对对象
使用预约义对象只是面向对象语言的能力的一部分,它真正强大之处在于可以建立本身专用的类和对象。
工厂方式
原始方式
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> var person = new Object(); person.color = 'yellow'; person.hight = 230; person.hands = 2; //最后一个属性其实是指向函数的指针,意味着该属性是个方法。执行这段代码后,就可使用对象 car。 person.action = function(){ document.write(this.color); } person.action(); </script> </body> </html>
工厂模式
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> function createPerson(){ var person = new Object(); person.color = 'yellow'; person.hight = 230; person.hands = 2; person.action = function(){ document.write(this.color); } return person; } var person1 = createPerson(); var person2 = createPerson(); person1.action(); document.write('<br>') person2.action(); </script> </body> </html> 返回 person 对象(person)做为函数值。调用此函数,将建立新对象,并赋予它全部必要的属性,复制出一个咱们在前面说明过的 person 对象。所以,经过这种方法,咱们能够很容易地建立 person 对象的两个版本(person1 和 person2),它们的属性彻底同样。
工厂模式传递参数
<!DOCTYPE html> <html> <!--给工厂模式传递参数--> <head> <title>html</title> </head> <body> <script type="text/javascript"> function createPerson(skinColor,phsiHight,hanNum){ var person = new Object(); person.color = skinColor; person.hight = phsiHight; person.hands = hanNum; person.action = function(){ document.write(this.color); } return person; } var person1 = createPerson('yellow',100,2); var person2 = createPerson('black',130,2); person1.action(); document.write('<br>') person2.action(); </script> </body> </html> 给 createPerson() 函数加上参数,便可为要建立的 person 对象的 skinColor、phsiHight 和 hanNum 属性赋值。这使两个对象具备相同的属性,却有不一样的属性值
将函数方法定义在工厂函数外面
<!DOCTYPE html> <html> <!--在工厂函数外定义对象的方法--> <head> <title>html</title> </head> <body> <script type="text/javascript"> function action(){ document.write(this.color) } function createPerson(skinColor,phsiHight,hanNum){ var person = new Object(); person.color = skinColor; person.hight = phsiHight; person.hands = hanNum; person.action = this.action; return person; } var person1 = createPerson('yellow',100,2); var person2 = createPerson('black',130,2); person1.action(); document.write('<br>') person2.action(); </script> </body> </html> <!-- 每次调用函数 createPerson(),都要建立新函数 action(),意味着每一个对象都有本身的 action() 版本。而事实上,每一个对象都共享同一个函数。 -->
构造函数方法
<!DOCTYPE html> <html> <!--构造函数方法--> <head> <title>html</title> </head> <body> <script type="text/javascript"> function Person(skinColor, phsiHight, hanNum) { this.color = skinColor; this.hight = phsiHight; this.hands = hanNum; this.action = function() { document.write(this.color) } } var person1 = new Person('yellow', 100, 2); var person2 = new Person('black', 130, 2); person1.action(); document.write('<br>') person2.action(); </script> </body> </html>
构造函数方法与工厂方式的差异。
首先在构造函数内没有建立对象,而是使用 this 关键字。使用 new 运算符构造函数时,在执行第一行代码前先建立一个对象,只有用 this 才能访问该对象。而后能够直接赋予 this 属性,默认状况下是构造函数的返回值(没必要明确使用 return 运算符)。
如今,用 new 运算符和类名 Person 建立对象,就更像 ECMAScript 中通常对象的建立方式了。
就像工厂函数,构造函数会重复生成函数,为每一个对象都建立独立的函数版本。不过,与工厂函数类似,也能够用外部函数重写构造函数,一样地,这么作语义上无任何意义。这正是下面要讲的原型方式的优点所在。
原型方式
<!DOCTYPE html> <html> <!--原型方式--> <head> <title>html</title> </head> <body> <script type="text/javascript"> function Person(){//该方式利用了对象的 prototype 属性,能够把它当作建立新对象所依赖的原型。 //这里,首先用空构造函数来设置类名。而后全部的属性和方法都被直接赋予 prototype 属性。 } //经过给 Car 的 prototype 属性添加属性去定义 Car 对象的属性。 Person.prototype.color = 'yellow'; Person.prototype.hight = 100; Person.prototype.hands = 2; Person.prototype.action = function() { document.write(this.color) } //调用 new Person() 时,原型的全部属性都被当即赋予要建立的对象,意味着全部 Person 实例存放的都是指向 action() 函数的指针。从语义上讲,全部属性看起来都属于一个对象,所以解决了前面两种方式存在的问题。 var person1 = new Person(); var person2 = new Person(); person1.action(); document.write('<br>') person2.action(); </script> </body> </html>
混合的构造函数
<!DOCTYPE html> <html> <!--混合的构造函数--> <head> <title>html</title> </head> <body> <script type="text/javascript"> function Person(sinkColor,job,gender){ this.color = sinkColor; this.title = job; this.sex = gender; this.numbers = new Array('bill','mike') } Person.prototype.show = function(){ document.write(this.title) } var person1 = new Person('yellow','ceo','man'); var person2 = new Person('red','dev','femal'); person1.numbers.push('iven'); document.write(person1.numbers) document.write('<br>') document.write(person2.numbers) </script> </body> </html>
字符串拼接,资源消耗问题
var str = "hello "; str += "world";
实际上,这段代码在幕后执行的步骤以下:
建立存储 "hello " 的字符串。 建立存储 "world" 的字符串。 建立存储链接结果的字符串。 把 str 的当前内容复制到结果中。 把 "world" 复制到结果中。 更新 str,使它指向结果。
每次完成字符串链接都会执行步骤 2 到 6,使得这种操做很是消耗资源。若是重复这一过程几百次,甚至几千次,就会形成性能问题。解决方法是用 Array 对象存储字符串,而后用 join() 方法(参数是空字符串)建立最后的字符串。想象用下面的代码代替前面的代码:
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> var arr = new Array(); arr[0] = 'hello' arr[1] = 'world' var str = arr.join(',') document.write(str) </script> </body> </html>
这样,不管数组中引入多少字符串都不成问题,由于只在调用 join() 方法时才会发生链接操做。此时,执行的步骤以下:
建立存储结果的字符串 把每一个字符串复制到结果中的合适位置
虽然这种解决方案很好,但还有更好的方法。问题是,这段代码不能确切反映出它的意图。要使它更容易理解,能够用 StringBuffer 类打包该功能:
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> function StringBuffer(){ this._s_ = new Array(); } StringBuffer.prototype.append = function(str){ this._s_.push(str) } StringBuffer.prototype.toString = function(){ return this._s_.join(","); } var buffer = new StringBuffer(); buffer.append('hello') buffer.append('world') var strs = buffer.toString() document.write(strs) </script> </body> </html>
这段代码首先要注意的是 s 属性,本意是私有属性。它只有两个方法,即 append() 和 toString() 方法。append() 方法有一个参数,它把该参数附加到字符串数组中,toString() 方法调用数组的 join 方法,返回真正链接成的字符串。要用 StringBuffer 对象链接一组字符串
<!DOCTYPE html> <html> <head> <!-- 建立 Date 对象时,若是没有参数,赋予对象的是当前的日期和时间。要计算链接操做历经多少时间,把日期的毫秒表示(用 getTime() 方法的返回值)相减便可。这是衡量 JavaScript 性能的常见方法 --> <title>html</title> </head> <body> <script type="text/javascript"> var d1 = new Date(); function StringBuffer(){ this._s_ = new Array(); } StringBuffer.prototype.append = function(str){ this._s_.push(str) } StringBuffer.prototype.toString = function(){ return this._s_.join(","); } var buffer = new StringBuffer(); for(var i = 0;i<10000000;i++){ buffer.append('txt') } var strs = buffer.toString() var d2 = new Date(); document.write('<h1>buffer time:</h1>') document.write(d2.getTime()- d1.getTime()) for(var i = 0;i<10000000;i++){ var txt = txt + "txt"; } var d3 = new Date(); document.write('<h1>str time:</h1>') document.write(d3.getTime()-d2.getTime()); </script> </body> </html>
重命名已有的方法
能够给已有的方法名更更名称,好比能够给 Array 类添加两个方法 enq() 和 inq(),只让它们反复调用已有的 push() 和 shift() 方法便可:
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> Array.prototype.enq = function(v1){ return this.push(v1) } Array.prototype.inq = function(){ //shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。 return this.shift(); } var arr = new Array(3); arr[0] = 'm1'; arr[1] = 'm2'; arr[2] = 'm3'; arr.enq('mike'); document.write(arr); document.write('<br>') arr.inq(); document.write(arr) </script> </body> </html>
创造方法
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置.可是Array没有indexof方法,这里能够给Array建立一个indexof方法
<!DOCTYPE html> <html> <head> <title>html</title> </head> <body> <script type="text/javascript"> Array.prototype.indeof = function(v){ for(var i = 0;i<this.length;i++){ if(v==this[i]){ return i } } return -1; } var arr = new Array('m1','m2','m3'); var str = arr.indeof('m2') document.write(str) </script> </body> </html>
重定义已有方法
就像能给已有的类定义新方法同样,也可重定义已有的方法。如前面的章节所述,函数名只是指向函数的指针,所以能够轻松地指向其余函数。
<!DOCTYPE html> <html> <head> <title>html</title> <!-- 重定义已有方法 --> </head> <body> <script type="text/javascript"> Function.prototype.toString = function(){//重定义toString方法,返回指定字符串 return'strings' } function sayHi(){ document.write('something') } document.write(sayHi.toString()) </script> </body> </html>
从新定义toString方法,可是保留它的原始指针
<!DOCTYPE html> <html> <head> <title>html</title> <!-- 重定义已有方法 Function 的 toString() 方法一般输出的是函数的源代码。覆盖该方法,能够返回另外一个字符串 不过,toString() 指向的原始函数怎么了呢?它将被无用存储单元回收程序回收,由于它被彻底废弃了。没有可以恢复原始函数的方法,因此在覆盖原始方法前,比较安全的作法是存储它的指针,以便之后的使用。有时你甚至可能在新方法中调用原始方法:--> </head> <body> <script type="text/javascript"> Function.prototype.originalToString = Function.prototype.toString;//这个表达式的意思是存储它的指针 Function.prototype.toString = function(){ if(this.originalToString().length > 100){ return 'too long to display' }else{ return this.originalToString(); } } function sayHi(){ alert('something') } document.write(sayHi.toString()) </script> </body> </html>
javascript的继承机制的实现
选定基类后,就能够建立它的子类了。基类只是用于给子类提供通用的函数。在这种状况下,基类被看做抽象类。
尽管 ECMAScript 并无像其余语言那样严格地定义抽象类,但有时它的确会建立一些不容许使用的类。一般,咱们称这种类为抽象类。
建立的子类将继承超类的全部属性和方法,包括构造函数及方法的实现。记住,全部属性和方法都是公用的,所以子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也能够覆盖超类的属性和方法。
继承的方式
和其余功能同样,ECMAScript 实现继承的方式不止一种。这是由于 JavaScript 中的继承机制并非明确规定的,而是经过模仿实现的。这意味着全部的继承细节并不是彻底由解释程序处理。做为开发者,你有权决定最适用的继承方式。
1,对象冒充
它是在开发者开始理解函数的工做方式,尤为是如何在函数环境中使用 this 关键字后才发展出来。
<html> <head> <title>Example</title> </head> <!-- 构造函数使用 this 关键字给全部属性和方法赋值(即采用类声明的构造函数方式)。由于构造函数只是一个函数,因此可以使 ClassA 构造函数成为 ClassB 的方法,而后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB: --> <body> <script type="text/javascript"> function ClassA(sColor) { this.color = sColor; this.sayColor = function() { document.write(this.color) }; } function ClassB(Lor, sName) { this.newMethod = ClassA;//由于构造函数只是一个函数,因此可以使 一个构造函数成为 另外一个函数的方法 this.newMethod(Lor); delete this.newMethod;//最后一行代码删除了对 ClassA 的引用,这样之后就不能再调用它。 this.name = sName; this.sayName = function() { document.write(this.name) }; } var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); document.write('<br>') objB.sayColor(); document.write('<br>') objB.sayName(); </script> </body> </html>
对象冒充可实现多重继承
UML
这里存在一个弊端,若是存在两个类 ClassX 和 ClassY 具备同名的属性或方法,ClassY 具备高优先级。由于它从后面的类继承。除这点小问题以外,用对象冒充实现多重继承机制垂手可得。
因为这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即 call() 和 apply()。
Call() 方法
<html> <head> <title>Example</title> </head> <!-- 构造函数使用 this 关键字给全部属性和方法赋值(即采用类声明的构造函数方式)。由于构造函数只是一个函数,因此可以使 ClassA 构造函数成为 ClassB 的方法,而后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB: --> <body> <script type="text/javascript"> function ClassA(sColor) { this.color = sColor; this.sayColor = function() { document.write(this.color) }; } function ClassB(Lor, sName) { //this.newMethod = ClassA; //this.newMethod(Lor); //delete this.newMethod; ClassA.call(this,Lor)//call() 方法是与经典的对象冒充方法最类似的方法。它的第一个参数用做 this 的对象。其余参数都直接传递给函数自身。这里的this等于建立了新的ClassB对象,Lor对于两个类来讲都是惟一的参数 this.name = sName; this.sayName = function() { document.write(this.name) }; } var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); document.write('<br>') objB.sayColor(); document.write('<br>') objB.sayName(); </script> </body> </html>
var pet = { words:'...', speak: function(say){ console.log(say+''+this.words); } } // pet.speak('speak') //speak ... // this 指的是调用这个方法的对象 pet // 狗有本身的话,可是没有speak的方法 var dog = { words:'wang' } // pet原本指向的是speak方法,可是call改变了执行上下文,pet 的speak就指向了dog //dog 如今有了一个pet的技能 speak pet.speak.call(dog,'speak ')//speak wang
call 实现继承 function pet (words) { this.words = words; this.speak = function(){ console.log(this.words) } } function dog(words){ pet.call(this,words)//dog 没有speak方法,经过call(this) 继承了pet的speak方法 //pet.apply(this,arry) apply和call的区别在于apply传递的是一个参数列表 } var dog = new dog('wang'); dog.speak();//wang
apply方法
<html> <head> <title>Example</title> </head> <body> <script type="text/javascript"> function ClassA(sColor) { this.color = sColor; this.sayColor = function() { document.write(this.color) }; } function ClassB(Lor, sName) { //this.newMethod = ClassA; //this.newMethod(Lor); //delete this.newMethod; ClassA.apply(this,arguments)//第一个参数还是 this,第二个参数是只有一个值 Lor 的数组。能够把 ClassB 的整个 arguments 对象做为第二个参数传递给 apply() 方法: this.name = sName; this.sayName = function() { document.write(this.name) }; } var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); document.write('<br>') objB.sayColor(); document.write('<br>') objB.sayName(); </script> </body> </html> //固然,只有超类中的参数顺序与子类中的参数顺序彻底一致时才能够传递参数对象。若是不是,就必须建立一个单独的数组,按照正确的顺序放置参数。
call(),apply(),bind()的区别
<!DOCTYPE html> <html> <!-- 改变执行上下文,call, apply,bind, call 方法可将一个函数的对象上下文从初始的(初始值)上下文改变为由 thisObj 指定的新对象。 若是没有提供 thisObj 参数,那么 Global 对象被用做 thisObj。同apply相似,惟一区别是: apply()把参数打包成Array再传入; call()把参数按顺序传入。--> <body> <script type="text/javascript"> var obj = { log: function() { alert(this.foo); }, foo: 'foo' }; var temp = { foo:'bar' }; obj.log.bind(temp)();//bar obj.log.apply(temp);//bar obj.log.call(temp);//bar </script> </body> </html>
好比,在举一个例子: <!DOCTYPE html> <html> <!-- 在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。 在说区别以前仍是先总结一下三者的类似之处: 一、都是用来改变函数的this对象的指向的。 二、第一个参数都是this要指向的对象。 三、均可以利用后续参数传参。 --> <head> <title>比较apply,call,bind的区别</title> </head> <body> <script type="text/javascript"> var o ={ name:'mike', age:'20', say: function(){ alert(this.name+' this year '+this.age+' years old') } } var b = { name:'mk', age:'21' } o.say() </script> </body> </html> 这段代码打印出来的确定是mike this year 20 years old
<!DOCTYPE html> <html> <!-- 那么如何用 o 的say方法来显示 b 的数据呢。这是就须要调用call,apply,bind --> <head> <title>比较apply,call,bind的区别</title> </head> <body> <script type="text/javascript"> var o ={ name:'o data', age:'20', say: function(){ alert(this.name+' this year '+this.age+' years old') } } var b = { name:'b data', age:'21' } // o.say() alert('will display call b data') o.say.call(b) alert('will dispaly apply b data') o.say.apply(b) alert('will display bind b data') o.say.bind(b)() </script> </body> </html>
<!DOCTYPE html> <html> <!-- call,apply直接调用,bind方法返回的仍然是一个函数,所以后面还须要()来进行调用才能够。 call后面的参数与say方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应的,这就是二者最大的区别。 可是因为bind返回的仍然是一个函数,因此咱们还能够在调用的时候再进行传参。--> <head> <title>比较apply,call,bind的区别</title> </head> <body> <script type="text/javascript"> var object1 ={ name:"object1 data", age:"20", say: function(gender,job){ alert(this.name+" this year " + this.age +" years old "+ gender+ " in microsoft, as a/an "+ job) } } var object2 = { name:"object2 data", age:"21" } // o.say() alert('will display call object2 data'); object1.say.call(object2,"female","developer"); alert('will dispaly apply object2 data'); object1.say.apply(object2,["male","Technical Leader"]); alert('will display bind object2 data'); object1.say.bind(object2)("female","CEO"); </script> </body> </html>
原型链继承
<html> <head> <title>Example</title> <!-- prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的全部实例。原型链利用这种功能来实现继承机制。 --> </head> <body> <script type="text/javascript"> function ClassA() { } ClassA.prototype.color = 'red'; ClassA.prototype.sayColor = function() { document.write(this.color) } function ClassB() { } ClassB.prototype = new ClassA();//把 ClassB 的 prototype 属性设置成 ClassA 的实例。 //调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准作法。要确保构造函数没有任何参数。 ClassB.prototype.name = 'mike' ClassB.prototype.sayName = function() { document.write(this.name) } var objA = new ClassA(); var objB = new ClassB(); objA.color = 'red' objB.name = 'john' objB.color = 'green' objA.sayColor() objB.sayColor() objB.sayName() </script> </body> </html>
混合继承机制
<html> <head> <title>Example</title> </head> <body> <script type="text/javascript"> function ClassA(sColor) { this.color = sColor; } ClassA.prototype.sayColor = function() { alert(this.color); }; function ClassB(sColor, sName) { ClassA.call(this, sColor);//call()继承机制 this.name = sName; } ClassB.prototype = new ClassA();//原型链继承机制 ClassB.prototype.sayName = function() { alert(this.name); }; var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); objB.sayColor(); objB.sayName(); </script> </body> </html>
javasript中须要注意的一些问题
var obj = {name:'michael',age:'23',gender:'male'} var txt = '' for(var i in obj){//这里能够不加 var,直接写‘i’可是会把i 作为全局的变量 window.i txt +=obj[i]//obj是一个对象,可是能够这样写 obj[i],由于集合也是对象。 } console.log(txt)//michael23male
javascript页面加载刷新就会自动执行部分脚本,请看下面demo
<ul> <li>click me</li> <li>click me</li> <li>click me</li> <li>click me</li> </ul> var eles = document.getElementsByTagName('li') var len = eles.length; for(var i = 0;i<len;i++){ eles[i].onclick = function(){ console.log(i)// 4 4 4 4 } } 页面加载后会自动把脚本部分执行,执行完脚本,i=4. 当点击li触发onclick事件 此时的i早已经是4
javascript 2种截取字符串的方法 substr 和 slice
var date = '2016-01-05' date.slice(0,7) date.substr(0,7)