JavaScript
起源: 1994年,网景公司(Netscape)发布了历史上第一个比较成熟的网络浏览Navigator浏览器0.9版。但是,这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。而网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。
因此 Netscape 成员 Brendan Eich 借鉴C语言的基本语法并迫于公司要求,借鉴了Java语言的数据类型和内存管理。所以说JavaScript是一种面向函数编程(核心思想) 和面向对象编程的结合体。
JavaScript的特点:
1.JavaScript 是一门(直译式)脚本语言,无需编译,随着网页的加载而运行
2.JavaScript 是可直接插入HTML页面的编程代码,并可以由所有的浏览器解析执行
3.JavaScript 是动态的弱类型语言(和Java相反)
4.JavaScript 主要是面向函数编程的
JavaScript 由 ECMA欧洲电脑制造商协会(European Computer Manufactures Association)通过 ECMAScript 实现语言的标准化。主要围绕DOM(Document Object Model)和BOM(Browser Object Model)操作。
JavaScript使用方式
在提到JavaScript使用方式前,我们先了解下他的一些输出方式,便于测验
(1)文档输出(在浏览器页面上输出内容):document.write("Captain")
(2)控制台输出(F12可打开浏览器控制台):console.log("SpiderMan")
(3)警告弹出框(在页面上出现弹框):alert("I'm coming back!")
(4)提示弹出框:prompt("输入需要显示的文本",“输入提示性文本”)
(5)确认弹出框:confirm("Are you sure to leave?")
JavaScript使用方式一般分为三种:行内,内部,和外部。
1.行内样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>javaScriptTest</title>
</head>
<body>
<a href="#" onclick="alert('Please stop!')"></a>
</body>
</html>
行内样式的缺点:
- 脚本代码和HTML标签一起,可读性差
- 代码的可复用性差
2.内部样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>javaScriptTest</title>
<script>
function print() {
console.log("I'm marco")
}
</script>
</head>
<body>
<a href="#" onclick=print()>click me</a>
</body>
</html>
3.外部样式
将以下部分单独定义到 .js文件中
function print() {
console.log("I'm marco")
}
然后在html文件中去调用(在H5之后<script>
中可以省略type = "text/javascript"
)
<script src="my-function.js"></script>
注意:
1.HTML 中的脚本必须位于<script>
与</script>
标签之间。脚本可被放置在 HTML 页面的 <body>
和 <head>
部分中,但是一般建议放置在body结束之前使用
2.在引用外部js文件的script标签中间,写js是没有效果的
3.HTML页面可以存在多个script标签,但是页面script标签顺序就是自上而下顺序执行的。在引入其他js文件时,
一定注意js文件引入的顺序,否则可能会导致脚本执行不成功。比如说A程序依赖于B程序才能执行,那么B脚本要放在A脚本的上方先被解析执行
JavaScript标识符和命名规范
注意: 和Java规范一样,我们在命名的时候
1.可以包含数字,字母,下划线,$,但是不能以数字开头
2.不能包含JavaScript种的关键字
3.遵循驼峰命名规则,第一个单词首字母小写,其余的首字母大写
以下是我们所用到的标识符
语句 | 描述 |
---|---|
break | 用于跳出循环。 |
catch | 语句块,在 try 语句块执行出错时执行 catch 语句块。 |
continue | 跳过循环中的一个迭代。 |
do … while | 执行一个语句块,在条件语句为 true 时继续执行该语句块。 |
for | 在条件语句为 true 时,可以将代码块执行指定的次数。 |
for … in | 用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。 |
function | 定义一个函数 |
if … else | 用于基于不同的条件来执行不同的动作。 |
return | 退出函数 |
switch | 用于基于不同的条件来执行不同的动作。 |
throw | 抛出(生成)错误 。 |
try | 实现错误处理,与 catch 一同使用。 |
var | 声明一个变量。 |
while | 当条件语句为 true 时,执行语句块。 |
基本语法
Javascript运算符:+、-、*、/、(类型被忽略,只比较值,比如10 == “10”返回true)、=(值和类型都相等)、!=、!==(类型不相等或值不相等)、<、>、<条件>?<条件为true执行> :<条件为false执行> 。
单行注释采用//,多行注释采用/**/。
字面量(固定值)
数字(Number)字面量:可以是整数或者是小数,或者是科学计数(e)。如3.14,5.88
等。
字符串(String)字面量:可使用单引号或双引号。如"Script","HTML"
等
表达式字面量:用于计算的固定值, 如2*3
等。
数组(Array:字面量:定义一个数组。如[a,b,c,d,e]
。
对象(Object:字面量:定义一个对象。如{name:"Marco", age:18}
。
变量
变量的数据类型
(1)5种基本数据类型:number、string、boolean(true或false)、undefined、null
(2)4种对象类型:Object、Date、Array、String。Javascript变量均可作为对象使用。
typeof可以获取变量的类型,如typeof null返回object,typeof undefined返回undefined。
变量的作用域
变量作用域指的是变量的作用范围,javascript中的变量分为全局变量和局部变量。
(1)、全局变量:在函数之外定义的变量,为整个页面公用,函数内部外部都可以访问。
(2)、局部变量:在函数内部定义的变量,只能在定义该变量的函数内部访问,外部无法访问。
基本数据类型
Number类型
Number( 数值类型): 包含整型、浮点型、NaN和Infinity
整型:
var age = 18;
浮点型:
var price = 12.8;//(浮点运算并不总是100%准确,切记不要做小数点的比较!!!)
例如var sum = 0.1 + 0.2的结果是0.30000000000000004
Infinity:
var max = 1/0;
NaN( NOT A NUMBER):
var num = Number("1234abcd"); // Number(value), 此处是吧字符串转化为number类型,输出: NaN console.log(isNaN(num)); // 输出: true, 判断num是不是NaN类型
Boolean类型
boolean: 布尔类型,布尔类型只有两个值:true 和 false
true: 表示为真
false: 表示为假
var flag1 = true;
console.log(typeof flag1); // 输出:boolean
注意: 使用Boolean(value)方法时,当value为0、null、" "、false、undefined或者NaN时,值为false,其他为true。
Undefined类型
undefined类型只有一个值,就是undefined
表示已声明但未赋值的变量,在程序运行中,一般指某个对象没有值,但是参与运算
var num;
console.log(typeof num); // 输出: undefined
注意:undefined的数和string相加为string类型,和其他基本数据类型相加都是undefined
string类型
string类型就是字符串,用双引号("")或单引号(’’)包裹的字符集合。
var str = “I’m coming!”;
字符串简单使用:字符串的拼接,可以用“+”来做拼接。
var str1 = "NB";
var str2 = " A!";
var str3 = str1 + str2;
console.log(str3); // 输出:"NBA!!"
常用方法 | 描述 |
---|---|
x.charAt(n) | 索引为n的字符,也可以使用x[n] |
x.concat(str) | 返回x与str拼接后的字符串 |
String.fromCharCode(n1, n2, …) | 返回Unicode值为n1, n2, …的字符拼接后的字符串 |
x.indexOf(str, start) | 从start位置开始,字符串str在x中首次出现的位置,没有找到返回-1 |
x.lastIndexOf(str, start) | 从start位置开始,字符串str在x中倒序第一次出现的位置,没有找到返回-1 |
String.localeCompare(str1, str2) | 返回str1、str2的语言本地排序结果 |
x.match(RegExp str) | 在x中正则匹配或字符串匹配,将匹配到的字符串放在数组中返回,没有匹配返回null |
x.replace(RegExp str, str func) | 将x中找到的匹配替换为str,或者将找到的匹配替换为函数func作用后的返回值 |
x.search(RegExp str) | 返回字符串x中查找到的第一个匹配的位置,没有找到匹配返回-1 |
x.slice(start, end) | 返回字符串x的切片,左闭右开 |
x.split(str RegExp, n) | 将字符串x按照匹配分隔,返回分隔出的字符串组成的数组,参数n定义最多分隔成几份 |
x.substr(start, length) | 返回字符串x从位置start开始,长度为length的子字符串 |
x.substring(start, ?end) | 返回字符串x从位置start开始,到end为止的子字符串(左闭右开)。end是可选参数, |
x.toLocaleUpperCase() | 将字符串x中所有字符转换成大写后返回 |
x.toLocaleLowerCase() | 将字符串x中所有字符转换成小写后返回 |
x.trim() | 去除字符串x两端的空白后返回新串 |
注意:
1.使用charAt()时,如果索引超出了字符串本身的字符范围时,不会报错,会返回” “空字符串
2.使用subStr(startIndex,[length])时,startIndex如果为负数,那么只会返回最后一个数
3.使用replace(oldStr,newStr)时newStr只会替换掉第一个oldStr,如需全部替换,需要用到正则方式
replace(new RegExp(oldStr,“g”),newStr)
Null类型
null类型只有一个值,就是null,从逻辑角度看,null值表示一个空对象指针。
var obj = null;
console.log(typeof obj); // 输出:object
因为null表示的是一个空对象的指针,所以使用typeof操作符检测null会返回object的原因。
Array
数组的创建有三种方式:
(1) var arr = ["batman“,”spiderman","ironman",1,2,3,true];
(2) var arr = new Array("batman“,”spiderman","ironman",1,2,3);
(3) var arr = new Array(10);//指定数组的长度为10,不过由于数组长度动态调整,所以意义不大
注意:
1.JavaScript在同一个数组中可以存放多种类型的元素,而且是长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改。
数组常用方法
/*通过字面方式定义一个数组*/
var arr = ["thon","ironman","spidermen",1,2,3,true];
/*splice的用法*/
var newArr = arr.splice(1,2);//从索引为1的元素开始,删除2个元素
var newArr = arr.splice(1,0,"black widow");//在索引为1的位置插入元素,后面的元素后移
var newArr = arr.splice(1,1,["Captain America",true]);//从索引为1的元素开始,删除1个元素,并添加2个元素
console.log(arr);
/*利用join()将数组转字符串*/
var newArr = arr.join("-");
console.log(newArr)//输出“thon-Captain America,true-1-2-3-true”
/*数组的添加和删除元素*/
var newArr = arr.push("Thor");//在数组最后面添加元素;
var newArr = arr.unshift("Ant-Man");//在数组的最前面添加元素
var newArr = arr.pop("Thor");//弹出数组最后面的添加元素;
var newArr = arr.shift("Ant-Man");//移除数组最前面添加的元素
Date
以下是Date对象的常用方法,如果需要设置时间,将get换成set即可
方法 | 描述 |
---|---|
getFullYear() | 从 Date 对象以四位数字返回年份。 |
getMonth() | 从 Date 对象返回月份 (0 ~ 11)。 |
getDate() | 从 Date 对象返回一个月中的某一天 |
getDay() | 从 Date 对象返回一周中的某一天 (0 ~ 6)。 |
getHours() | 返回 Date 对象的小时 (0 ~ 23)。 |
getMinutes() | 返回 Date 对象的分钟 (0 ~ 59)。 |
getSeconds() | 返回 Date 对象的秒数 (0 ~ 59)。 |
getMilliseconds() | 返回 Date 对象的毫秒(0 ~ 999)。 |
getTime() | 返回 1970 年 1 月 1 日至今的毫秒数。 |
补充:
循环定时器:周而复始的执行
/*参数一是函数名称,参数二是间隔的毫秒数*/
var time = setInterval(fun,3000);
var num = 0;
function fun() {
num++;
if(num == 5) {
clearInterval(time);//清除定时器
console.log("每三秒出现一次");
}
函数
函数:就是由事件驱动的或者当它被调用时执行的可重复使用的代码块。当调用该函数时,会执行函数内的代码。可以在某事件发生时直接调用函数(比如当用户点击按钮时),并且可由 JavaScript 在任何位置进行调用。
函数的定义
function 函数名(参数1, 参数2, ... , 参数3) {
// 需要执行的代码块
}
1、function是一个关键字, 和var、typeof一样, 都是关键字, 后面要加空格;
2、函数名的命名规范和变量命名一样, 只能是字母、数字、下划线、美元符号, 不能以数字开头, 一般采用驼峰式命名大;
3、函数名后的()中放置函数形参, 形参可以为任意多个(意味着可以没有形参), 如有有多个形参用","隔开;
4、JavaScript函数允许有返回值,返回关键字为return。当函数返回值后,函数将停止执行,在return后面的语句将不会被执行。
变量的作用域
变量按照作用域划分有局部变量和全局变量。
局部变量
在JavaScript函数内部声明的变量(使用var声明的)是局部变量,所以只能在函数内部访问它(该变量的作用域是局部的),因此,变量名称相同的元素可以同时出现在不同的函数领域中。
注意: 只要函数运行完毕,局部变量就会被销毁回收
全局变量
在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。
在函数内部没使用var来声明的变量也属于全局变量。
就近原则: 在函数内部使用某一个变量, 会优先查看函数内部中是有这个变量, 如果函数内部有这个变量, 那么使用的这个变量就是函数内部声明的变量; 反之函数内部没有这个变量, 那么使用的变量就有可能是函数外部的变量(最后如果在全局变量中也没有,那么直接提示错误))。
变量的生存期
JavaScript 变量的生命期从它们被声明的时间开始。
局部变量会在函数运行完毕后被销毁。
全局变量会在页面关闭后被销毁。
对象
JavaScript 提供多个内建对象,比如 Object、String、Date、Array 等等,此外 JavaScript 允许自定义对象。对象只是带有属性和方法的特殊数据类型。
创建对象方式
1.new关键字创建
var obj = new Object();
obj.name = "Hulk";
obj.attack = function () {
console.log("浩克冲撞!");
};
缺点:
(1):对象没有辨识度,都是Object的对象
(2):每创建一次对象,属性都要重写一遍,代码复用性极差
2.字面量创建对象
var obj = {
name : "IronMen",
age : 38,
attack : function (money) {
console.log(this.name + ":" + this.age + "的资产有:" + money);
}
};
obj.attack(10000000000000);
缺点:想创造属性,方法名称相同但是值不同的对象需要创建多个,造成代码的重复
3.工厂模式创建对象
function createHero (name , age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.getInfo = function () {
return this.name + this.age;
};
return obj;
}
var hero = createHero("Captain Marvel",40)
console.log(hero);
var heroInfo = hero.getInfo();
console.log(heroInfo);
缺点:无法确定对象的来源,因为创造出来的对象都是Object的实例,因此存在识别上的问题
4.构造函数创建对象
function Hero (name , age) {
this.name = name;// 此处的this代表就是全局对象window
this.age = age;
this.sayHi = function (name) {
console.log(this.name + ":Hello" + name);
};
}
var hero = new Hero("Captain Marvel",40);
console.log(hero);
hero.sayHi("Thor")
此方法,解决了可识别问题,并且我们只定义了对象的架构,需要调用的时候,直接传参new对象即可,提高了代码的复用性,但是同样存在缺陷。
alert(hero.sayHi == hero2.sayHi);//输出false
缺点:通过构造函数创建对象时,当一个构造函数被实例化多次时,构造函数里的方法也被实例化了多次,同一类型的不同对象之间并不共用同一函数,造成了内存的浪费。
5.原型模式创建对象
/*方式一*/
function Hero() {};
Hero.prototype.name = "Captain Marvel";
Hero.prototype.age = 40;
Hero.prototype.sayHi = function (name) {
console.log(this.name + ":Hello" + name);
}
var hero = new Hero();
var hero2 = new Hero();
alert(hero.sayHi == hero2.sayHi);
/*方式二*/
function Hero() {};
Hero.prototype = {
constructor:Hero,
name:"Captain Marvel",
age:40,
sayHi:function (name) {
console.log(this.name + ":Hello" + name);
}
}
使用原型模式相当于创建了一个共享模板,因此,原型中的内容被new了之后,也都是可共享的
但是如果需要修改原型会比较麻烦,需要进到原型地址中修改原型内容,或者直接修改对象的属性
var hero = Hero();
hero.name = "Thor"
hero.age = "28"
6.寄生构造函数创建对象
function Hero(name,age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.getInfo = function () {
return this.name + this.age;
}
return obj;
}
寄生构造函数的架构和工厂模式很相像,但是工厂模式是在内部帮你new对象,而寄生构造函数创建对象是在外面自己new对象,因此可以说工厂模式和寄生构造函数模式在功能上是等价的。
事实上,两者本质上的差别仅在于new操作符(因为函数取什么名字无关紧要),工厂模式创建对象时将createHero看作是普通的函数,而寄生构造函数模式创建对象时将Person看作是构造函数,不过这对于创建出的对象来说,没有任何差别。
补充:
遍历对象或者数组的方式:
for(var attr in hero) {
if(typeof hero[attr] != "function") {
console.log("属性" + hero[attr]);
}
}