前言 :常用的输出语句
window.alert()——>写入提示框
document.write()——>写入html输出
console.log()——>写入浏览器控制台
一、JavaScript的变量
1.声明关键字var
与java和C不同,JavaScript不需要在声明时确定变量的数据类型。使用var定义的变量可以自适应任何赋予其中的数据类型。
<script>
var a=6;
console.log("a="+a);
a="hello!"
console.log("a="+a);
a=true;
console.log("a="+a);
</script>
结果:
二、强制类型转换
1.将其他类型转化为Number型
①使用Number()函数
null==>0;
boolean: true==>1,false==>0;
undefined==>NaN。
②使用parseInt()函数与parseFloat函数
- 这两种函数都只有效于字符串中的第一串有效数字子串,例如parseInt(123.456)=123,parseFloat(123.456.789)=123.456。
- 如果对非String类型变量使用parseInt()或parseFloat(),则会先对其使用toString()。
- 不同的浏览器对于数字的进制解析不同,例如以下的一串代码
<script>
var a = '070';
a = parseInt(a);
document.write(a);
</script>
在firefox、chrome中会显示70,而在老大IE版本种回被识别为八进制二显示成56。
P.S.
0X 八进制
0xX 十进制
0bX 二进制
解决方法:向parseInt中传入第二个参数,用来表示解析的进制数。如parseInt(“070”,8) = 56。
Tips
使用paeseInt()函数,能直接将小数转换为整数。
2.将其他类型转化为Boolean型
使用Boolean()函数:
Number ----> Boolean:除了0和NaN为false,其余全为true。
String ----> Boolean:除了空串为false,其余全为true。
null/undefined ----> Boolean:全为false。
三、算数运算符
1. “+”
① 与其他语言差不多,当Number类型与非Number类型(除String外)的值相加时,会将这些值先转化为Number然后再算,但需要注意的是任何值+NaN结果都为NaN。
② String类型的转化优先级较高,因此会将非String的值转化为String后做拼接操作。
Tips
针对这一特性,a = a + “” 就是toString的隐式转化式。
2. “-”,“÷”,"*"
① 除了"+"运算外,其余运算都会自动转化为Number类型。
- 100 - “1” = 99。
- “8” * 2 = 16。
- undefined * 2 = NaN。
Tips
针对这一特性,a = a - 0 ,a = a / 1, a = a * 1就是number()的隐性类型转化式。
② 不同于C语言等常规语言,"/"会区分整数与浮点数。
- 4 / 2 = 2
- 3 / 2 = 1.5
3. “+”(正号),"-"(负号)
①负号可以对Number类型进行取反,对非Number类型的值,会先将其转化为Number类型后再进行取反。
②可以对一个数据类型使用+,来将其转化为Number类型。例如:
<script>
// console.log('aaaa');
var a = 1 + +"2" + 3;
console.log(a);
</script>
结果则会在控制台输出一个类型为Number的6。
四、逻辑运算符
1. “&&”
JS中的&&运算符为短路运算符,例如:
<script>
var a = 1 + +"2" + 3;//6
console.log(a==0 && a++); // false
console.log(a); //a = 6
</script>
在第一个输出语句中,&&运算符左边的等式返回false,由于短路原则不会执行右边的a++,故a依然为6。
2. “||”
JS中的||运算符为短路运算符,例如:
<script>
var a = 1 + +"2" + 3;
console.log(a!=0 || a++);//true
console.log(a);//6
</script>
因此不推荐在逻辑运算符中加入其他赋值运算,如果可以的话,最好还是分开计算后再合并。
3. “&&”与“||”两边为非布尔值
①对非布尔值进行与、或运算时,会先将其转化为boolean类型,然后再运算,并且返回原值。
②与运算:
- 如果第一个值为true,则必然返回第二个值。
- 如果第一个值为false,则直接返回第一个值。
P.S. 均返回原值!!!
<script>
var a = 5 && 7;
console.log(a);//7
a = NaN && 0
console.log(a);//NaN
</script>
③或运算与运算相反。
五、关系运算符
1. ‘<’,’>’,’<=’,’>=’
①对于非数字进行比较时,会将其转化为数字然后再比较。
- 如果符号两侧的值都是字符串,不会将其转化为数字进行比较,而会逐次比较字符串中字符的Unicode编码。因此如果比较的是两个字符类型的数字的话,可能结果会不同,可以在前面加一个"+"转型。
- 如果符号两侧有变量的值为NaN,则返回false。
2. ‘==’
①对于同类型的两个变量,若相等,则返回true,反之,返回false。
②对于不同类型的两个变量,在一般情况下,会将变量都转化为Number类型后在进行比较判断。以下列出几个特殊情况:
<script>
console.log(null == undefined) //true
console.log(null == 0); //false
console.log(NaN == null); //false
console.log(NaN == 0); //false
console.log(NaN == NaN) //false
</script>
解析:NaN不和任何值相等,包括其自身。因此若想判断一个变量的值是否为NaN时,不能直接使用’==’,考虑调用函数isNaN()进行判断。
3. ‘!=’
①对于同类型的两个变量,若不等,则返回true,反之,返回false。
②对于不同类型的两个变量,可将其想象成"=="的逆操作,也就是说不同于C、JAVA等语言,当执行以下代码块时会自动进行类型的转换,之后再进行比较。
<script>
console.log('1' != 1); //false
</script>
P.S.
若想实现C语言、Java语言中包括类型判断的相等与不等运算符,则可以使用"===“与”!= ="。
六、练习: 键盘输入方法-Prompt()函数
1.prompt()可以弹出一个提示框,用户可以在其中输入内容,该函数可添加一串字符串作为提示文字。函数会返回用户输入的内容。
<script>
var age = prompt("请输入您的年龄~");
alert("您的年龄为" + age + "岁");
</script>
七、函数
js的函数通过function关键字定义,与java和c不同,无论函数最后return什么数据类型都用function。
<script>
function myFunction(p1, p2) {
return p1 * p2; // 返回 p1 和 p2 的乘积
}
alert(myFunction(2,6));
</script>
八、对象
对象可以看成一个可以包含多个值的变量,存储形式不同。
1.对象的基本操作
- 普通定义:
var obj = new Object();
obj.name = "Klee";
obj.age = 12;
- 定义的同时添加属性(对象字面量):
var person = {
name:"Klee",
age:8,
gender:"女",
eyeColor:"gold",
sayname:function(){//在对象中封装函数时,这个函数成为这个对象的方法
alert("I'm "+this.name);
}
};
Tips
定义时名和值之间用冒号隔开,多个名值之间用逗号隔开,最后一个不加逗号。
- 调用:person.sayname();
- 删除:delete person.age;
- 添加:person.age=12;
P.S.
如果要用特殊的属性名,不能用.的方式操作,则用[ ],且调用时也要用[ ]:
person[“123”]=789;
console.log(person[“123”]); - 检查对象中是否含有某个属性:console.log(“name” in person);
- 枚举对象中的属性:
for (var n in person){
alert("属性名"+n);
alert("属性值"+person[n])//
}
P.S.
在for in语句枚举中,n在每次循环中会被赋予一个属性名,但是不能直接使用person.n来调用这个属性,因为对象中没有n这个属性,n只是被赋予了这个属性名的变量,他本身不是对象中的一个属性,要想使用这个变量n中的属性名,可以使用person[n] 。
2.对象的存储形式与变量的区别
- 对象是保存在堆内存中的,每创建一个新的对象,就会在对内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响。
- 当比较两个基本数据类型时,就是比较值。当比较两个引用数据类型时,比较的是对象的内存地址 。
九、函数
函数也是对象,可以用来封装一些功能,以便在需要的时候调用执行。
1.函数的声明
function fun(){//直接用函数表达式声明
alert("hello!");
}
var fun2=function(){//创建一个匿名函数再赋值给变量
alert("hello!");
};
P.S.
上述两种函数的声明方式都可以使用,但是由于第二种利用了赋值语句所以在语句的最后要加上分号。
2.函数的参数
调用函数时可以向括号中传入参数
function sum(a,b){
alert(a+b);
}
sum(23,3)
不同于java和C,实参可以是任意数据类型,甚至可以直接传入对象和函数。
var person={
name:"Klee",
gender:"女",
age:18
}
function fun(o){
alert("我是"+o.name+",今年我"+o.age+"岁");
}
fun(person);
3.函数的返回值
就是return,和大多数语言一样,唯一区别就是返回值可以是任意数据类型,这一点从定义函数时不需要设置返回值的数据类型可以看出。
4.立即执行函数
(function(){
alert("我是一个匿名函数");
})();
匿名函数不能直接执行,除非放在括号里并再加上一对括号。立即执行函数往往只执行一次。
5.方法
在java和c中函数和方法往往是指同一个东西,在js中,方法是函数被封装在对象中时的称呼,不过这些也仅仅是名称上的区别。
var person = {
name:"Klee",
sayname:function(){//在对象中封装函数时,这个函数称为这个对象的方法
alert("I'm "+this.name);
}
};
Tips
对象里可以封装函数,函数里也可以添加对象。
十、作用域
作用域指一个变量的作用范围。作用域方面基本与java和c无异
1.全局作用域
- 直接编写在script标签中的js代码,都在全局作用域里。
- 全局作用域在页面打开时创建,在页面关闭时销毁。
- 全局作用域中有一个全局对象window,我们可以直接使用。
- 在全局作用域中创建的变量其实都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存。
- 全局作用域中的变量都是全局变量,在页面中的任意部分都可以被访问。
var a=10;
function fun(){
alert("我是window的方法。");
}
alert(window.a);
window.fun();
2.函数作用域
- 调用函数时创建函数作用域,函数执行完毕后,作用域销毁。
- 每调用一次函数就会创建一个函数作用域,他们之间时互相独立的。
- 函数作用域中可以访问全局作用域的变量
- 在全局作用域中,无法访问函数作用域中的变量。
3.变量的声明提前
- 使用var关键字声明的变量,会在所有的代码执行之前被声明。
alert(a);//a的声明会被提前到所有代码执行之前,但是a的赋值不会,故这里会输出undefined.
var a=10;
4.函数的声明提前
- 使用关键词funtion创建的函数,会在所以代码执行前被声明并创建 。
- 使用关键词var创建函数的话,则只会在所有代码执行前被声明。
fun();//输出“我是fun函数”
fun2();//输出undefined
function fun(){
alert("我是fun函数");
}
var fun2(){
alert("我是fun2函数");
}
十一、this参数
- this是浏览器在调用函数时会向函数内部传递的一个隐含参数,this指向的是一个上下文对象。
- 根据函数调用方式都不同,this可能会指向不同的对象。
①以函数的形式调用,this指向window;
②以方法的形式调用,this指向方法的那个对象。
③当以构造函数的形式调用时,this就是新创建的那个对象。
var name="Klee";
function fun(){
alert(this.name);
}
fun();
上面代码中的以函数的形式调用fun(),实际上fun()是被封装到了window对象中,因此fun()相当于window.fun() ,故this指向window,所以this.name=window.name。
var person={
name:"Klee"
sayname:fun(){
alert(this.name);
}
};
person.fun();
上面的代码表示,以方法的形式调用fun(),this指向这个方法的对象,所以this.name=person.name。
十二、工厂方法
工厂方法批量创建对象。使用工厂方法创建的对象,使用的构造函数都是Object,导致无法区分多种不同类型都对象。
工厂方法实际使用较少。
function createPerson(name,age){
var person = new Object();
person.name = name;
person.age=age;
person.sayname=function(){
alert(this.name);
}
return person;
}
var obj=createPerson("Klee",12);
var obj2=createPerson("Abor",15);
十三、构造函数
1.基础概念
- 构造函数也是用来创建对象的,比较常用。
- 构造函数就是一个普通函数,创建方式与普通函数没有区别,区别在于调用方法的不同,而且通常习惯用首字母大写的函数名。
- 普通函数直接调用,而构造函数需要用new关键字调用。
- 构造函数的执行流程:
1.立刻创建一个新的对象
2.将新建的对象设置为函数中的this,在构造函数中可以使用this来应用新建的对象。
3.逐行执行函数中的代码
4.将新建的对象返回
function Person(name,age){
this.name=name;
this.age=age;
}
var per = new Person("Klee",12);
var per2= new Person("Abor",18);
alert("per的名字="+per.name);
alert("per2的名字="+per2.name);
- 使用instanceof可以检查一个对象是否是一个类的实例
alert(per instanceof Person);//true
P.S.
用java 的术语来讲,构造函数就是类,构造函数创建的对象就是该类的实例。
2.改进方法
- 在第一点中有提到,每创建一个构造方法就会创建一个新的对象,那么看下面的代码
function Person (name){
this.name = name;
this.sayName = function(){
alert("Hello大家好,我是"+this.name);
};
}
用这个构造函数创造的所有对象都会有一个完全一样的sayName方法,这样太过冗余,我们可以按照下面的代码来改进这个构造函数。
//sayName方法在全局作用域中定义,但是不安全可能会被其他程序员覆盖
function fun(){
alert("Hello大家好,我是"+this.name);
}
function Person(name){
this.name = name;
this.sayName = fun;
}
十四、原型对象
1.概念
每创建一个函数,浏览器都会向函数中添加一个属性prototype,即是原型对象。
当这个函数被当做构造函数调用时,它所创建的对象中会有一个隐含的属性,指向构造函数的原型对象,我们可以通过__proto__来访问该属性。
function MyClass(){
}
var mc = new MyClass();
alert(mc.__proto__ == MyClass.__proto__);//true
2.作用
- 原型对象相当于一个公共区域,同一个构造函数创造的对象都可以访问,我们可以将对象共有的内容设置到原型对象中。
- 访问对象中的属性时,它会优先在对象自身中寻找,如果没有找到则会去原型对象中寻找。
有了这个公共区域,我们可以继续优化构造函数了。
function Person(name){
this.name = name;
}
//向构造函数的原型中添加sayName方法
Person.prototype.sayName = function(){
alert("Hello大家好,我是:"+this.name);
};
以后创建构造函数时,可以将对象共有的属性和方法,添加到原型对象中,这样不用分别为每一个对象添加,也不会影响全局作用域。
P.S.
原型对象的共有性质可以简单类比java中的父类,子类都继承父类的属性和方法,而且这些继承下来的东西可以被重写。
Tips
上面提到过,调用构造函数构造的对象中的属性时,若这个对象中没有该属性,则会去原型对象中寻找并使用,这对in关键字查询对象中是否有某个属性时也是一样的。如果想要知道这个对象本身是否含有一个属性,而不考虑原型对象的话,应该使用对象.hasOwnProperty()函数:
function MyClass(){
}
MyClass.prototype.name="我是原型中的名字";
var mc = new MyClass();
alert("name" in mc);//true
alert(mc.hasOwnProperty("name"));//false
这个hasOwnProperty()函数来自原型对象中的原型对象,原型对象也是对象,所以它也有原型。不过这个套娃到此为止,不存在原型的原型的原型了,也就是Object对象的原型没有原型了。
function MyClass(){
}
var mc = new MyClass();
alert(mc.__proto__.hasOwnProperty("hasOwnProperty"));//false
alert(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));//true,这个函数就在原型的原型里
alert(mc.__proto__.__proto__);//Object存在
alert(mc.__proto__.__proto__.__proto__);//null不存在
十五、toString()
1.概念
- 当我们直接在页面中打印一个对象时,事实上是输出对象的toString()方法的返回值。
- 这个方法其实在对象的原型的原型里,也就是在Object对象里。
function Person(name ,age){
this.name = name;
this.age = age;
}
var per = new Person("Klee",12);
//如果我们希望输出对象时不输出[objec Objec],可以为对象重写一个toString()方法,per.toString=function(){}如此,不过如果希望由此构造函数创建的所有对象都享受到这个重写,则应这样写:
Person.prototype.toString = function(){
return "[name="+this.name+",age="+this.age+"]";
};
alert(per);
十六、数组
1.数组对象的基本操作
- 创建:var arr = new Array();
- 语法:arr[索引] = 值;
- 获取数组长度:arr.length
- 向数组的最后添加值:arr[arr.length] = 值;
2.使用字面量创建数组
var arr = [2,4,7,5,9];
console.log(arr.length);//5
//很少用
var arr2 = new Array(10);//这样使用构造函数创建一个长度为10的数组
3.元素
数组的元素可以是任意类型
//甚至可以放对象,函数,数组
var arr = ["hello",2,true,{name:"Klee",age:12},function(){},[1,2,3]];
4.主要方法
- push()方法向数组末尾添加一个活多个元素并返回数组新的长度。
- pop()方法删除数组的最后一个元素,并返回被删的元素。
var arr = [12,3,43];
var len = arr.push(23,43);
console.log(arr);//12,3,43,23,43
alert(len);//5
var re = arr.pop();
console.log(re);//43