1 初见js
1.alert() --警告框
2.document.write() --在计算机页面输出文本
3.console.log() --在计算机页面输出文本
2 js的编写位置
1.body里面
(1)标签onclick属性
例如:< button οnclick=“alert(‘讨厌’)”>按钮< /button>
(2)超链接的href属性
例如: < a href=“javascript:alert(‘你是谁’)”>点一下< /a>
2.script标签里面
例如:
< script type=“text/javascript”>alert(“我是标签代码”)< /script>
3.外部js文件
例如:
< script type=“text/javascript” src=“js/script.js”>
好处:将js代码写到外部js文件,通过script标签引入 。可以在不同页面中同时引入,也可以利用到浏览器的缓存机制。
3 基本语法
1.单行注释//
2.多行注释/**/
3.JS中严格区分大小写
4.JS中每条语句以分号(;)结尾
5.不写分号,浏览器会自动添加,但会消耗一定的系统资源,且浏览器可能会加错分号
6.JS会忽略多个空格和换行
4 字面量和变量
1.字面量
解析:是一些不可改变的值,可直接使用
例如:1 2 3 4
2.变量
解析:变量可保存字面量,变量的值是可随意改变
3.声明变量
解析:js使用var关键字来声明一个变量,声明和初始化同时进行
5 标识符
1.js中可以自主命名的都可以称之为标识符
例如:变量名、函数名、属性名
2.标识符中可以含有字母、数字、_、$
3.标识符不能以数字开头
4.标识符不能是ES中的关键字或者保留字
5.标识符一般使用驼峰命名:首字母小写,每个单词的开头字母大写,其余字母小写
6 数据类型
6.1 基本数据类型
String 字符串、Number 数字、Boolean 布尔值、 Null 空值、 Undefined 未定义、Symbol(ES6)
- JS中的变量都是保存到栈内存中
- 基本数据类型的值直接在栈内存中存储
- 值与值之间是独立存在,修改一个变量不会影响其他的变量
例如:
var a = 123;
var b = a;
a++;
console.log("a = "+a);//124
console.log("b = "+b);//123
6.2 引用数据类型
Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)
- 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间
- 变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个变量修改属性时,另一个也会受到影响
例如:
var obj = new Object();
obj.name = “孙悟空”;
var obj2 = obj;
obj.name = “猪八戒”;
console.log(obj.name);//猪八戒
console.log(obj2.name)//猪八戒
特殊:设置obj2为null,修改变量的值时候,另一个变量不受影响
数据类型比较
- 比较两个基本数据类型的值时,就是比较值
- 比较两个引用数据类型时,它是比较的对象的内存地址
- 引用类型,如果两个对象一摸一样,但是地址不同,返回false
6.3 String
1.字符串需要使用引号引起来;双引号或单引号都可,但不能混着用
2.引号不能嵌套,双引号不能放双引号,单引号不能使用单引号
例如正确做法: str = ‘我说:“喜欢你”’
3.字符串的转义字符
(1) \ " 表示 "
(2) \ ’ 表示 ’
(3) \n 表示 换行
(4) \t 表示 转表符
(5) \ \ 表示 \
6.4 Number
解析:JS中所有数值都使用number类型,包括整数和浮点数(小数)
1.Number.MAX_VALUE表示js中数字的最大值
2.Number.MIN_VALUE示js中数字的最小值
3.使用Number表示的数字超过了最大值,则返回Infinity,表示正无穷; -Infinity表示负无穷
4.NaN表示一个特殊的数字,表示 Not A Number,检查该值时返回Number
5.typeof运算符可检测变量的类型
语法:【typeof 变量】
6.JS进行浮点运算,结果可能不精确;不用JS进行对精确度要求高的运算
6.5 Boolean
解析:布尔值有两个,主要用来负责逻辑判断
true – 表示真
false --表示假
6.6 Null
解析:Null(空值)类型的值只有一个,那就是null
1.null这个值专门用来表示一个为空的对象
2.使用typeof检查null值时,会返回一个object
6.7 undefined
解析: Undefined(未定义)类型的值只有一个,那就是undefined
1.声明一个变量,但不给变量赋值时,他的值就是undefined
2.使用typeof检查undefined值时,会返回一个undefined
7 强制类型转换
解析:指将一个数据类型转换成其他数据类型;类型转换主要指将其他数据类型转成String、Number、Boolean
7.1 转换成String
方式一:toSting()
例如:a = a.toSting();
- 调用被转换的数据类型的toSting()方法
- 该方法不会影响到原变量,它会将被转换的结果返回
- null和undefined两个值是没有toString,如调用他们的方法会报错
方式二:String()
例如; a = String(a);
1.调用String()函数,并将被转换的数据作为参数传递给函数
2.用String()函数做强制类型转换:
-对于Number和Boolean实际上调用的就是toString()方法;
-对null 和 undefined ,就不会调用toString()方法;它会将null直接转换城"null";它会将undefined直接转换城"undefined"
方式三:隐式类型转换–加法运算
解析:任何的值和字符串做加法运算,都会先转换成字符串,只需要为任意的数据类型+一个"",即可将其转换成string,由浏览器自动完成.
7.2 转换成Number
方式一:Number()
例如:a = Number(a);
字符串 转 数字
1.如果是纯数字的字符串,则直接转成数字
2.如果字符串中有非数字的内容,则转换成NaN
3.如果字符串是一个空串或者是一个全是空格的字符,则转成0
布尔值 转 数字
1.true 转 1
2.false 转 0
Null 转 数字 0
undefined 转 数字 NaN
方式二:parseInt()和 parseFloat()
解析:这种方式用来专门对付字符串
1.parseInt()把字符串中有效的整数内容取出来,然后转成number
例如:var a = “123px”;a = parseInt(a);//123
2.parseFloat()把一个字符串转成浮点数
例如; var a = “123.569px”; a = parseFloat(a);//123.569
3.非string使用parseFloat()或parseInt(),它会先转成string,然后再操作
方式三:隐式类型转换
解析:任何值做/ * - 运算,都会自动转换成Number;通过为一个值 -0 *1 /1 可将其转换为Number类型
方式四:一元运算+
解析:对非Number类型的值,会先转为Number,然后再运算;可对一个其他数据类型值使用+,可将其转换成number。
例如:var b = 1 + ‘2’ + 3; //123
var b = 1 + +‘2’ + 3; //6
7.3 其他进制数字表示
- 十六进制表示
解析:输入需要以0x开头;以10进制输出
例如:a = 0xa;//10
- 八进制表示
解析:0开头表示八进制;
例如: a = 070;//70
特殊:"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析
解决:在parseInt()中传递一个第二个参数,来指定数字的进制
例如:a = parseInt(a,10);
- 二进制表示
解析: 0b开头便是二进制
例如: a = 0b10;//10
7.4 转换成Boolean
方式一:Boolean()
1.数字转成Boolean,除了0和NaN其他都是true
2.字符串转成Boolean,除了空串其他都是true
3.null转成Boolean,为false
4.undefined 转成Boolean,为false
8 算术运算符
解析:对非Number的值进行运算时,会将这些值转换成Number再进行运算(与String加法运算除外)
例如: result = 123 + ‘1’;//1231 String
result = true + 1; //2 number
result = 2 + null;//2 number
result = 2 + undefined;//NaN number
- 任何值和NaN进行任何运算都得NaN
1.加号可以对两个值进行加法运算,并将结果返回
2.如对两个字符串进行加法运算,会将两个字符串拼接为一个字符串,并返回.
例如:result = ‘你好’+ ‘帅哥’//你好帅哥
3.任何的值和字符串做加法运算,都会先转换成 字符串,然后再和字符串进行拼接操作
例如:
result = 123 + ‘1’;//1231 String
result = true + ‘nihao’;//truenihao String
/ * -
解析:减号可以对两个字符串进行减法运算,并将结果返回;乘号可以对两个字符串进行乘法运算,并将结果返回;除号可以对两个字符串进行除法运算,并将结果返回
1.任何值做/ * - 运算,都会自动转换成Number
%
解析:%去模运算(取余数);先转成数字类型再运算
例如:
b = 2 % ‘3’;//2
b = 2 % true;//0
b = 2 % null;//NaN
b = 2 % undefined;//NaN
b = 2 % NaN;//NaN
9 一元运算符
- +正号
解析:正号不会对数字产生任何影响
- -负号
解析: 负号可以对数字进行负号的取反
特殊:对非Number类型的值,会先转为Number,然后再运算
例如:var b = 1 + +‘2’ + 3; //6
10 自增和自减
10.1 自增
解析:通过自增可使变量在自身的基础上加1
1.对于一个变量自增以后,原变量的值会立即自增1
* 无论是a++,还是++a,都会立即使原变量的值自增1
a++ 和 ++a异同
-
a++的值等于原变量的值(自增前的值)
-
++a的值等于原变量的新值(自增后的值)
10.2 自减
解析:通过自减可使变量在自身的基础上减1
1.自减分成两种:后–(a–)和 前–(--a),都会立即使原变量的值自减1
a-- 和 --a异同
-
a–的值等于原变量的值(自减前的值)
-
–a的值等于原变量的新值(自减后的值)
11 逻辑运算符
11.1 !非
解析:非运算就是对一个布尔值进行取反操作, true变false ,false变true
1.如果对一个值进行两次取反,它不会变化
非布尔值的非运算
解析:对非布尔值进行非运算,则先会将其转换成布尔值,再进行取反
11.2 && 与
解析:&&可以对符号两侧的值进行与运算,并返回结果
1.两个值都为true,结果才返回为true
2.只要有一个为false,就返回false
3.如果第一个值为false,则不会看第二个值
非布尔值的与运算
解析:对非布尔值进行与运算,会先将其转换成布尔值,然后再运算,并且返回原值
1.如果第一个值为true,则必然返回第二个值
2.如果二个值为false,则必然返回第一个值
11.3 || 或
解析:可以对符号两侧是值进行或运算并返回结果
1.两个值只要有一个值为true,就返回true
2.如果两个值都为false,则返回false
3.如果第一个值为true,则不会看第二个值
非布尔值的或运算
解析:对非布尔值进行或运算,会先将其转换成布尔值,然后再运算,并且返回原值
1.如果第一个值为true,则直接返回第一个值
- 如果第一个值是false,则直接返回第二个值
12 赋值运算符
解析:= 可以将符号右侧的值赋值给符号左侧的变量
-
a += 5 等价于a = a+5
-
a -= 5 等价于a = a-5
-
a = 5 等价于a = a5
-
a /= 5 等价于a = a/5
13 关系运算符
解析:通过关系运算符可以比较值之间的大小关系;如关系成立它返回true,如关系不成立则返回false
1.非数值情况
解析:对于非数值进行比较时,会将其转换成数字然后进行比较
例如: console.log(1 > true);//false
console.log(1 >= true);// true
console.log(1 > “0”);//true
console.log(10 > null);//true
2.符号两侧是字符串
解析:如果符号两侧的值都是字符串时,不会将其转成数字比较
(1)比较两个字符串时,比较的是字符串的编码
例如:console.log(“a” < “b”); //true
(2)比较字符编码是一位一位进行比较;如两位一样,则比较下一位,可以用来对英文进行排序
例如:
console.log(“abc” < “b”);//true
console.log(“bbc” < “b”);//false
(3)如比较的这两个字符串的数字,可能会得到不可预期的结果
特殊:在比较两个字符串类型的数字时,必须要转型
例如:
console.log(“11” < +“5”);//false
14 编码
编码链接:unicode.org
1.在script里面
解析: 在字符串中使用转义字符例如Unicode编码
语法:【\u四位编码】
例如: console.log("\u2620");//骷颅头
2.在body里面
语法:【 &#编码; 】;这里使用的编码需要的是10进制
例如: < h1 style=“font-size: 200px;”>☠< /h1>
15 相等运算符
解析:相等运算符用来比较两个值是否相等,如果相等会返回true,否则返回false
15.1 ==
解析: == 用来做相等运算
-
使用==来比较时,如值的类型不同则会自动进行类型转换,将其转换成相同的类型再比较
-
一般转换成数字进行比较
例如:console.log(“1” == 1); //true
console.log(true == “1”); //true
- 也有不转成数字的
例如: console.log(null == 0); //false
- undefined衍生自null,两个值做相等判断时,返回true
例如: console.log(undefined == null); //true
- NaN不和任何值相等,包括它本身
console.log(NaN == NaN); //false
- 通过isNaN()函数可以判断一个值是不是NaN
var b = NaN;
console.log(isNaN(b)); //true
15.2 !=
解析: 不相等用来判断两个值是否不相等,如果不相等返回true,否则返回false;
- 使用!=来做不相等运算,会对变量进行自动的类型转换,如果转换后等于它也会返回false
例如:console.log(“1” != 1); //false
15.3 ===
解析:用来判断两个值是否全等,它和相等类似。不同的是它不做自动类型转换。如果两个值类型不同,直接fasle
例如: console.log(“123” === 123); //false
15.4 !==
解析:用来判断两个值是否不全等,它和不等类似。不同的是它不做自动类型转换。如果两个值类型不同,直接true
例如:console.log(‘1’ !== 1); //true
16 条件运算符
解析:条件运算符也叫三元运算符
语法:条件表达式?语句1:语句2;
-
条件运算符在执行时,首先对条件表达式进行求值
-
如果该值为true,则执行语句1,并返回执行结果
-
如果该值为false,则执行语句2,并返回执行结果
例如:获取a, b , c中最大的值
写法1:先获取a,b最大值;后获取a, b , c中最大的值
var max = a > b ? a : b;
max = max > c ? max : c;
写法二:阅读性差,不推荐使用
var max = a > b?(a > c ? a : c):(b>c ? b: c);
- 如条件表达式的求值结果不是一个布尔值,会将其转换为布尔值,然后再进行运算
例如: “hello” ? alert(“语句1”) : alert(“语句2”);
17 运算符的优先级
解析:在JS中有一个运算符优先级的表,在表中越靠上优先级越高,优先级越高越优先计算,如果优先级一样,则从左往右计算。
- 使用逗号可以分割多个语句,一般可以在声明多个变量时使用
例如:var a , b , c;
- 可以使用()来改变优先级
18 代码块
解析:JS中可以使用{}来为语句进行分组, 同一个{}中的语句为是一组语句,它们要么都执行,要么都不执行。
-
一个{}中的语句称为一个代码块
-
代码块的后边不再写【;】
-
JS中的代码块,只具有分组的的作用,没有其他的用途
-
代码块的内容,在外部是完全可见的
19 流程控制语句
三类:
-
条件判断语句
-
条件分支语句
-
循环语句
解析:通过流程控制语句可以控制程序执行流程,使程序可以根据一定的条件来选择执行
19.1 条件判断语句
解析:使用条件判断语句可以在执行某个语句之前进行判断,如果条件成立才会执行语句,条件不成立则语句不执行。
语法一:
if (条件表达式) { 语句… }
- if语句在执行时,会先对条件表达式进行求值判断,如果条件表达式的值为true,则执行if后的语句;如果条件表达式的值为false,则不会执行if后的语句。
- if语句只能控制紧随其后的那个语句
- 如果希望 if 语句可以控制多条语句,可以将这些语句统一放到代码块中
语法二:
if(条件表达式){
语句…
}else{
语句… }
- 当该语句执行时,会先对if后的条件表达式进行求值判断,如果该值为true,则执行if后的语句; 如果该值为false,则执行else后的语句
语法三:
if(条件表达式) { 语句…
}else if(条件表达式){ 语句…
}else if(条件表达式){ 语句…
}else{ 语句… }
- 当该语句执行时,会从上到下依次对条件表达式进行求值判断,如果值为true,则执行当前语句;如果值为false,则继续向下判断;如果所有的条件都不满足,则执行最后一个else后的语句
- 该语句中,只会有一个代码块被执行,一旦代码块执行了,则直接结束语句
19.2 条件分支语句
解析:执行时会依次将case后的表达式的值和switch后的条件表达式的值进行全等比较,如果比较结果为true,则从当前case处开始执行代码; 当前case后的所有的代码都会执行,我们可以在case的后边跟着一个break关键字, 这样可以确保只会执行当前case后的语句,而不会执行其他的case。如果比较结果为false,则继续向下比较;如果所有的比较结果都为false,则只执行default后的语句
语法:
switch(条件表达式){
case 表达式:
语句…
break;
case 表达式:
语句…
break;
default:
语句…
break; }
19.3 循环–while
解析:while语句在执行时,先对条件表达式进行求值判断, 如果值为true,则执行循环体,循环体执行完毕以后,继续对表达式进行判断;如果为true,则继续执行循环体,以此类推;如果值为false,则终止循环。
语法:
while(条件表达式){
语句… }
19.4 循环–do…while
解析: do…while语句在执行时,会先执行循环体;循环体执行完毕以后,在对while后的条件表达式进行判断;如果结果为true,则继续执行循环体,执行完毕继续判断以此类推; 如果结果为false,则终止循环
语法:
do{
语句… }while(条件表达式)
while循环和o…while循环区别
- while是先判断后执行
- 而do…while会先执行后判断,do…while可以保证循环体至少执行一次
死循环
解析:将条件表达式写死为true的循环,叫做死循环;该循环不会停止,除非浏览器关闭,死循环在开发中慎用
例如:while(true){ alert(n++); }
循环创建三步骤
-
创建初始化一个变量
var i = 1;
-
设置一个条件表达式
while(i <= 10){
-
定义一个更新表达式
document.write(i++ +" <br / >") }
19.5 循环–for
解析:for循环中,提供了专门的位置用来放三个表达式:
-
初始化表达式
-
条件表达式
-
更新表达式
语法: for(①初始化表达式;②条件表达式;④更新表达式){ ③语句… }
执行流程:
-
①执行初始化表达式,初始化变量(初始化表达式只会执行一次)
-
②执行条件表达式,判断是否执行循环。
-
如果为true,则执行循环③
-
如果为false,终止循环
-
④执行更新表达式,更新表达式执行完毕继续重复②
特殊:for循环中的三个部分都可以省略,也可以写在外部。如果在for循环中不写任何的表达式,只写两个;
此时循环是一个死循环会一直执行下去,慎用。
例如:
for(;; ){ alert(“hello”); }
嵌套for循环
语法:
for(){
for(){ }
}
- 外层for循环执行几次,图形的高度就是多少
- 内部循环,用来控制图形的宽度
19.6 prompt提示框
解析: prompt()可以弹出一个提示框,该提示框中会带有一个文本框,
-
用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数,该字符串将会作为提示框的提示文字
-
用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该内容
例如: var score = prompt(“请输入小明的期末成绩(0-100):”);
20 break和continue
20.1 break
解析:break关键字可以用来退出switch或循环语句
- 不能在if语句中使用break和continue
- break关键字,会立即终止离他最近的那个循环语句
特殊:
for(var i=0 ; i<5 ; i++){
console.log("@外层循环"+i)
for(var j=0 ; j<5; j++){
break;
console.log(“内层循环:”+j);
}
} //结果是内层循环跳出了,外层循环还在执行
方案:为循环语句创建一个label,来标识当前的循环
语法: 【label:循环语句】;使用break语句时,在break后跟着一个label,break将会结束指定的循环,而不是最近的
例如:
outer:
for(var i=0 ; i<5 ; i++){
console.log("@外层循环"+i)
for(var j=0 ; j<5; j++){
break outer;
console.log(“内层循环:”+j);
} }
20.2 continue
解析: continue关键字用来跳过当次循环
- 同continue也是默认只会对离他最近的循环起作用
20.3 return
解析:return可以结束整个函数
21 对象
解析:除了基本数据类型,其他都属于对象
21.1 对象分类
内建对象:
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
例如:Math String Number Boolean Function Object…
宿主对象:
- 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
例如: BOM(浏览器对象模型) DOM(文档对象模型)
自定义对象:
- 有开发人员创建的对象
21.2 对象的创建
- 使用new关键字调用的函数,是构造函数;构造函数是专门用来创建对象的函数;使用typeof检查一个对象时,会返回object
例如:var obj = new Object();
21.3 对象属性的添加
解析:在对象中保存的值称为属性
21.3.1 属性名:
- 对象的属性名不强制要求遵守标识符的规范,什么都可以,但是我们还是尽量按照标识符的规范去做
语法:对象.属性名 = 属性值;
例如: obj.name = “孙悟空”;
特殊属性名:
- 不能采用.的方式来操作的特殊属性名,用另一种方式
- 语法:对象[“属性名”] = 属性值
- 读取也需要这种方式;[]这种形式去操作属性,更加的灵活
例如:
obj[“123”] = 789;
console.log(obj[“123”]); //789
21.3.2 属性值:
- JS对象的属性值,可以是任意的数据类型;对象也行,函数也行
对象属性的读取:
解析:读取对象的属性,有则返回;无则返回undefined,不会报错
语法:对象.属性名
例如: console.log(obj.name);
对象属性的修改
语法:对象.属性名 = 新值
例如: obj.name = “tom”;
对象属性的删除
语法:delete 对象.属性名
例如: delete obj.name;
- 对象的属性值是函数的时候
解析:
- 如一个函数作为一个对象的属性保存,那这个函数是这个对象的方法
- 调用这个函数就说调用对象的方法(method)
- 它们只是名称上的区别,没有其他的区别
例如:
//对象的方法
obj.sayName = function () {
console.log(obj.name);
};
//调方法 什么点什么就是调用什么的方法,如下:
obj.sayName();
//函数
function fun() {
console.log(obj.name);
};
//调函数
fun();
21.4 枚举对象中的属性:
解析:
- for…in语句 对象中有几个属性,循环体就会执行几次
- 每次执行时,会将对象中的一个属性的名字赋值给变量
语法: for(var 变量 in 对象){ }
例如:
for (var n in obj) {
console.log(“属性名:” + n);
console.log(“属性值:” + obj[n]); //obj[n]表示该对应属性的值
}
21.5 in 运算符
解析:通过该运算符可以检查一个对象中是否含有指定的属性;如果有则返回true,没有则返回false
语法:“属性名” in 对象
例如: console.log(“test2” in obj);
21.6 对象的字面量
解析:使用对象字面量,可以在创建对象时,直接指定对象中的属性
语法:{属性名:属性值,属性名:属性值…}
- 对象字面量的属性名可以加引号也可以不加,建议不加
- 如果要使用一些特殊的名字,则必须加引号
- 属性名和属性值是一组一组的名值对结构
- 名和值之间使用:连接,多个名值对之间使用,隔开
例如;
var obj2 = {
name: “猪八戒”,
age: 13,
gender: “男”,
test: { name: “沙僧” }
};
22 工厂方法创建对象
解析: 使用工厂方法可以大批量的创建对象
22.1 方式一:解决了每创建一个对象都要创建一个函数问题
缺点:工厂方法创建的对象,使用的构造函数都是Object, 所以创建的对象都是Object这个类型,以至于无法区分出多种不同类型的对象
例如:
function createPerson(name, age, gender) {
//创建一个新的对象
var obj = new Object();
//向对象中添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function () {
alert(this.name);
};
//将新的对象返回
return obj;
}
22.2 方式二: 解决了多种不同类型的对象无法区分问题
解析:
-
创建一个构造函数,专门用来创建某某对象;
–构造函数就是一个普通的函数,创建方式和普通函数没有区别;
–不同的是构造函数习惯上首字母大写
-
构造函数和普通函数的区别就是调用方式的不同:
--普通函数是直接调用,
--构造函数需要使用new关键字来调用
- 构造函数的执行流程:
(1)立刻创建一个新的对象
(2)将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象
(3)逐行执行函数中的代码
(4)将新建的对象作为返回值返回
-
同一个构造函数创建的对象,称为一类对象;
–也将一个构造函数称为一个类;
–将通过一个构造函数创建的对象,称为是该类的实例
-
this的情况:
(1)当以函数的形式调用时,this是window
(2)当以方法的形式调用时,谁调用方法this就是谁
(3)当以构造函数的形式调用时,this就是新创建的那个对象
例如:
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function () {
alert(this.name);
}; }
var per = new Person(“孙悟空”, 18, “男”);
console.log(per)
问题:Person构造函数中,每一个对象都添加了一个sayName方法。目前sayName方法构造函数内部创建,会造成构造函数每执行一次就会创建一个新的sayName方法,这样会影响性能。
解决一:
解析:将sayName方法在全局作用域中定义
例如:
function fun(){
alert(“Hello大家好,我是:”+this.name); };
缺点:将函数定义在全局作用域,污染了全局作用域的命名空间,而且定义在全局作用域中也很不安全
解决二:
解析:在原型中添加sayName方法
例如:
Person.prototype.sayName = function () {
alert(“Hello大家好,我是:” + this.name); };
优点:不用多次创建sayName方法,减低性能消耗
22.3 instanceof
解析: 使用instanceof可以检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
例如:
console.log(per instanceof Person); //如果是,则返回true,否则返回false
- 所有的对象都是Object的后代,任何对象和Object进行instanceof检查时都会返回true
例如: console.log(dog instanceof Object); //true
23 函数
解析:
- 函数function也是一个对象;
- 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码);
- 函数中可以保存一些代码在需要的时候调用
- 使用typeof检查一个函数对象时,会返回function
函数创建
23.1 方法一:构造函数(实际开发中很少使用)
解析:将要封装的代码以字符串的形式传递给构造函数
例如:var fun = new Function(“console.log(‘Hello 这是我的第一个函数’);”);
- 封装到函数中的代码不会立即执行;会在函数调用的时候执行
- 当调用函数时,函数中封装的代码会按照顺序执行
- 语法:函数对象() 例如: fun()
23.2 方法二:函数声明(常用)
语法:
function 函数名([形参1,形参2…形参N]){ 语句… }
例如:
function fun2() {
console.log(“这是我的第二个函数~~~”);
alert(“哈哈哈哈哈”);
document.write("");(>_<)
}
fun2();
23.3 方法三:函数表达式
语法:
var 函数名 = function([形参1,形参2…形参N]){ 语句… };
例如:
var fun3 = function () {
console.log(“我是匿名函数中封装的代码”);
};
fun3();
23.4 函数的参数
解析:
- 函数的()中可以指定一个或多个形参(形式参数);多个形参之间使用逗号隔开,声明形参就相当于在函数内部声明了对应的变量,但是并不赋值
例如:function sum(a, b) { console.log(a + b); } === function* sum() { var a, b; console.log(a + b); }
- 函数的实参可以是任意的数据类型,对象,函数等
例如: sum(true , false);
- 在调用函数时,可以在()中指定实参(实际参数),实参将会赋值给函数中对应的形参
例如:sum(1,2);
-
调用函数时解析器不会检查实参的类型,所以要注意是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查
-
调用函数时,解析器也不会检查实参的数量
----多余实参不会被赋值
----如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined
23.5 函数的返回值
解析:可以使用 return 来设置函数的返回值
语法: 【return 值】
- return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
- 如果return语句后不跟任何值就相当于返回一个undefined;
- 如果函数中不写return,则也会返回undefined
- 在函数中return后的语句都不会执行
- 返回值可以是任意的数据类型,对象、函数都行
例如:
function sum(a, b, c) {
var d = a + b + c;
return d; }
调用函数
例如:
- 变量result的值就是函数的执行结果
- 函数返回什么result的值就是什么
var result = sum(4, 7, 8);
23.6 函数的方法
23.6.1 call()和apply()
解析:
- 两个都是函数对象的方法,需要通过函数对象来调用
- 当对函数调用call()和apply()都会调用函数执行
- 在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
例如:function fun() {
alert(this.name);}
var obj = {name: “aa”,}
fun.call(obj);//aa
fun.apply(obj);//aa
call()和apply()区别
- call()方法可以将实参在对象之后依次传递
例如:function fun(a, b) {
console.log("a = " + a);
console.log("b = " + b);}
var obj = {
name: “obj”,};
fun.call(obj,2,3);//a = 2, b = 3
- apply()方法需要将实参封装到一个对象后的数组中统一传递
例如:function fun(a, b) {
console.log("a = " + a);
console.log("b = " + b);}
var obj = {
name: “obj”,};
fun.apply(obj, [2, 3]);//a = 2, b = 3
call()和apply()this情况
解析:
-
以函数形式调用时,this永远都是window
2.以方法的形式调用时,this是调用方法的对象
3.以构造函数的形式调用时,this是新创建的那个对象
4.使用call和apply调用时,this是call()和apply()里指定的对象
24 立即执行函数
解析:函数定义完,立即被调用,这种函数叫做立即执行函数
- 立即执行函数往往只会执行一次
例如:
(function (a, b) {
console.log("a = " + a);
console.log("b = " + b);
})(123, 456);
类似于-----sum(123,456), sum跟立即执行函数中前一个()都是对象
25 作用域(Scope)
25.1 全局作用域
解析:
- 直接编写在script标签中的JS代码,都在全局作用域
- 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
- 在全局作用域中,创建的变量都会作为window对象的属性保存
- 在全局作用域中,创建的函数都会作为window对象的方法保存
- 全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到
25.2 函数作用域
解析:
-
用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
-
每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
-
在函数作用域中可以访问到全局作用域的变量
在全局作用域中无法访问到函数作用域的变量
-
当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用;
如果没有则向上一级作用域中寻找,直到找到全局作用域;
如果全局作用域中依然没有找到,则会报错ReferenceError(引用错误)
- 在函数中要访问全局变量可以使用window对象
26 声明提前
26.1 变量的声明提前
解析:
- 使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值)
- 如果声明变量时不使用var关键字,则变量不会被声明提前
26.2 函数的声明提前
解析:
- 函数声明形式创建的函数 function 函数(){},会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
例如://函数声明,会被提前创建
function fun() {
console.log(“我是一个fun函数”); }
- 函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
例如: //函数表达式,不会被提前创建
var fun2 = function () {
console.log(“我是fun2函数”);
};
- 函数中,不使用var声明的变量都会成为全局变量
function fun5() {
c = 10 // 全局变量
console.log("c = "+c); //undefined
}
27 debug(断点)
解析:
-
断点可以对每个值的流程进行查看,可以使用火狐、谷歌等浏览器
-
控制台找到可以断点模块,添加监视,进行流程查看
28 this参数
解析:解析器在调用函数时每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的 上下文对象
根据函数的调用方式的不同,this会指向不同的对象
- 以函数的形式调用时,this永远都是window
例如:
function fun() {
console.log(this.name);
}
fun();
- 以方法的形式调用时,this就是调用方法的那个对象
例如:
function fun() {
console.log(this.name);
}
//创建一个对象
var obj = {
name: “孙悟空”,
sayName: fun
};
obj.sayName();
29 原型(prototype)
解析:
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
- 这个属性对应着一个对象,这个对象就是我们所谓的原型对象
- 如果函数作为普通函数调用prototype没有任何作用
- 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过 __ proto __ 来访问该属性
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用;如果没有则会去原型对象中寻找,如果找到则直接使用
- 我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中。这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法
例如:
function MyClass() { }
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
//向MyClass的原型中添加一个方法
MyClass.prototype.sayHello = function () {
alert(“hello”); };
var mc = new MyClass();
console.log(MyClass.prototype);
console.log(mc.__ proto__ == MyClass.prototype); //true
对象属性检查
- 使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
例如:console.log(“name” in mc);
- 可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性,该方法只有当对象自身中含有属性时,才会返回true
例如:console.log(mc.hasOwnProperty(“age”));
console.log(mc.hasOwnProperty(“hasOwnProperty”)); //false, hasOwnProperty方法不在hasOwnProperty上
console.log(mc.__ proto__ . __ proto__.hasOwnProperty(“hasOwnProperty”)); //true
原型对象也是对象
解析:原型对象也是对象,所以它也有原型
- 当我们使用一个对象的属性或方法时,会现在自身中寻找,自身中如果有,则直接使用;如果没有则去原型对象中寻找,如果原型对象中有,则使用
- 如果原型中没有则去原型的原型中寻找,直到找到Object对象的原型
- Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
console.log(mc.__ proto__ .__ proto__ .object) //undefined
console.log(mc.__ proto__ .__ proto__ .__ proto__) //null
30 修改原型中的toString
例如:
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender }
var per = new Person(“孙悟空”, 18, “男”);
console.log(per);//输出[object Object]
目的:
为了输出是如下形式:Person[name=孙悟空,age=18,gender=男];给对象添加个toString()方法
结果:
per.toString = function(){
return “Person[name=”+this.name+",age="+this.age+",gender="+this.gender+"]"; };
问题:如果是其他对象又要手动改变对象,不好
疑问:toString()方法在哪里的?
查找:console.log(per.__ proto__ . __ proto__.hasOwnProperty(“toString”));//在对象的原型的原型中
方案:修改Person原型的toString
Person.protoType.toString = function () {
return “Person[name=” + this.name + “,age=” + this.age + “,gender=” + this.gender + “]”;}
31 垃圾回收GC(garbage collection)
解析:
- 程序运行过程中会产生垃圾,垃圾积攒过多会导致程序运行的速度过慢
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢
- JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁
- 需要做的只是要将不再使用的对象设置null即可
例如:
var obj = new Object();
obj = null;