JavaScript是什么

Netscape在最初将其脚本语言命名为LiveScript,后来Netscape在与Sun合作之后将其改名为JavaScript。JavaScript最初受Java启发而开始设计的,目的之一就是“看上去像Java”,因此语法上有类似之处,一些名称和命名规范也借自Java。JavaScript与Java名称上的近似,是当时Netscape为了营销考虑与Sun微系统达成协议的结果。Java和JavaScrip只是名字很像。

Java 服务器端的编程语言

JavaScript 运行在客户端(浏览器)的编程语言

JavaScript是一种运行在客户端脚本语言 JavaScript的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。

JavaScript和HTML、CSS的区别

  1. HTML:提供网页的结构,提供网页中的内容

  2. CSS: 用来美化网页

  3. JavaScript: 可以用来控制网页内容,给网页增加动态的效果

第一个JavaScript程序

在HTML页面中添加

    <title>Document</title>
    <script>
        window.onload=function(){
            for(var i = 0;i < 10;i ++){
                document.write("<p>我要中奖500W!<p>");
            }
        }
    </script>

JavaScript的书写位置

  • 写在行内

<input type="button" value="按钮" onclick="alert('Hello World')" />
  • 写在script标签中    script可以写在HTML页面的任何位置。

<head>
  <script>
    alert('Hello World!');
  </script>
</head>
  • 写在外部js文件中,在页面引入

<script src="main.js"></script>

tips:引用外部js文件的script标签中不可以写JavaScript代码

严格检查模式 在script标签内的第一行写 'use strict';

var ES5 --let  ES6

变量

什么是变量

变量是存储数据的最小单元

就是可以变化的量。

程序在计算的时候,是CPU从内存中获取数据,进行计算,计算完成之后再将数据写入内容。

数据是存储在内存中的。内存可以认为是一个数组(表格)。表格的每一个单元格都是有序号的。任何数据存在内存中都有一个开始的位置和结束的位置。

变量就是在内存中开辟空间,存储要计算的数据,为了方便操作这个数据,给这个空间起一个别名。

别名+空间+数据 = 变量。

别名:变量名。

数据:变量的值。

空间:根据变量的数据类型开辟的。

变量的使用

tips: JS是严格区分大小写。

tips:js是弱数据类型,所以在申明变量的时候不需要申明数据类型。在做赋值运算的时候,会自动根据赋值的类型确定变量的数据类型。

  • var声明变量

var age;

任何类型的变量(对象)都是使用var/let。在申明变量的时候不需要注明数据类型。

  • 变量的赋值

var age;
age = 18;

在赋值的时候才确定数据类型,也就是说,一个变量可以赋任何类型的数据。

  • 同时声明多个变量

var age, name, sex;
age = 10;
name = 'mingren';
  • 同时声明多个变量并赋值

var age = 10, name = 'kakaxi';
  • 如果一个变量没有赋值,则默认值是:undefined

//将一个没有赋值的变量输出到控制台
        var tel;
        console.log(tel);// undefined
  • 如果一个变量没有申明,就直接使用,会出错。

console.log(a);//出错 : a is not defined

控制台的使用

现在的主流浏览器中都有JS的控制台。

都是打开浏览器之后,按:F12。

            // 如果申请了一个变量是没有赋值的,则这个变量的值默认是undefined
            var job;
            // alert(job);
            // 在控制台输出内容
            // 直接输出字符串
            console.log("我是一个直接输出的字符串");
            // 输出一个变量的值,直接写变量的名字,不需要引号
            console.log(c);
            console.log(job);
            console.log(type);

变量的命名规则和规范

规则:

①不能是JS的关键字和保留字符。

错误示例:var var ; var int ;

②不能以数字开头。(可以以数字结尾,或者中间有数字)

错误示例: var 0abc; var 10name;

正确示例: var name0; var stu10score;

③不能有特殊符号(特殊符号一般都是运算符和空字符)可以有“_” "$/¥" 也可以是中文。

错误示例: var name+score; var name score;

1、js中的关键字:

breakcasecatchcontinuedefault
delete do else finally for
function if in instanceof new
return switch this throw try
typeof var void while with

2、js中的保留字:

abstractbooleanbytecharclass
const debugger double enum export
extends final float goto implements
import int interface long native
package private protected public short
static super synchronized throws transient
volatile        

规范:

①言简意赅。

错误示例: var a , c , def;

正确示例: var name; age; score;gender;tel;

②符合驼峰规则。

如果变量由一个单词组成,则所有的字母小写。

如果由多个单词组成,则除过第一个单词之外,其他的单词的首字母都要大写。其余的字母小写。

案例:var stuScore; var teacherTel;

如果是简称 就全部小写。

数据类型

tips:弱数据类型不代表没有数据类型。

简单数据类型

Number、String、Boolean、Undefined、Null

Number类型

  • 数值字面量:数值的固定值的表示法

    110 1024 60.5

  • 进制

十进制
	var num = 9;
	进行算数计算时,八进制和十六进制表示的数值最终都将被转换成十进制数值。
十六进制
	var num = 0xA;
	数字序列范围:0~9以及A~F,0x开头
八进制
    var num1 = 07;   // 对应十进制的7
    var num2 = 019;  // 对应十进制的19
    var num3 = 08;   // 对应十进制的8
    数字序列范围:0~7
    如果字面值中的数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析
  • 浮点数

    • 浮点数的精度问题

浮点数
	var n = 5e-324;   // 科学计数法  5乘以10的-324次方  
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数
   var result = 0.1 + 0.2;    // 结果不是 0.3,而是:0.30000000000000004
   console.log(0.07 * 100);
   不要判断两个浮点数是否相等
  • 数值范围

最小值:Number.MIN_VALUE,这个值为: 5e-324
最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
无穷大:Infinity
无穷小:-Infinity
  • 数值判断★★★★★★★★★

    • NaN:not a number

      • NaN 与任何值都不相等,包括他本身

    • isNaN: is not a number

关于NaN和isNaN的使用:

NaN是一个类型,表示不是数字。

isNaN是一个函数,判断一个数字是否是NaN。

        //这是一个错误的运算
        var x = 10 - "Ⅹ";
        console.log(x);// NaN
        var r = isNaN(x);
        console.log(r);// true

String类型

1.正常字符串使用单引号或者双引号包裹,如:'abc' "abc"

tips:在javaScript中的单引号和双引号是没有区别的。 再理解就是没有字符和字符串的区分。

一个字符串可以是空的,也可以是很长。

2.注意转义字符 \    " \' "    "\n"   "\t"    "\u4e2d" Unicode字符  "\x41" Ascii字符

3.多行字符串编写 写在一对反引号里面  ` `

var msg = `hello

world

你好`

4.模板字符串:

let name = "zhangsan";let age = 3;

let msg = `你好,${name }`

console.log(msg);//你好,zhangsan

5.字符串长度  console.log(str.length);

6.字符串不可变性

var str = "student";  console.log(str[0]) //s; str[0] = 1; console.log(str);//仍然输出student

7.大小写转化 //是方法,不是属性

str.toUpperCase();  str.toLowerCase();

8.获取指定字符第一次出现的索引

str.indexOf('t')//1

9.截取字符串 前包后不包

str.substring(1,3)  //tu

str.substring(1)//从第一个字符串截取到最后一个字符串

String 有没有长度限制?  理论上没有,实际上有。

数组

基本概念

所谓数组,就是一组数。

数组的特点就是在内存开辟一组连续的空间,存储一组数据。

变量,就是给内存的一个空间起个别名。

数组就是把多个变量放在一起,一起起一个别名。

数组中的每一个元素都是有索引的,索引从0开始,长度如果是3,那么索引就是0,1,2。

数组的定义

数组是一个有序的列表,可以在数组中存放任意的数据,并且数组的长度可以动态的调整。

数组的基本操作

arr.length

arr.indexOf('a') 通过元素获得下标索引

slice(2,5) 截取Array的一部分,返回一个新数组,类似于String中的substring()

arr.push('a','b','c'.....):压入到尾部
arr.pop():弹出尾部的一个元素
arr.unshift('a','b'):压入头部
arr.shift():弹出头部的第一个元素
arr.sort():排序 b c a--->a b c
arr.reverse():元素反转  a b c--->c b a
arr.cocat([1,2,3]):拼接 c b a --->c b a 1 2 3 没有修改原数组,只是会返回一个新的数组
arr.join('-'):打印拼接数组,使用特定的字符串连接 c b a  --->c-b-a
多维数组:arr  = [[1,2],[3,4],["5","6"]]; arr[1,1]--->4 //  0,0   0,1   1,0  1,1   2,0   2,1

[1]申明一个数组。

 // 申明数组
      var names;
    // 初始化  (所谓初始化,就是在内存中开辟空间,并且放入数据)
    names = new Array(3);
      //申明一个空数组
        var arr = [];// java >> int [] arr = {};
        // 再申明一个数组
        var arr1 = new Array(3);// 创建了一个数组,里面有3个元素都是undefined
        // 创建一个有初始值的数组,数字的值的类型可以不一致, 申明的同时初始化
    var ages = [18,18,16];
tips:
在js中申明数组也是使用var。 数组的长度可以指定,也可以不指定。 指定长度 new Array(len); 这个len只是表示这个数组的最小长度。我们在赋值的时候即使超过了这个长度也不会有任何错误。 数组如果指定了长度。元素的默认值统一是undefined。 数组元素的类型是可以不规则的。

当我们操作的元素的索引超过了最大索引时,数组会自动增长。

		var skills = new Array(2);
		skills[0] = "千年杀";
		skills[1] = "千鸟";
		skills[30] = "写轮眼";
		console.log(skills.length);// 31
		console.log(skills); // 其中有27个undefined
     //赋值
        arr1[0] = '一';
        arr1[1] = '二';
        arr1[2] = '三';
        //在js中没有索引越界
        arr1[3] = '四';// java>>ArrayIdexOutOfBoundsException

JS中的数组的元素的类型是可以不一致的。 数组的元素可以是任何类型。

			var infos = new Array(6);
			infos[0] = "卡卡西";//字符串
			infos[1] = 28; // 数字
			infos[2] = false; // 布尔型
			infos[3] = null;// NaN // null
			infos[4] = {skill:"千年杀"};// 一个对象 
			infos[5] = [1,2,3,4,5]; // 一个数组
			console.log(infos);

[2]数组的元素的操作

我们可以通过 数组名[index] 访问数组中的任何一个元素。

		names = new Array(3);
		// 给数组的元素赋值
		names[0] = "张三";
		names[1] = "大锤";
		names[2] = "如花";
		// 取出数组元素的值
		var n1 = names[2];
		console.log(n1);
		console.log("-----------");
		console.log(names);

数组是一个对象。我们访问一个对象的属性的时候,使用的语法一般都是:

对象名.属性名  或者  对象名['属性名']
        var cs = new Array();
        cs[0] = '哈哈'
        cs[1] = '嘻嘻'
        cs['江苏'] = '南京';
        cs['安徽'] = '合肥';
        cs['河南'] = '郑州';
        console.log(cs);

浏览器格式化之后的数组对象,所有的数据都是 key: value的形式。

这里的key都是这个数组对象的属性。那么理论上来说,我们就可以通过 对象名.属性名 来方法所有的属性。

但是,如果属性是数字,从语法解析上就会出错,所以数组就是用 对象名.[index]来访问。

		var skills = new Array(2);
		skills[0] = "千年杀";
		skills[1] = "千鸟";
		// 使用"-1"作为索引
		skills[-1] = "写轮眼";
		console.log(skills.length);// 2
		console.log(skills); 

数组中有三个元素,但是长度是2,说明-1不作为数组的元素索引。

案例:

var person = {name:"卡卡西",skill:"千年杀"}
console.log(person.name);
// 对象的属性也可以使用[]访问
console.log(person["skill"])

案例:

var ns = ["白素贞","卡卡西","小丸子"];
console.log(ns[0]); // ①白素贞
function  changeArray(args){
console.log(args[0]); // ②白素贞
args[0] = "青城山下-白素贞";
console.log(args[0]);// ③青城山下-白素贞
}
changeArray(ns);
console.log(ns[0]); // ④青城山下-白素贞
案例:  var cs = new Array();
        cs['江苏'] = '南京';
        cs['安徽'] = '合肥';
        cs['河南'] = '郑州';
        console.log(cs['江苏']);// 南京
        console.log(cs.length);// 0

tips:上面的例子上可以看出,数组的索引不是数字 。。。

JS中的数组就是一个对象, 我们给数组中添加一个元素,就相当于给数组添加一个属性。这个属性名字就是这个元素的索引。

使用数组名[index] 访问数组元素。JS中只有数组,没有集合

[3]遍历数组

		var scores = [98,96,98,97,99];
		// 获取数组的长度(元素个数)
		console.log(scores.length);
		// 将所有的成绩逐个的打印到控制台
		console.log(scores[0]);
		console.log(scores[1]);
		console.log(scores[2]);
		console.log(scores[3]);
		console.log(scores[4]);
		console.log("-----循环遍历------");
		// 循环遍历数组
		for(var x = 0; x < scores.length;x ++){
			console.log(scores[x]);
		}
      //遍历数组
        for(var x = 0;x < arr1.length;x++){
            console.log(arr1[x]);
        }
        //foreach遍历
        console.log("foreach遍历--和java不同");
        // 将:替换为in关键字。  j表示的是数组的索引
        for(var j in arr1){
            console.log(arr1[j]);
        };

Boolean类型

  • Boolean字面量: true和false,区分大小写

  • 计算机内部存储:true为1,false为0

tips:js中的元素只要存在就是true,不存在就是false。

在JS中字符串 "" 表示 false, “123”表示true 。 0表示false,非0表示true。

看一个案例:

        var a = new Object();//这里的a可以赋值为任何类型
        if(a){
            console.log("a");
        }else{
            console.log("no a");
        }

Undefined和Null

  1. undefined表示一个声明了没有赋值的变量,变量只声明的时候值默认是undefined

  2. null表示一个空,变量的值如果想为null,必须手动设置

        var student;
        var person = null;
        console.log(student);// undefined
        console.log(person);// null

获取变量的类型  typeof

       console.log(typeof car) // object
        console.log(typeof person) // object
        console.log(typeof x) // number
        console.log(typeof "haha")// string
注释:

//单行注释

/*
* 多行注释
*
*/

数据类型转换

转换成字符串类型

  • toString()

    var num = 5;
    console.log(num.toString());
    
  • String()

    String()函数存在的意义:有些值没有toString(),这个时候可以使用String()。比如:undefined和null
    			var u;// undefined
    			console.log(typeof u);
    			// u = u.toString();// undefined没有toString方法
    			u = String(u); // tips这里的s要大写
    			console.log(typeof u);
    
  • 拼接字符串方式

    num + "",当 + 两边一个操作符是字符串类型,一个操作符是其它类型的时候,会先把其它类型转换成字符串再进行字符串拼接,返回字符串

转换成数值类型

  • Number()

    Number()可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaN
    			var score = "98.5a";
    			console.log(typeof score);// string
    			console.log(score);// 98.5a
    			score = Number(score);
    			console.log(typeof score);// number
    			console.log(score);// NaN
    

    TIPS:使用Number()进行转换,字符串必须是数字形式。 “123”,“95.2” 非数字形式:“32.9A”“abc123” 如果是非数字形式就转换为NaN

  • parseInt()

    var num1 = parseInt("12.3abc");  // 返回12,如果第一个字符是数字会解析直到遇到非数字结束
    var num2 = parseInt("abc123");   // 返回NaN,如果第一个字符不是数字或者符号就返回NaN
    	/// 案例1
    			var score = "98.9";
    			console.log(typeof score);// string
    			console.log(score);// 98.9
    			score = parseInt(score);// 将字符串转化为整数
    			console.log(typeof score);// number
    			console.log(score);// 98  tips: 如果有小数部分,直接抛弃。
    	// 当字符串是非数字形式的时候。
    			var score = "98a89";
    			console.log(typeof score);// string
    			console.log(score);// 98a89
    			score = parseInt(score);// 将字符串转化为整数
    			console.log(typeof score);// number
    			console.log(score);// 98 
    // 如果字符串中间出现了非数字,则从非数字字符往前会转换为整形,其他的字符直接抛弃。如果第一个字符就是非数字,则直接转换为NaN
    
  • parseFloat()

    parseFloat()把字符串转换成浮点数
    parseFloat()和parseInt非常相似,不同之处在与
    	parseFloat会解析第一个. 遇到第二个.或者非数字结束
    	如果解析的内容里只有整数,解析成整数
    	
    			var score = "98.89.56";
    			console.log(typeof score);// string
    			console.log(score);// 98.89.56
    			score = parseFloat(score);// 将字符串转化为Float
    			console.log(typeof score);// number
    			console.log(score);// 98.89
    
  • +,-0等运算

    var str = '500';
    console.log(+str);		// 取正
    console.log(-str);		// 取负
    console.log(str - 0);
    

    tips:当使用字符串和数字进行数学运算的时候,如果没有歧义(+可以链接字符串),会自动将字符串转换为数字,如果字符串不是纯的数字形式,最终的结果就是NaN。

转换成布尔类型

  • Boolean()

0 ''(空字符串) null undefined NaN 会转换成false 其它都会转换成true

操作符(运算符)

运算符 operator

5 + 6

表达式 组成 操作数和操作符,会有一个结果

算术运算符

+ - * / %  

和数学中表达的意思是一样的。

+特殊情况: 当两个字符串使用+连接的时候,会作为字符串连接。

对了还是有点区别的:

两个字符串也许是可以作任何算数运算的。如果是“+”有可能会出现字符串连接。

			var score1 = "23";
			var score2 = "25";
			// 字符串连接
			var score = score1 + score2;// 2325
			console.log(score);
			// 转换再运算。
			score = eval(score1)+eval(score2);
			console.log(score);
			score = parseInt(score1) + parseInt(score2);
			console.log(score);
			// 其他的运算,如果操作数不出现非数字形式的字符串,都会自动转换
			score = score1 - score2;
			console.log(score);
			// 如果操作数出现非数字形式,最终结果都是NaN
			score = score1 - "123a";
			console.log(score);// NaN

一元运算符

一元运算符: ++ -- (常常被称为自加自减)。

用法:

var x = 10;
x ++; // 11  给自己+1。

++和--在操作数的前后是有区别的。

试题:

15  var x = 2;
16  var j = x ++;
x和j分别是多少?
x = 3; j = 2;

tips: 任何时候使用++和--无论在前还是在后,一旦程序执行之后,被操作数肯定+1或者-1了。

++在前,先++后运算。 ++在后,先运算后++;

j = x ++;
先把x的值赋值给j,再给x++;
j = ++ x;
先把x++ 再赋值给j。

案例:
var x = 2;
j = x ++ + 4;
y = ++ x + 5;
上面的情况
x = 4;
j = 6;
y = 9;

试题:

var x = 3;
y = x ++ + ++ x;
结果:
x = 5;
运算过程: 先计算++x,x=4; 继续计算 x + x (4 + 4),接下来就是赋值。所以y是8。 接下来执行 x ++;x = 5;

试题:交换两个变量的值。

var x = 3;y = 4;

中间变量做法:

var t = x;

x = y;

y = t;

在不使用中间变量的情况下的做法:

x = x + y;

y = x - y;

x = x - y;

关系运算符(比较运算符)

任何时候一个表达式中只要出现了 “ 关系运算符 ”,那么这个表达式的结果必然是一个boolean值。

<  >  >=  <= == != === !==
①绝对不能出现等于大于  >=  也不能出现 等于小于 
②比较两个变量的值是否相等,使用 == 是否不相等使用 !=
③比较两个变量的值和类型是否相等,使用 === 
==与===的区别:==只进行值得比较,===类型和值同时相等,则相等
			var x  = 10;
			var y = 9
			var result = x > y;
			console.log(result);
			// <  >=   <=  都是一样的。
			// 如果是字符串....
			var name = "卡卡西";
			var name1 = "佐助";
			result = name < name1;
			console.log(result);
			// 数字形式的字符串直接按照数字处理。
			var score = "98.5"
			var score1 = 98.5;
			console.log(score >= score1);
			// 运算符 == 和 !=
			var s1 = "abc";
			var s2 = "abc";
			console.log(s1 == s2);// true
			console.log(s1 != s2);// false
			var c1 = "95.8";
			var c2 = 95.8;
			console.log(c1 == c2);// true
			var c3 = "abc" - 98;
			var c4 = "def" * 95;
			console.log(c3 == c4);// false 所有的NaN == 的结果都是false。
			// 运算符 === (要求值和类型完全一致,才是true)
			var c1 = "95.8";
			var c2 = 95.8;
			console.log(c1 === c2);// false
			console.log(c1 !== c2);// true
逻辑运算符(布尔运算符)

逻辑运算符主要用来链接或者操作一个或多个结果为布尔值的表达式。

&& 与 两个操作数同时为true,结果为true,否则都是false || 或 两个操作数有一个为true,结果为true,否则为false ! 非 取反

案例:

		var score1 = 90;
		var score2 = 80;
		// 两个条件同时是true
		var result = score1 >= 85 && score2 >= 85;
		console.log(result);
		// 两个条件满足一个即可
		result = score1 >= 90 || score2 >= 90;
		console.log(result);
		// 逻辑非 ! 取反  优先级贼高
		result = !(score1 >= 90) || score2 >= 90;
		console.log(result);
		
		result = !(score1 >= 90 || score2 >= 90);
		console.log(result);

逻辑运算符连或者操作的表达式肯定是boolean类型的表达式。 任何一个表达式如果出现了逻辑运算符,结果肯定也是boolean值。

短路情况:

(笔试面试常考的细节)

		// 特殊情况
		var score1 = 90;
		var score2 = 80;
		var a = 10;
		result = score2 > 85 && (a = score1) > 85;
		console.log(result);// false
		console.log(a);// 10

逻辑与 && 和逻辑或|| 都有短路的作用:当运算符前面的表达式已经决定了整个表达式的结果,运算符后面的表达式不会再运算了。

赋值运算符

= += -= *= /= %=

赋值运算符的主要作用就是将运算符右边的表达式的结果赋值给左边的变量。

例如:
var num = 0;
num += 5;	//相当于  num = num + 5;

运算符的优先级

优先级从高到底
	1. ()  优先级最高
	2. 一元运算符  ++   --   !  (++和--要考虑在前还是在后)
	3. 算数运算符  先*  /  %   后 +   -
	4. 关系运算符  >   >=   <   <=
	5. 相等运算符   ==   !=    ===    !==
	6. 逻辑运算符 先&&   后||
	7. 赋值运算符

案例:计算一个年份是否是闰年

var result = ((year % 400) == 0) || (((year % 100) != 0) && ((year % 4) == 0));

三目运算

或者说是三元运算。

运算符:result = 表达式1 ? 表达式2 : 表达式3

result的结果 = 如果表达式1的结果是true,则整个表达式的结果是表达式2的结果。如果表达式1的结果是false,则整个表达式的结果是表达式3的结果。

性别:

		var gender = 1;
		console.log(gender == 1?'男':'女');

流程控制

程序的三种基本结构

顺序结构从上到下执行的代码就是顺序结构

程序默认就是由上到下顺序执行的

分支结构根据不同的情况,执行对应代码

循环结构重复做一件事情

分支结构

if语句

语法结构

情况1: 如果xxx就xxxx

if (/* 条件表达式 */) { // 执行语句}

案例:

            var score = 85;
            if(score > 85){
                console.log("奖励《奎华宝点》");
            }
            console.log("程序结束")

情况2:如果xxx就xxx,否则就xxxx

if (/* 条件表达式 */){ // 成立执行语句 } else { // 否则执行语句 }

案例:

            var score = 85;
            if(score > 85){
                console.log("奖励《奎华宝点》");
            }else{
                console.log("奖励《一顿暴揍》");
            }
            console.log("程序结束");
            // 三目运算解决问题
            console.log(score > 85 ?"《奎华宝点》":"《一顿暴揍》");

tips: 这个世界上最远的距离就是你在if里,我在else里。 if(条件),条件理论上必须是布尔值的表达式。但是js中的默认会自动将其他类型转换为布尔型。所以书写上就感觉可以写任何类型。

            var x = 0;
            if(x){// 默认会将其他的类型转换为布尔型、
                console.log("111");
            }else{
                console.log("222");
            }

其他类型转换为布尔值的情况:

其他类型布尔型
数字 0->false,非0 -> true
字符串 "" -> false,其他都是true
undefined,null,NaN 全部都是false
其他的对象 全部都是true

案例:

var username = document.getElementById("username").value;
// 判断用户名是否是空字符或者是否是undefined
if(username != undefined && username != ""){
    // username不是空的
}
// ---------------
if(username){
    // username不是空的
}else{
    // username是空的
}

情况3 多重分支语句

if (/* 条件1 /){ // 成立执行语句 } else if (/ 条件2 /){ // 成立执行语句 } else if (/ 条件3 */){ // 成立执行语句 } else { // 最后默认执行语句 }

tips:这里的if(条件) 后面的条件可以是任何类型,因为它会自动进行类型转换。 else模块是可选的。

        <input type="text" id="score">
        <input type="button" onclick="showScore()" value="click me">
        <script>
            function showScore(){
                var score = document.getElementById("score").value;
                if(score == undefined || score ==""){// 没有输入任何内容
                    alert("请输入一个成绩");
                    return;// 让这个程序中断
                }
                // 判断输入的是否是一个数字
                if(isNaN(Number(score))){ // 如果是true,就说明不是一个数字
                    alert("请输入一个数字");
                    return;// 让这个程序中断
                }
                // 判断数字范围
                if(score > 100 || score < 0){
                    alert("请输入一个0~100之间数字");
                    return;
                }
                // 你输入的格式符合要求了
                // 多重分支
                if(score >= 90){
                    console.log("奖励《亏华宝殿》");
                }else if(score >= 80){
                    console.log("奖励宝马自行车");
                }else if(score >= 70){
                    console.log("奖励《三年模拟五年高考》");
                }else{
                    console.log("奖励《一顿暴揍》");
                }
            }
        </script>

tips:即使是多重分支语句,也是永远最多执行一个语句块。如果某一个判断条件已经成立,其他的条件就不会再判断了。

多重分支要注意的一些问题:

上面的案例做一个简单的修改:

            // 你输入的格式符合要求了
            // 多重分支
            if(score >= 70){
                console.log("奖励《三年模拟五年高考》");
            }else if(score >= 80){
                console.log("奖励宝马自行车");
            }else if(score >= 90){
                console.log("奖励《亏华宝殿》");
            }else{
                console.log("奖励《一顿暴揍》");
            }

上面的程序中只要超过70分就是三年模拟五年.....

避免上面的问题的解决方案:

[1]不要把顺序写错了。

[2]把条件写完整

分支语句的嵌套

分支语句中{}表示一个分支语句块。

一个语句块中可以写其他的执行语句获取其他的分支语句。

案例:

        <input type="text" placeholder="请输入年龄" id="age">
        <input type="button" onclick="parseAge()" value="click me">
        <script type="text/javascript">
            function parseAge(){
                var age = document.getElementById("age").value;
                if(age){// 分支语句中再嵌套一个分支
                    if(age < 18 || age > 150){
                        alert("年龄大小不符合范围");
                    }else{
                        alert("OKKKKKKK");
                    }
                }else{
                    alert("请输入一个年龄");
                }
            }
        </script>

tips: 在实际的开发中,尽量避免复杂的分支语句和分支嵌套。

switch语句

语法格式:

switch (expression) {
  case 常量1:
    语句;
    break;
  case 常量2:
    语句;
    break;
  case 常量3:
    语句;
    break;
  …
  case 常量n:
    语句;
    break;
  default:
    语句;
    break;
}

tips:这里的expression机会没有限制。break是非必须的。 default块也是可选的。

看一个简单案例:

        <input type="text" placeholder="请输入年级" id="grade">
        <input type="button" onclick="parseGrade()" value="click me">
        <script type="text/javascript">
            function parseGrade(){
                var grade = document.getElementById("grade").value;
                // 使用switch输出年级的特性
                switch(grade){
                    case '1':
                        console.log("积极的回答问题!");
                        break;
                    case '2':
                        console.log("就知道玩!");
                        break;
                    case '3':
                        console.log("你就是校园的老大!");
                        break;
                    case '4':
                        console.log("你根校园马上就没有关系了!");
                        break;
                    default:
                        console.log("已经进入社会,被社会毒打!");
                }
            }
        </script>

break是可选的,如果删除break,会出现如下的情况:

当case 2 符号条件之后,后面的所有程序都会执行。

因为在swtich结构中,如果某一个case判断为true,后面的case默认全部是true。

我们使用break就为了跳出当前的swtich结构,不再执行后面的程序。

问题switch ...case 和多重的if esle if . ....有些相似。能不能互换?

案例1: 使用if else if 替换switch

                    // 使用多重的if  else  替换swtich
                    if(grade =='1'){
                            console.log("积极的回答问题!");
                        }else if(grade == '2'){
                            console.log("就知道玩!");
                        }else if(grade == '3'){
                            console.log("你就是校园的老大!");
                        }else if(grade == '4'){
                            console.log("你根校园马上就没有关系了!");
                        }else{
                            console.log("已经进入社会,被社会毒打!");
                    }

swtich只能做等值判断。 所以所有的等值判断的分支,都可以使用swtich。

if else if 可以是做任何的分支判断。

tips:能使用swtich的地方  不要使用多重的if else ......

循环结构

在javascript中,循环语句有三种,while、do..while、for循环。

循环结构是用来执行多次相同或者相似的操作。

while语句

基本语法:

// 当循环条件为true时,执行循环体,
// 当循环条件为false时,结束循环。
while (循环条件) {
  //循环体
}

案例1:一个简单的死循环(浏览器会奔溃,建议不要尝试这个程序)

        <script type="text/javascript">
            // 先判断while中的条件是否是true,如果是就执行循环语句
            // 执行循环语句之后,再次判断条件......
            while(1 == 1){// 这个循环是一个死循环
                console.log("明年就中500W!");
            }
        </script>

案例2:简单循环

    <script type="text/javascript">
        var i = 0;
        while( i < 10 ){
            console.log(i+"明年就中500W!");
            i ++;
        }
    </script>

while循环的特点:先判断,后执行,有可能一次都不执行。 退出循环的位置在判断条件的位置。

问题:计算1~100之间所有的数的和。

    <script type="text/javascript">
        // 计算1到100之间的和
        var x = 1;
        var sum = 0;
        while( x <= 100){
            sum += x;// sum = sum + x;
            x ++;
        }
        console.log("sum = "+sum);
    </script>

do...while语句

do..while循环和while循环非常像,二者经常可以相互替代,但是do..while的特点是不管条件成不成立,至少会执行一次。

基础语法:

do {
  // 循环体;
} while (循环条件);

执行流程:先执行后判断。

先执行循环体,再判断循环条件,如果条件成立,则继续循环,条件不成立,退出循环。

案例1:不写死循环了。

    <script type="text/javascript">
        // do while循环
        var j = 0;
        do{
            console.log("22年要找"+j+"个对象");
            j ++;// 不要忘记
        }while(j < 10); // 也执行10次
    </script>

do while 无论如何都会执行一次。

案例2: 计算1~100之间所有的偶数的和

	<script type="text/javascript">
		var y = 1;
		var sum = 0;
		do{
			if(y % 2 == 0){// 当y是偶数的时候才+
				sum += y;
			}
			y ++;
		}while(y <= 100);
		console.log("sum = "+sum);
	</script>

for语句

while和do...while一般用来解决无法确认次数的循环。for循环一般在循环次数确定的时候比较方便

for循环语法:

// for循环的表达式之间用的是;号分隔的,千万不要写成,
for (初始化表达式1; 判断表达式2; 自增表达式3) {
  // 循环体4
}

for循环中的表达式不是必须的。

案例1:

	<script type="text/javascript">
		for(var x = 0;x < 10;x ++){
			console.log(x + "->这个是for循环");
		}
	</script>

上面for循环的执行流程:

进入for循环立刻执行表达式1,
接下来执行表达式2,表达式2结果为true,执行循环体,为false退出循环。
如果执行了循环体,接着执行表达式3。
执行完表达式3表示一个循环结束。接着执行表达式2。继续判断是否循环。。。。。

流程应该是:1,2,3,4, 2,3,4...... 当2为false的时候退出循环。

表达式1在进入循环的时候执行一次,以后不会再执行。

表达式2最终都会被转换为布尔值。

看看下面的例子:

			var x = 0
			for(console.log("循环开始");x < 10;x ++,console.log("一次循环结束")){
				console.log(x + "->这个是for循环");
			}

for循环的第一个表达式不一定就是循环变量定义。可以是任何可执行的语句。表达式3也是可以写任何可执行的程序。

案例2: 计算一个数字的阶乘。1x2x3x4x5x6x7x8x9x10 = 10!

	<input type="text" id="num">
	<input type="button" value="click me" onclick="jiechen()">
	<script type="text/javascript">
		function jiechen(){
			var num = document.getElementById("num").value;
			num = parseInt(num);
			// 使用for循环计算阶乘
			var result = 1;
			for(var x = 2; x <= num ;x ++){
				result *= x;// result = result * x;
			}
			document.getElementById("num").value=result;
		}
	</script>
for...in:
在处理key-value数据(比如属性用作“键”)需要检查其中的任何键是否为某值的情况下使用
//下面的函数接受一个对象作为参数,被调用时迭代传入对象的所有可枚举属性
//然后返回一个所有属性名和其对应值的字符串 打印数组里的下标
案例:
var obj = {a:1,b:2,c:3};
for(var k in obj){
console.log("obj."+k+"="+obj[k]);//obj.a=1 obj.b=2 obj.c=3
}
forEach():5.1引入
var num = [11,54,5,64,6,76,7];
num.forEach(function(value){
console.log(value);//遍历获取到每个值
})
for...of:
var arr =[3,4,5];
for(var x of arr){
console.log(x);//3,4,5 打印具体的值
}
Map 和 Set
//ES6的新特性
Set:无序不重复的集合
案例:
var map = new Map([['Tom',100],['Jack',80],['Rose',66]]);
var name = map.get('Tom');//通过key获得value的值
var set = new Set([3,1,1,1,1])//3,1 Set可以去重
console.log(name);//100
map.set('admin',123456);//新增或修改
map.delete('tom');//删除
set.delete(1);//3 删除
set.add(2);//3,2 添加
console.log(set.has(3));//true 是否包含某个元素
iterator es6新特性
for... of
//遍历map
var map = new Map([['Tom',100],['Jack',80],['Rose',66]]);
for(let x of map){
console.log(x);//['Tom',100] ['Jack',80] ['Rose',66]
}
//遍历Set
var set = new Set([5,6,7,8]);
for(let x of set){
console.log(x);//5,6,7,8
}

continue和break

break:立即跳出整个循环,即循环结束,开始执行循环后面的内容(直接跳到大括号)

continue:立即跳出当前循环,继续下一次循环(跳到i++的地方)

break 中断当前的循环

案例1:

	<script type="text/javascript">
		// break
		for(var x = 0;x < 10;x ++){
			console.log(x+"--你好!");
			if(x == 5){
				break;// 中断循环
			}
		}
		
	</script>

案例:2计算两个数字的最小公倍数。

	<input type="text" id="num1" placeholder="第一个数">
	<input type="text" id="num2" placeholder="第一个数">
	<input type="button" value="click me" onclick="jisuan()">
	<script type="text/javascript">
		function jisuan(){
			// 从相对比较大的数开始往上+1,进行测试
			var num1 = document.getElementById("num1").value;
			var num2 = document.getElementById("num2").value;
			// 找出相对较大的数据
			var n = num1 > num2 ? num1:num2;
			// 开始循环,这里我们不知道循环次数
			while(true){
				if(n % num1 == 0 && n % num2 == 0){
					// 最小公倍数找到,退出循环。
					break;
				}
				n ++;
			}
			console.log(num1+"和"+num2+"的最小公倍数是:"+n);
		}
	</script>

continue中断本次循环,继续下次循环

案例1:

	<script type="text/javascript">
		// break
		for(var x = 0;x < 10;x ++){
			if(x == 5){
				continue;// 中断本次循环,继续下次循环
			}
			console.log(x+"--你好!coninue");
		}
	</script>

案例2: 计算1~100之间所有可以被3整除的数的和

	<script type="text/javascript">
		var sum = 0;
		for(var x = 1;x <= 100;x ++){
			if(x % 3 != 0){
				continue;// 不能被3整除的就直接continue
			}
			sum += x;
		}
		console.log(sum);
	</script>

调试

  • 过去调试JavaScript的方式

    • alert()

    • console.log()

  • 断点调试

断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。

  • 调试步骤

浏览器中按F12-->sources-->找到需要调试的文件-->在程序的某一行设置断点

  • 调试中的相关操作

Watch: 监视,通过watch可以监视变量的值的变化,非常的常用。
F10: 程序单步执行,让程序一行一行的执行,这个时候,观察watch中变量的值的变化。
F8:跳到下一个断点处,如果后面没有断点了,则程序执行结束。

函数

模块化编程。就是java中的方法。

函数的定义

  • 函数声明

方式1:
function 函数名(参数列表){
    函数体(要执行的代码)
}
//function abs(x){
if(x>0){return x;}else{return -x;}
} 方式2: var 函数名 = function(参数列表){   函数体(要执行的代码) }
//var fun1 = function(){
console.log(456);
}
fun1();
  • 特点:

    函数声明的时候,函数体并不会执行,只要当函数被调用的时候才会执行

function:固定关键字 必须的

参数列表:表示执行这个函数的时候,需要提前准备的数据。 可以为空

函数体:要执行的代码。

函数名:名字,在一个作用域内,不能有同名的函数。 命名规则和规范与变量的命名规则和规范一致。 必须的

函数可以简单的认为是做一个事的方法,方法就是一个行为,一个动作。

比如:炒 《西红柿炒鸡蛋》的过程就是一个函数。函数可以重复的被调用。

函数的调用 (函数的调用应该在函数申明和实现之后)

  • 调用函数的语法:函数名();

案例:

        //定义一个函数
        //第一种方式
        function sayHello(){
            console.log("hello");
        }
        //第二种定义函数的方式
        var sayBey=function(){
            console.log("再见");
        }
        //调用函数
        sayHello();
        sayBey();

函数的返回值

所谓返回值,就是这个函数执行结束之后得到的结果。并不是每个函数都有返回值。有的函数就是纯粹的执行,没有返回值。

  • 返回值不需要申明

  • 如果这个方法没有返回值,则默认返回undefined

  • 如果有返回值,只需要在最后一行使用return返回即可。

        //有返回值的函数
        function md(n){
            var r = eval(n)+1;
            return r==10?0:r;
        }
        var str = '950506';
        var s = "";
        for(var x = 0;x < str.length;x ++){
            var ch = str.charAt(x);
            //调用有返回值的函数
            var rs = md(ch);
            s += rs;
        };
        console.log(s);

案例1:在页面输出几个标签 这个函数就没有返回值

<script type="text/javascript">
function showTag(){
for(var x = 0;x < 3;x++){
document.write("<h2>哈哈哈</h2>");
}
}
showTag();
</script>

案例2: 定义一个函数,计算两个数字的和,并且返回

<script type="text/javascript">
// 有返回值的函数
function he(n1,n2){
var sum = n1 + n2;
// 使用return返回一个返回值。
return sum;
// 任何使用,return如果执行了,后面的程序将不再执行。
}
// 调用有返回值的函数
var result = he(1,101);// 我们将函数执行的结果赋值给result变量
console.log(result);
</script>

在函数中使用return返回一个变量, 或者一个数据对象等等。这时这个函数在调用之后就会得到返回的结果,并且在return关键字后面的程序将不再执行。

函数的参数

js是弱数据类型,在申明参数的时候,不需要申明数据类型,只要写清楚参数的名称和个数就好。
        //函数的参数
        function eat(food){
            console.log("吃"+food);
        }
        //调用有参数的函数
        eat("米饭");
        function sleep(name,time){
            console.log(name+"睡了"+time+"毫秒");
        }
        sleep("卡卡西",56416316456);

有的时候,申明或者不申明参数,好像对函数的调用也没啥影响

        //有一个参数的函数
        function fn(n){
            console.log(n);
        }
        fn();// undefined
        fn(1,2,3,4,5,6);//1
arguments:代表传递进来的所有的参数,是一个数组
案例:
var abs = function(x){
console.log("x=>"+x); //x=>123
for(var i = 0;i<arguments.length;i++){
console.log(arguments[i]); //123 23 3234 4353
}
if(x>=0){return x;}else{return -x;}
}
abs(123,23,3234,4353);
arguments包含所有的参数,我们有时候想使用多余的参数来进行附加操作,需要排除已有的参数
rest 获取除了已经定义的参数之外的所有的参数 ES6引入的新特性,rest参数只能写在最后面,必须用...标识
function aaa(a,b,...rest){
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
aaa(1);//a=>1 b=>undefined []
aaa(1,1233,3,45,89);//a=>1 b=>1233 (3)[3,45,89]

函数传参

申明函数的时候,申明参数。

案例: 申明一个函数,可以使用xxx炒鸡蛋。

<script>
/**
 * 申明函数
 * 
 */
function chaojidan(food){
console.log("-------")
console.log("把鸡蛋准备好....");
console.log("炒鸡蛋...");
console.log("加入"+food+",继续炒....");
console.log("出锅装盘:《"+food+"炒鸡蛋》");
}
chaojidan("青椒");
chaojidan("番茄");
chaojidan("鸭蛋");
</script>

上面的案例中,小括号中的food就是参数。

参数名可以随意,但是不能太随意。按照变量命名的规则和规范指定。

申明参数的意思是:当调用这个函数的时候,可以在()中传递参数,所谓传递参数就是给参数赋值。

多个参数的案例:

// 多个参数的案例
function chaocai(food1,food2,count){
console.log("-------")
for(var i = 0; i < count;i++){
console.log("第"+(i+1)+"份《"+food1+"炒"+food2+"》出锅");
}
}
// 调用函数的时候传入多个参数
chaocai("番茄","鸡蛋",3);
chaocai("土豆","马铃薯",4);

当有多个参数的时候,就按照参数的顺序传入对应的参数。参数的类型要注意:如果是字符串就要使用引号包裹。如果是数字,不需要引号。

当然我们可以把一个变量作为参数,当变量作为参数的时候,无论是什么类型,都不要使用引号。

案例:

var f1 = "西葫芦";
var f2 = "肉片";
var c = 5;
// 把变量作为参数传递
chaocai(f1,f2,c);

函数其它

匿名函数

匿名函数:没有名字的函数

匿名函数如何使用:

将匿名函数赋值给一个变量,这样就可以通过变量进行调用
匿名函数自调用

关于自执行函数(匿名函数自调用)的作用:防止全局变量污染。

自调用函数

匿名函数不能通过直接调用来执行,因此可以通过匿名函数的自调用的方式来执行

        //自执行函数(往往是用来做初始化工作的)
        (function fn1(a){
            console.log("做一些初始化的工作:"+a);
        })("准备一些数组");
        //fn1("准备一些数组");

函数是一种数据类型

function fn() {}
console.log(typeof fn);
  • 函数作为参数

因为函数也是一种类型,可以把函数作为两一个函数的参数,在两一个函数中调用

  • 函数做为返回值

因为函数是一种类型,所以可以把函数可以作为返回值从函数内部返回,这种用法在后面很常见。

        //函数可以作为参数传递
        function fn2(f){
            console.log("执行fn2");
            //调用f函数
            f();
        }
        //随意定义一个函数
        function fn3(){
            console.log("执行fn3");
        }
        //调用fn2,将fn3作为参数传递到fn2中。
        fn2(fn3);

        //函数作为返回值
        function fn4(){
            console.log("执行 fn4 ");
            return function(){
                console.log("fn4 内部产生的一个函数");
            }
        }
        //调用fn4得到一个函数对象
        var fn5 = fn4();
        //调用fn5
        fn5();//fn4 内部产生的一个函数

作用域

作用域:变量可以起作用的范围,在JS中var定义变量实际是有作用域的,

假设在函数体中声明,则在函数体外不可以使用(要实现闭包)

在JS中函数查找变量从自身函数开始,由内向外查找,假设外部存在同名的函数变量,则内部函数会屏蔽外部函数的变量。

全局变量和局部变量

  • 全局变量

    在任何地方都可以访问到的变量就是全局变量,对应全局作用域

<script>  

var x =1;//全局变量

function f(){console.log(x);}

f();//1    console.log(x);//1

</script>

  全局对象  window 

var x = 'xxx';

window.alert(x); 

window.alert(window.x);//默认所有的全局变量,都会自动绑定在window 对象下

由于我们所有的全局变量都会绑定到window上,如果不同的js文件使用了相同的全局变量,会发生冲突 ,如何减少冲突??

把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突的问题

//唯一全局变量

var doller = {};

//定义全局变量

doller.name = 'daole';

doller.sum = function (a,b){

return a + b;

}

  • 局部变量

    只在固定的代码片段内可访问到的变量,最常见的例如函数内部。对应局部作用域(函数作用域)

不使用var声明的变量是全局变量,不推荐使用。变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁
案例:
function name(){
var x = 1;
//内部函数可以访问外部函数的成员,反之则不行
function name2(){
var y = x + 1;//2
}
var z = y + 1;
}
name();
// y is not defined
案例:
function aa(){
for(var i = 0;i<100;i++){
console.log(i);//0-99
}
console.log(i+1);//?? i出了作用域还可以使用
}
aa();//0-101
let 关键字,解决局部冲突问题 ,一般都是用let定义局部作用域的变量 ES6
function aa(){
for(let i = 0;i<100;i++){
console.log(i);//0-99
}
console.log(i+1);//i is not defined
}
aa();//0-99
常量 const
const PI = '3.14';//只读变量
PI = '123'; //TypeError:Assignment to constant variable
console.log(PI);
在ES6 之前,定义常量用全部的大写字母命名,但这个值可以改变,如 var PI = '3.14';

块级作用域

任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

词法作用域

变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。

在 js 中词法作用域规则:

  • 函数允许访问函数外的数据.

  • 整个代码结构中只有函数可以限定作用域.

  • 作用域规则首先使用提升规则分析

  • 如果当前作用规则中有名字了, 就不考虑外面的名字

var num = 123;
function foo() {
  console.log( num );
}
foo();

if ( false ) {
    var num = 123;
}
console.log( num ); // undefiend

作用域链

只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。

将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。
// 案例1:
function f1() {
    function f2() {
    }
}
var num = 456;
function f3() {
    function f4() {    
    }
}

预解析

JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程

预解析过程:

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。

  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。

  3. 先提升var,在提升function

        //console.log(a);// 错误  a  is  not defined
        console.log(b); // undefinde
        m();// 输出m
        var b = 10;
        function m(){
            console.log('m');
        }
//所有的变量定义都放在函数的头部,便于代码的维护

对象

面向对象思想

面向对象是一个思想,跟编程语言没有关系。面向对象的思想实现的最经典的语言就是 java。计算机语言都是向着人类更容易理解的方向在发展。

使用面向过程的方式描述你早上刷牙这件事:准备牙刷,牙膏,打水,漱口,刷牙,漱口,  步骤。。。。。

使用面向对象的方式描述:过程中的一些事物:人,牙刷,牙膏,杯子等等

这些事物都有哪些特征和行为:

人:

特征:性别,名字等等   行为:打水,挤牙膏,刷牙等等

牙刷:

特征:尺寸,颜色,品牌等等  行为:刷牙。。。。

杯子:

特征:大小,颜色。。。  行为:盛水。。。。

这些事物之间如何配合完成工作:

人拿杯子打水,漱口,使用牙刷刷牙。

今天刷牙的时候,发现牙刷掉毛了。。。。。。。。 换牙刷。。。。

牙膏过期了,换牙膏。。。。。

万物皆对象

面向对象的描述一件事情:找出一件事情中的事物(对象),明确这些事物的特征和行为,明确它们之间的配置方式(接口)。

描述表示

特征:看得见,摸得着的。

行为:能干啥?

对象就是任何一个具体的事物。

高内聚,低耦合

程序中的面向对象

对象的创建

  • 对象字面量   

var person = { //若干个键值对,JS中所有的键都是字符串,值是任意对象!
  name: 'zs',
  age: 18,
  sex: true,
  sayHi: function () {
    console.log(this.name);
  }
};   
//判断属性值是否在这个对象中 xxx in xxx
'age' in person //true
'toString in person' //true 继承
//判断一个属性是否是这个对象自身拥有的 hasOwnProperty()
person.hasOwnProperty('toString')//false
person.hasOwnProperty('age')//true
  • new Object()创建对象

var person = new Object();
  person.name = '卡卡西';
  person.age = 35;
  person.job = '高级忍者';
  person.sayHi = function(){
  	console.log('千年杀');
  }
  • 工厂函数创建对象

function createPerson(name, age, job) {
  var person = new Object();
  person.name = name;
  person.age = age;
  person.job = job;
  person.sayHi = function(skill){
    console.log(skill);
  }
  return person;
}
var p1 = createPerson('鸣人', 18, '初级忍者');
  • 自定义构造函数

function Person(name,age,job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayHi = function(skill){
  	console.log(skill);
  }
}
var p1 = new Person('鸣人', 18, '初级忍者');

属性和方法

一些概念:

案例中的person就是对象。其中name,age称之为属性行为:sayHi称之为方法

方法就是把函数放在对象的里面

对象中属性和行为调用:

[1]创建对象时设置属性和行为

[2]也可以在创建对象之后设置属性和行为

给对象设置属性和行为的语法:

对象名.属性名 = 属性值。
对象名.方法名 = function(){.....}

也可以使用这样的语法修改原来的属性值和行为。

调用对象中的属性和行为。

所谓调用属性,就是获取属性值:

		console.log(person.name);
		console.log(person.age);

对象名.属性名 如果后面有=就是赋值,如果没有就是获取值。

方法的调用是: 对象名.方法名(参数) 调用方法一定要带()!!

		person.sayHi();

方法的参数和返回值与之前函数的操作一致。

new关键字

构造函数 ,是一种特殊的函数。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

  1. 构造函数用于创建一类对象,首字母要大写。

  2. 构造函数要和new一起使用才有意义。

new在执行时会做四件事情

new会在内存中创建一个新的空对象
new 会让this指向这个新的对象
执行构造函数  目的:给这个新对象加属性和方法
new会返回这个新对象

this详解

JavaScript中的this指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解
现在我们需要掌握函数内部的this几个特点
	1. 函数在定义的时候this是不确定的,只有在调用的时候才可以确定
	2. 一般函数直接执行,内部this指向全局window
	3. 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
	4. 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到了这个隐式对象身上,后续通过new关键字来调用,从而实现实例化
案例:
var zhangsan = {
name:'zhangsan',
birth:2000,
age:function(){
var now = new Date().getFullYear();
return now-this.birth;
}
}
console.log(zhangsan.age());//22
把上面的案例拆分来写:
function getAge(){
var now = new Date().getFullYear();
return now - this.birth;
}
var zhangsan = {
name:'zhangsan',
birth:2000;
age:getAge//只写函数名
}
getAge();//NaN
zhangsan.age();//22
在JS中 apply 可以控制指向
getAge.apply(zhangsan,[]);this指向了zhangsan,参数为空

对象的使用

遍历对象的属性

通过for..in语法可以遍历一个对象

var obj = {};
for (var i = 0; i < 10; i++) {
  obj[i] = i * 2;
}
for(var key in obj) {
  console.log(key + "==" + obj[key]);
}

删除对象的属性

function fun() { 
  this.name = 'mm';
}
var obj = new fun(); 
console.log(obj.name); // mm 
delete obj.name;//动态的删减属性,也可以动态添加属性,给新的属性添加值即可
console.log(obj.name); // undefined

对象作为参数传递

在js中我们可以将一个对象作为一个参数进行传递。

参数传递中的一些问题

程序1:

<script type="text/javascript">
var num = 100;
console.log(num); // ①100
function changeNum(n){
console.log(n); // ②100
n = 10000;
console.log(n); // ③10000
}
changeNum(num); // n = num
// -------------
console.log(num); // ④100
</script>

程序2:

	<script type="text/javascript">
		var person = {name:"大锤"};
		console.log(person.name);// ①大锤
		function changeName(p){
			console.log(p.name); // ②大锤
			p.name = "小锤锤";
			console.log(p.name); // ③小锤锤
		}
		changeName(person);
		console.log(person.name); // ④小锤锤
	</script>

程序②的结果和程序③的结果截然不同,是因为对象和简单类型在内存中的存储是不一样的。

对象在栈中只有一个地址,堆里面值具体数据。

总结:

简单类型的引用和数值都是存储在栈内存中。

对象是引用存储在栈中,具体的数据存储在堆内存中的。栈中的存储着堆中数据的地址。

所谓传参或者说赋值:就是将栈中的内容进行拷贝传递。

具体的描述:

简单类型,就是我把我的书复印一份给你。你随便折腾。看坏了,也跟我没关系。

对象类型,就是我把我书借给你。你要是看坏了,我的书就坏了。

简单类型和复杂类型的区别

基本类型又叫做值类型,复杂类型又叫做引用类型

值类型:简单数据类型,基本数据类型,在存储时,变量中存储的是值本身,因此叫做值类型。

引用类型:复杂数据类型,在存储是,变量中存储的仅仅是地址(引用),因此叫做引用数据类型。

  • 堆和栈

    堆栈空间分配区别:
      1、栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
      2、堆(操作系统): 存储复杂类型(对象),一般由程序员分配释放, 若程序员不释放,由垃圾回收机制回收,分配方式倒是类似于链表。
    
  • 注意:JavaScript中没有堆和栈的概念,目的方便理解和方便以后的学习。

基本类型和复杂类型在内存中的存储和java是一样的。