Danmo的学习之路(JavaScript基础_上)

文章目录


11.21
虽然还没学完H5和CSS,怀着好奇心,先来了解一下JS。

ECMAScrpt是JavaScript标准,一般情况下我们认为这两个词是一个意思。
但一个完整的JavaScrpt由三部分构成:ECMAScript(标准/浏览器端)、DOM(文档对象模型,提供操作对象使我们操纵网页)、BOM(浏览器对象模型,提供操作对象使我们操纵浏览器)

11.22

JS 写Hello World/引入

  • JS按顺序执行。

  • 语句:

    • alert控制浏览器弹出一个警告框。
    • document.write()可以向body内输出一个内容。
    • console.log()可以在控制台内输出一个内容,控制台在右键“检查”里可以看。
		alert("警告:Hello World");
		/*打开页面时弹出警告框,内容是"Hello World"*/
		document.write("我出现在body中")/*括号内的话出现在主页面内*/
		console.log("我出现在控制台中")

11.23

  • JS书写的位置
    • script标签内写JS,也可以引入外部文件,引入仍然用script。
    • 可以将JS写到标签的onclick属性中 ,比如点击按钮执行js。
    • 可以点击超链接执行js,写在href中。
<script type="text/javascript" src=""></script>
/*引入外部js文件,src内写文件路径*/
<button onclick="alert('讨厌,点我干嘛啦!');">点我一下</button>
/*按钮,注意符号*/
<a href="javascript:alert('让你点你就点?!');">你也点我一下</a>
/*超链接*/

数据类型

  • var声明变量,变量必须要声明和赋值。

其实声明变量也可以不用var,至于为什么要用var,请看“作用域”部分。

  • JS数据类型:
    • String 字符串
    • Number 数值
    • Boolean 布尔值
    • Null 空值
    • Undefined 未定义
    • Object 对象
    • (前五个属于基本数据类型,最后一个属于引用数据类型)
  • 转义字符:
    • \" 表示 "
    • \’ 表示 ’
    • \n 表示换行
    • \t 制表符
    • \\ 表示\
  • 输出字面量和输出变量:
//输出字面量 字符串str
//alert("str");

//输出变量str
//alert(str);
  • 在JS中所有的数值都是Number类型,包括整数和浮点数(小数)。

  • JS中可以表示的数字的最大值。
    Number.MAX_VALUE=1.7976931348623157e+308

  • Number.MIN_VALUE 大于0的最小值=5e-324

  • 如果使用Number表示的数字超过了最大值,则会返回一个Infinity 表示正无穷,-Infinity 表示负无穷。

  • 使用typeof检查Infinity也会返回number

  • NaN 是一个特殊的数字,表示Not A Number,使用typeof检查一个NaN也会返回number。

Boolean 布尔值

  • 布尔值只有两个,主要用来做逻辑判断:
  • true 表示真
  • false 表示假
  • 使用typeof检查一个布尔值时,会返回boolean

其他类型:

  • Null(空值)类型的值只有一个,就是null。null这个值专门用来表示一个为空的对象。

  • 使用typeof检查一个null值时,会返回object。

  • Undefined(未定义)类型的值只有一个,就undefind。当声明一个变量,但是并不给变量赋值时,它的值就是undefined。

  • 使用typeof检查一个undefined时也会返回undefined

数据类型转换

将其他的数据类型转换为String

  • 方式一: 调用被转换数据类型的toString()方法。
  • 该方法不会影响到原变量,它会将转换的结果返回
  • 但是注意:null和undefined这两个值没有toString()方法,如果调用他们的方法,会报错。

调用xxx的yyy()方法,就是xxx.yyy()。

  • 方式二:调用String()函数,并将被转换的数据作为参数传递给函数。
  • 使用String()函数做强制类型转换时,对于Number和Boolean实际上就是调用的toString()方法。但是对于null和undefined,就不会调用toString()方法,它会将 null 直接转换为 “null”,将 undefined 直接转换为 “undefined”。

将其他的数据类型转换为Number

  • 转换方式一:使用Number()函数

  • 字符串 --> 数字
    1.如果是纯数字的字符串,则直接将其转换为数字。
    2.如果字符串中有非数字的内容,则转换为NaN。
    3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为0。

  • 布尔 --> 数字
    true 转成 1
    false 转成 0

  • null --> 数字 0

  • undefined --> 数字 NaN

  • 转换方式二:专门用来对付字符串

  • parseInt() 把一个字符串转换为一个整数。

  • parseFloat() 把一个字符串转换为一个浮点数。

  • 备注:
    parseInt遇到非数字停止,如果一开始的字符非数字,则转换为NaN。parseFloat可以遇到一个小数点。
    如果对非String使用parseInt()或parseFloat(),它会先将其转换为String再操作。所以用这种方法,布尔会转换为NaN。

转换为其它进制的数字

  • 可以在parseInt()中传递一个第二个参数,来指定数字的进制:
    a = parseInt(a,10);

将其他的数据类型转换为Boolean

  • 调用Boolean()函数来将其他类型转换为布尔值。

  • 数字 —> 布尔
    除了0和NaN,其余的都是true。

  • 字符串 —> 布尔
    除了空串,其余的都是true。

  • null和undefined都会转换为false。

  • 对象也会转换为true。

11.26

运算符

算数运算符

  • 当对非Number类型的值进行运算时,会将这些值转换为Number再运算。

  • 任何值和NaN做运算都得NaN。

  • + 可以对两个值进行加法运算,并将结果返回。
    如果对两个字符串进行加法运算,则会做拼串
    会将两个字符串拼接为一个字符串,并返回。

  • '+'两侧只要有一侧是字符串,另一侧的数字则会自动转换成字符串,因为其中存在隐式转换

  • - 可以对数字进行符号的取反。

逻辑运算符

  • 符号和C中相同,非 在下方↓
  • JS中的“与”属于短路的与,如果第一个值为false,则不会看第二个值。
  • JS中的“或”属于短路的或,如果第一个值为true,则不会检查第二个值。

&& || 非布尔值的情况

  • 对于非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且返回原值。

  • 与运算:

    • 如果第一个值为true,则返回第二个值。
      (两个值都为true,也返回第二个值,即靠后的true)
    • 如果第一个值为false,则返回第一个值。
      (两个值都为flase,也返回第一个值,即靠前的false)
    •   And:true后false前。
      
  • 或运算

    • 如果第一个值为true,则直接返回第一个值。
      (两个值都为true,也返回第一个值,即靠前的true)
    • 如果第一个值为false,则返回第二个值。
      (两个值都为flase,也返回第一个值,即靠后的false)
    •   Or:true前false后。
      

关系运算符

  • 非数值的情况
  • 对于非数值进行比较时,会将其转换为数字再比较。
  • 如果符号两侧的值都是字符串时,不会将其转换为数字进行比较,而会分别比较字符串中字符的Unicode编码。比较字符编码时是一位一位进行比较。如果两位一样,则比较下一位,所以借用它来对英文进行排序
    比如console.log(“abcd”>“abcc”),会返回true。
    而console.log(“abc”>“abd”),会返回flase。
  • 比较中文没有意义。
  • 任何值和NaN做任何比较都是false。

注意:在比较两个字符串型的数字时,一定要转型

相等运算符

  • 当使用==来比较两个值时,如果值的类型不同,则会自动进行类型转换,将其转换为相同的类型,然后再比较。使用!=来比较时,也存在类型转换。

=== (全等

  • 用来判断两个值是否全等,它和相等类似,不同的是它不会做自动的类型转换,如果两个值的类型不同,直接返回false。

!==(不全等

  • 用来判断两个值是否不全等,和不等类似,不同的是它不会做自动的类型转换,如果两个值的类型不同,直接返回true。

其它:

  • undefined 衍生自 null,所以这两个值做相等判断时,会返回true。
  • NaN不和任何值相等,包括它本身。
  • 可以通过 isNaN() 函数来判断一个值是否是NaN,如果该值是NaN则返回true,否则返回false。

条件运算符

条件运算符也叫三元运算符:

  • 语法:条件表达式?语句1:语句2;
  • 执行的流程:
    • 条件运算符在执行时,首先对条件表达式进行求值,如果该值为true,则执行语句1,并返回执行结果。
    • 如果该值为false,则执行语句2,并返回执行结果。
    • 如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后在运算。

隐式类型转换

任何值和字符串相加都会转换为字符串,并做拼串操作。

  • 我们可以利用这一特点,来将一个任意的数据类型转换为String。
  • 我们只需要为任意的数据类型 + 一个 “” 即可将其转换为String。
  • 隐式的类型转换,由浏览器自动完成,实际上它也是调用String()函数。

任何值做- * /运算时都会自动转换为Number。

  • 可以通过为一个值 -0 *1 /1来将其转换为Number。
  • 原理和Number()函数一样。

如果对非布尔值进行元素,则会将其转换为布尔值,然后再取反。

  • 所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值。
  • 可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样。

编码

  • 在字符串中使用转义字符输入Unicode编码:\u四位编码(编码为16进制
    console.log("\u2620");

  • 在网页中使用Unicode编码:&#编码(编码为10进制

      <h1 style="font-size: 200px;">&#9760;</h1>
      <h1 style="font-size: 200px;">&#9856;</h1>
    

(用win10自带计算器转换进制)

11.27

代码块

  • 在JS中可以使用{}来为语句进行分组,同一个{}中的语句称作是一组语句。
  • 一个{}中的语句我们也称为叫一个代码块。
  • JS中的代码块,只具有分组的的作用,没有其他的用途。代码块内容的内容,在外部是完全可见的。

输入

  • 使用prompt()函数:
    如var money = prompt(“请输入你的财富(万):”)

条件分支语句switch

比C语言多了 default。

num = "hello";
		
		switch(num){
			case 1:
				console.log("壹");
				//使用break可以来退出switch语句
				break;
			case 2:
				console.log("贰");
				break;
			case 3:
				console.log("叁");
				break;
			default:
				console.log("非法数字~~");
				break;
		}

for循环

练习——九九乘法表

要点:在document.write中加入html标签< span>;注意拼串的用法。

for(var i=1 ; i<=9 ; i++ ){
	//创建一个内层循环来控制图形的宽度
	for(var j=1 ; j<=i ; j++){
		document.write("<span>"+j+"*"+i+"="+i*j+"</span>");
		/*注意span和拼串*/
	}
	
	//输出一个换行
	document.write("<br />");
}
			

练习——素数(+计时器)

console.time("test");
//console.time("计时器的名字")可以用来开启一个计时器
//它需要一个字符串作为参数,这个字符串将会作为计时器的标识			
	for(var i=2 ; i<=1000 ; i++){
		var flag = true;
		for(var j=2 ; j<=Math.sqrt(i) ; j++){
			if(i%j == 0){
				flag = false;
				break;
			}
		}
		if(flag){
			console.log(i);
		}
	}
	//终止计时器
	//console.timeEnd()用来停止一个计时器,需要一个计时器的名字作为参数
	console.timeEnd("test");

备注:Hbuilder中无法查看运行时间,打开Chrome浏览器的控制台,会在最下方输出运行时间(ms)。

对象

如果使用基本数据类型的数据,创建的变量独立,不能成为一个整体。

对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。

对象的分类

  • 1.内建对象
    由ES标准中定义的对象,在任何的ES的实现中都可以使用。
    比如:Math String Number Boolean Function Object…
  • 2.宿主对象
    由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
    比如 BOM DOM(console和document……)
  • 3.自定义对象
    由开发人员自己创建的对象。

创建对象/添加/修改/删除属性

var 对象名 = new Object();
对象名可以随意。

  • 在对象中保存的值称为属性。

向对象添加属性:
语法:对象.属性名 = 属性值

var obj = new Object();
//向obj中添加一个name属性
obj.name = "孙悟空";
//向obj中添加一个gender属性
obj.gender = "男";
//向obj中添加一个age属性
obj.age = 18;
  • 读取整个对象:console.log(对象名);
    在Hbuilder的控制台中看不到对象中的内容,要打开浏览器。
  • 读取对象中的属性:
    语法:console.log(对象.属性名);
    如果读取对象中没有的属性,不会报错而是会返回undefined。
console.log(obj.gender);
console.log(obj.hello);
  • 修改对象的属性值:
    语法:对象.属性名 = 新值
obj.name = "Tom";
delete obj.name;
  • 删除对象的属性:
    语法:delete 对象.属性名 ↑

11.28

  • 如果要使用特殊的属性名(比如"var"),不能采用.的方式来操作,需要使用另一种方式:语法:对象[“属性名”] = 属性值,读取时也需要采用这种方式。
  • 使用[]这种形式去操作属性,更加灵活,在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性。
	obj["var"] = 233;
	obj["nihao"] = "你好";
	var n = "nihao";
	console.log(obj["var"]);
	console.log(obj[n]);

属性值

JS对象的属性值,可以是任意的数据类型,甚至也可以是一个对象。

	//属性可以是布尔、null、undefined
	obj.test = true;
	obj.test = null;
	obj.test = undefined;
	
	//创建一个对象
	var obj2 = new Object();
	obj2.name = "猪八戒";
	
	//将obj2设置为obj的属性
	obj.test = obj2;
	
	console.log(obj.test.name);

in运算符

通过in运算符可以检查一个对象中是否含有指定的属性,如果有则返回true,没有则返回false。

  • 语法:“属性名” in 对象
console.log("name" in obj);
//控制台显示"true"

基本数据类型和引用数据类型

  • 基本数据类型:String Number Boolean Null Undefined
  • 引用数据类型:Object
  • JS中的变量都是保存到栈内存中的,基本数据类型的值直接在栈内存中存储,值与值之间是独立存在,修改一个变量不会影响其他的变量。
    在这里插入图片描述

b的值复制a的,a再自增。

  • 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响。
    在这里插入图片描述

由于obj2=obj,obj2的值直接复制obj1的,而obj1的值又是地址,所以obj2和obj1是一个地址,指向堆内存中相同的区域。

但是如果把一个对象的值变为null时,相当于它自己主动断开了连接,并不会影响另一个对象。
在这里插入图片描述

  • 当比较两个基本数据类型的值时,就是比较值。
  • 而比较两个引用数据类型时,它是比较的对象的内存地址,如果两个对象是一模一样的,但是地址不同,它也会返回false。

对象字面量

  • 使用对象字面量,可以在创建对象时,直接指定对象中的属性。

(类似数组)

  • 语法:{属性名:属性值,属性名:属性值…}
  • 对象字面量的属性名可以加引号也可以不加,建议不加,如果要使用一些特殊的名字,则必须加引号。
  • 属性名和属性值是一组一组的名值对结构,名和值之间使用:连接,多个名值对之间使用 , 隔开。
var obj = {};
console.log(typeof obj);
obj.name = "孙悟空";

var obj2 = {

name:"猪八戒",
age:13,
gender:"男",
test:{name:"沙僧"}
};

console.log(obj2.test);

枚举对象中的属性

枚举对象中的属性:使用for … in 语句

  • 语法:
    for(var 变量 in 对象){
    }

  • for…in语句 对象中有几个属性,循环体就会执行几次。每次执行时,会将对象中的一个属性的名字赋值给变量。

var obj = {
	name:"孙悟空",
	age:18,
	gender:"男",
	address:"花果山"
};

for(var n in obj){
	console.log("属性名:"+n);
	console.log("属性值:"+obj[n]);
}
//属性名为冒号前的部分,属性值为冒号后的部分。

函数

函数 function:

  • 函数也是一个对象。
  • 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
  • 函数中可以保存一些代码在需要的时候调用。
  • 使用typeof检查一个函数对象时,会返回function。

11.30

创建函数

  • 创建一个函数对象:
    可以将要封装的代码以字符串的形式传递给构造函数。
  • 调用函数 语法:函数对象()
var fun = new Function("console.log('Hello 这是我的第一个函数');");
fun();//调用
  • 封装到函数中的代码不会立即执行,会在函数调用的时候执行。

  • 当调用函数时,函数中封装的代码会按照顺序执行。

  • 使用函数声明来创建一个函数

    • 语法:
      function 函数名([形参1,形参2…形参N]){
          语句…
      }
function sum(a,b){
	console.log("a = "+a);
	console.log("b = "+b);
	console.log(a+b);
}
  • 使用 函数表达式 来创建一个函数
    • 语法:
      var 函数名 = function([形参1,形参2…形参N]){
          语句…
      }
var fun3 = function(){
	console.log("我是匿名函数中封装的代码");
};

fun3();

强调形参

function fun2(){
	console.log("这是我的第二个函数~~~");
	alert("哈哈哈哈哈");
	document.write("~~~~(>_<)~~~~");

console.log(fun2);//可以在控制台输出函数内的所有内容
fun2();//调用函数
}
  • 调用函数时解析器不会检查实参的类型,所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查。
  • 函数的实参可以是任意的数据类型

比如上方的sum函数,如果一个参数为数字,一个为字符串,就会输出“NaN”。

  • 调用函数时,解析器也不会检查实参的数量,多余实参不会被赋值。如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined。

返回值

可以使用 return 来设置函数的返回值

  • 语法:return 值
  • return后的值将会会作为函数的执行结果返回,可以定义一个变量,来接收该结果。
  • 在函数中return后的语句都不会执行。如果return语句后不跟任何值就相当于返回一个undefined;如果函数中不写return,则也会返回undefined。
  • return后可以跟任意类型的值。
  • 函数遇到return就结束了。
function sum(a , b , c){
	var d = a + b + c;	
	return d;
	//return undefined;	
	
//调用函数
//变量result的值就是函数的执行结果
//函数返回什么result的值就是什么
var result = sum(4,7,8);
console.log("result = "+result);			
}

返回值可以是任意的数据类型,可以是一个对象,也可以是一个函数。

  • 返回对象:
function fun2(){
	//返回一个对象
	return {name:"沙和尚"};
	//这种写法相当于 var obj={name:"沙和尚"}; return obj;
}

var a = fun2();

console.log("a = "+a);//控制台输出整个对象
console.log(a.name);//控制台输出“沙和尚”
  • 返回函数:
function fun3(){
	//在函数内部再声明一个函数
	function fun4(){
		alert("我是fun4");
	}
	
	//将fun4函数对象作为返回值返回
	return fun4;
}
a = fun3();//此时a是fun4对象
a();//相当于调用fun4函数

//上方两行代码,作用相当于fun3()()

小练习:判断奇偶

function isEven(num){
return num % 2 == 0;
//该式子有一个返回值,是偶数返回true,不是返回false。
//如果不加== 0,可以返回0和1,但不是布尔。
}
var result = isEven(15);
console.log("result = "+result)

将参数封装到对象中

实参可以是任意的数据类型,也可以是一个对象。当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递。

function sayHello(o){
	//console.log("o = "+o);
	console.log("我是"+o.name+",今年我"+o.age+"岁了,"+"我是一个"+o.gender+"人"+",我住在"+o.address);
}

//创建一个对象
var obj = {
	name:"孙悟空",
	age:18,
	address:"花果山",
	gender:"男"
};
sayHello(obj);

函数作实参

实参也可以是一个函数。

function fun(a){
	console.log("a = "+a);
}
fun(sayHello);

会把函数sayHello的内容输出到控制台。

开发常用,将匿名函数作为实参传递给函数。

function fun(a){
	a(obj);
}
fun(sayHello);

相当于sayHello(obj); 和上方孙悟空的例子是同理的。



调用函数/函数对象:

fun()

  • 调用函数,相当于使用的函数的返回值。
    (相当于冰淇淋机做的冰淇淋)

fun

  • 函数对象,相当于直接使用函数对象。
    (相当于冰淇淋机本身)

立即执行函数(IIFE)

全称: Immediately-Invoked Function Expression

  • 函数定义完,立即被调用,这种函数叫做立即执行函数。
  • 立即执行函数往往只会执行一次
    (function(){
        alert(“我是一个匿名函数~~~”);
    })();
(function(a,b){
	console.log("a = "+a);
	console.log("b = "+b);
})(123,456);
//控制台输出: a=123 b=456

作用

  • 隐藏实现
  • 不会污染外部(全局)命名空间
  • 用它来编码js模块

对象的属性可以是函数

  • 函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数时这个对象的方法。
  • 调用这个函数就说调用对象的方法(method)
  • 但是它只是名称上的区别没有其他的区别。
	//创建一个对象
	var obj = new Object();
	
	//向对象中添加属性
	obj.name = "孙悟空";
	obj.age = 18;
	
	//对象的属性值可以是任何的数据类型,也可以是个函数
	obj.sayName = function(){
		console.log(obj.name);
	};
	
	function fun(){
		console.log(obj.name);
	};
	//在控制台输出函数对象
	console.log(obj.sayName);
	//调方法(带括号)
	obj.sayName();
	//调函数
	fun();

作用域

作用域指一个变量的作用的范围。在JS中一共有两种作用域:

全局作用域

  • 直接编写在script标签中的JS代码,都在全局作用域。
  • 全局作用域在页面打开时创建,在页面关闭时销毁。
  • 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用.
  • 在全局作用域中:
    • 创建的变量都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存。
    • 全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问得到。
<script type="text/javascript">
var c = "hello";

console.log(c);
//相当于console.log(window.c);
//变量作为window对象的属性保存
//console.log作为window对象的方法保存,
//所以也可以是window.console.log(window.c);

function fun(){
	console.log("我是fun函数");
}

window.fun();
//相当于直接fun(); 
//函数作为window对象的方法保存

window.alert("hello");
//相当于直接alert("hello");

声明提前

变量的声明提前

  • 使用var关键字声明的变量,会在所有的代码执行之前被声明 (但是不会赋值),但是如果声明变量时不使用var关键字,则变量不会被声明提前。
console.log("a = "+a);

var a = 123;
//控制台输出a=undefined,因为a只是被提前声明,但是没有被赋值。
//如果删去下边的var,会报错。

函数的声明提前

  • 使用函数声明形式创建的函数 function 函数(){}。它会在所有的代码执行之前就被创建, 所以我们可以在函数声明前来调用函数。
  • 使用函数表达式创建的函数 var 函数=function(){},不会被声明提前,所以不能在声明前调用。
fun();
//函数声明,会被提前创建
function fun(){
	console.log("我是一个fun函数");
}

//函数表达式,不会被提前创建
var fun2 = function(){
	console.log("我是fun2函数");
};

fun2();

函数作用域

  • 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁。
  • 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的。
  • 在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量。在函数中要访问全局变量可以使用window对象。
  • 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用。如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域中依然没有找到,则会报错ReferenceError
var a = 10;
function fun(){
	var a = "我是fun函数中的变量a";
	var b = 20;
	
	console.log("a = "+a);
	//此处a="我是fun函数中的变量a"
	
	function fun2(){
		console.log("a = "+window.a);
		//此处调用全局变量,a=10
	}
	fun2();
}
fun();
console.log("b = "+b);
//会报错:ReferenceError

提前声明(补充):

  • 在函数作用域也有声明提前的特性。
  • 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明。
  • 函数声明也会在函数中所有的代码执行之前执行。
function fun3(){
				
	fun4();
	//先调用fun4,然后在控制台输出a(undefined)。
	console.log(a);
	
	var a = 35;
	
	function fun4(){
		alert("I'm fun4");
	}
	
}
fun3();

12.13

Debug in Chrome

  • 右键→检查
  • Sources
  • 左侧,点击数字,小蓝条表示断点
  • 添加监视:右键变量/函数,选择Add Selected text to watches(也可以右侧Watch +)
  • 点击右侧弯箭头(或F10),一步步执行。

注意刷新来清除浏览器缓存。

Hbuilder的使用

  • 如果不慎弄没了控制台和web浏览器,参考:https://jingyan.baidu.com/article/c85b7a64b9667b003aac9549.html
  • 如何更新控制台的内容:修改HTML文件,然后ctrl+s
  • ctrl+r 可以在浏览器运行该文件。

this

何为this

  • 解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象。
  • 这个对象称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象。
    1. 以函数的形式调用时,this永远都是window。
    2. 以方法的形式调用时,this就是调用方法的那个对象。
    3. 构造函数的情况(见下文)

由于在全局作用域中:
创建的变量都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存。
所以fun()是全局的方法,在控制台打印的name,也必然是全局的name。
而object.sayName是局部对象的方法,在控制台打印的name,也即为局部的name。

	function fun(){
		console.log(this.name);
		// 是
	}
	var obj = {
		name:"孙悟空",
		sayName:fun
		// sayName此时和fun是一样的
	};
	
	var obj2 = {
		name:"沙和尚",
		sayName:fun
	};
	var name = "全局的name属性";
	
	fun();
	// 以函数的形式调用,this就是window,在控制台打印“全局的name属性”
	obj.sayName();
	// 在控制台打印“孙悟空”
	obj2.sayName();
	// 在控制台打印“沙和尚”
				

this的好处

仅仅修改调用方式,就可以得到同一个变量的不同的值。

使用工厂方法创建对象

(它是下边构造函数的铺垫,有很多相似的地方)
通过该方法可以大批量地创建对象,优于使用对象字面量:

// 比如创建“造人”的对象:
	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;
	}
	var obj2 = createPerson("猪八戒",28,"男");
	var obj3 = createPerson("白骨精",16,"女");
	var obj4 = createPerson("蜘蛛精",18,"女");
	// 这样即直接创建了含有三个属性和一个方法的对象

构造函数

  • 构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。
  • 构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
// 创建函数
	function Person(name , age , gender){
		this.name = name;
		// 注意这里是写this.属性名
		this.age = age;
		this.gender = gender;
		this.sayName = function(){
			alert(this.name);
			// 关于此处的this,请看下一段文字解释——
		};
	}
	
	function Dog(){
		
	}
// 调用时,构造函数要加“new”
	var per = new Person("孙悟空",18,"男");
	var per2 = new Person("玉兔精",16,"女");
	var per3 = new Person("奔波霸",38,"男");

构造函数的执行流程:

  1. 立刻创建一个新的对象
  2. 将新建的对象设置为函数中的this(在构造函数中可以使用this来引用新建的对象)
  3. 逐行执行函数中的代码
  4. 将新建的对象作为返回值返回

this的情况

  1. 当以函数的形式调用时,this是window
  2. 当以方法的形式调用时,谁调用方法this就是谁
  3. 当以构造函数的形式调用时,this就是新创建的那个对象

instanceof

使用instanceof可以检查一个对象是否是一个类的实例。

  • 语法:对象 instanceof 构造函数
  • 如果是,则返回true,否则返回false
  • 所有的对象都是Object的后代,所以任何对象和Object做instanceof检查时都会返回true

构造函数修改

在Person构造函数中,为每一个对象都添加了一个sayName方法,目前方法是在构造函数内部创建的,也就是构造函数每执行一次就会创建一个新的sayName方法。

执行10000次就会创建10000个新的方法,而10000个方法一模一样,这样没有必要。可以使所有的对象共享同一个方法。

可以在全局定义函数,但是这样有缺陷,会污染全局作用域的命名空间,而且定义在全局作用域中也很不安全。

有好的解决方案,请接着往下看。

原型对象

原型 prototype

  • 创建的每一个函数,解析器都会向函数中添加一个属性prototype。这个属性对应着一个对象,这个对象就是我们所谓的原型对象。
  • 如果函数作为普通函数调用prototype没有任何作用。
  • 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__来访问该属性。
  • 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
  • 当访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。
  • 以后创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。

函数对象,实例,以及原型对象之间的关系:

	function MyClass(){
		
	}
	// 添加原型对象并不在函数内,而是在花括号外,用.prototype添加
	// 原型对象就像一个“公共区域”,但又
	
	//向MyClass的原型中添加属性a
	MyClass.prototype.a = 123;
	
	//向MyClass的原型中添加一个方法
	MyClass.prototype.sayHello = function(){
		alert("hello");
	};
	
	var mc = new MyClass();
	var mc2 = new MyClass();
	// 二者都会在屏幕上弹窗hello
	mc.a = "我是mc中的a";
	console.log(mc.a);
	// 可以在对象自身内找到,在控制台打印“我是mc中的a”
	console.log(mc2.a);
	// 无法在对象自身内找到,去原型对象中找,找到123

hasOwnProperty

  • 使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true

  • 可以使用对象的hasOwnProperty()来**检查对象自身中是否含有该属性。**使用该方法只有当对象自身中含有属性时,才会返回true

原型链

补充刚才的图:

之前的原型对象,还存在原型对象。

  • 原型对象也是对象,所以它也有原型,当我们使用一个对象的属性或方法时,会现在自身中寻找,自身中如果有,则直接使用
  • 如果没有则去原型对象中寻找,如果原型对象中有,则使用
  • 如果没有则去原型的原型中寻找,直到找到Object对象的原型
  • Object对象的原型没有原型(有__proto__属性,对应的值是null),如果在Object原型中依然没有找到,则返回undefined
	function MyClass(){
		
	}
	var mc = new MyClass();
	console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));
	//在mc的原型即MyClass中寻找hasOwnProperty方法。由于没有该方法,返回false。
	console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
	//在mc原型的原型(即Object对象)中寻找hasOwnProperty方法,返回true。
	console.log(mc.__proto__.__proto__.__proto__);
	//由于Object对象的原型是null,如果此时使用hasOwnProperty方法,会报错。

toString 补充

直接在页面中打印一个对象时,实际上是输出的对象的toString()方法的返回值。如果希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法。

[object Object]是object对象里的toString方法,现在需要给对象的原型对象添加该方法,便可覆盖Object对象里的方法。

	function Person(name , age , gender){
		this.name = name;
		this.age = age;
		this.gender = gender;
	}
	
	//修改Person原型的toString
	Person.prototype.toString = function(){
		return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
	};
	
	
	//创建一个Person实例
	var per = new Person("孙悟空",18,"男");
	var per2 = new Person("猪八戒",28,"男");
		
	console.log(per2);
	console.log(per);
			

Hbuilder控制台内运行结果:
在这里插入图片描述

12.16

垃圾回收(GC)

程序运行过程中会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢,所以需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾。

  • 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,必须进行清理。
  • 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,不需要也不能进行垃圾回收的操作。
  • 需要做的只是要将不再使用的对象设置null即可。

数组(Array)

  • 数组也是一个对象,它和普通对象功能类似,也是用来存储一些值的。
  • 不同的是普通对象是使用字符串作为属性名。而数组时使用数字来作为索引(从0开始的整数)操作元素。
  • 数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据。

创建数组对象、添加/读取元素

创建数组对象:

  • 语法:var 数组名 = new Array();
    向数组中添加元素:
  • 语法:数组[索引] = 值

读取数组中的元素:

  • 语法:console.log(数组[索引]) (可以不用console.log,纯粹为了演示)
  • 如果读取不存在的索引,不会报错而是返回undefined

读取整个数组:

  • 语法:console.log(数组名)

length属性

获取数组的长度(元素的个数)

  • 语法:数组.length
  • 对于连续的数组,使用length可以获取到数组的长度(可借助console.log)
  • 对于非连续的数组,使用length会获取到数组的最大的索引+1,尽量不要创建非连续的数组

修改数组的长度

  • 语法:数组名.length = 某个数
    例如: arr.length = 10
  • 如果修改的length大于原长度,则多出部分会空出来
  • 如果修改的length小于原长度,则多出的元素会被删除

向数组的最后一个位置添加元素

  • 语法:数组[数组.length] = 值
    例如:
    arr[arr.length] = 70;
    arr[arr.length] = 80;
    arr[arr.length] = 90;

数组字面量

使用字面量来创建数组:

  • 语法:[ ]
    var arr = [ ];
  • 使用字面量创建数组时,可以在创建时就指定数组中的元素
    var arr = [1,2,3,4,5,10];
  • 使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作文构造函数的参数传递
    var arr2 = new Array(10,20,30);

但是使用字面量和构造函数创建数组时有区别:

	//创建一个数组数组中只有一个元素10
	arr = [10];
	
	//创建一个长度为10的数组
	arr2 = new Array(10);

数组中的元素可以是任意的数据类型:

  • arr = [“hello”,1,true,null,undefined];

  • 可以是对象
    var obj = {name:“孙悟空”};
    arr[arr.length] = obj;
    arr = [{name:“孙悟空”},{name:“沙和尚”},{name:“猪八戒”}];

  • 可以是一个函数(函数也是对象)
    arr = [function(){alert(1)},function(){alert(2)}];

  • 数组中也可以放数组,如下这种数组称为二维数组
    arr = [[1,2,3],[3,4,5],[5,6,7]];
    console.log(arr[1]);

常用数组方法

点击此处进入w3school,查看更多方法

push()

该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度

  • 可以将要添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组的末尾
  • 该方法会将数组新的长度作为返回值返回
	var arr = ["孙悟空","猪八戒","沙和尚"];
	var result = arr.push("唐僧","蜘蛛精","白骨精","玉兔精");
	console.log(arr);
	// "孙悟空,猪八戒,沙和尚,唐僧,蜘蛛精,白骨精,玉兔精"
	console.log("result = "+result);
	// result = 7
其它
  • pop():该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
  • unshift():向数组开头添加一个或多个元素,并返回新的数组长度
    向前边插入元素以后,其他的元素索引会依次调整
  • shift():可以删除数组的第一个元素,并将被删除的元素作为返回值返回

12.17

slice和splice(推荐)

slice()可以用来从数组提取指定元素
  • 该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回

  • 参数:
    1.截取开始的位置的索引,包含开始索引
    2.截取结束的位置的索引,不包含结束索引

  • 第二个参数可以省略不写,此时会截取从开始索引往后的所有元素

  • 索引可以传递一个负值,如果传递一个负值,则从后往前计算

	var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
	var result = arr.slice(1,4);
	// 此时result == "猪八戒","沙和尚","唐僧"
	result = arr.slice(3);
	// result == "唐僧","白骨精"
	result = arr.slice(1,-2);
	// result == "猪八戒","沙和尚"
splice 删除指定元素/替换/增加 一网打尽

使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回

  • 参数:
    第一个,表示开始位置的索引
    第二个,表示删除的数量
    第三个及以后,可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
	arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
	var result = arr.splice(3,0,"牛魔王","铁扇公主","红孩儿");
	// result == "孙悟空","牛魔王","铁扇公主","红孩儿","猪八戒","沙和尚","唐僧","白骨精"
	// 如果删除的元素数量等于新增的元素数量,可以看作发挥了替换功能
	// 如果删除元素数量为0,可以看作发挥了增加元素的功能
	// 我认为splice是一个万能的方法
	console.log(arr);

concat / join / reverse / sort

concat()可以连接两个或多个数组,并将新的数组返回,该方法不会对原数组产生影响
	var arr = ["孙悟空","猪八戒","沙和尚"];
	var arr2 = ["白骨精","玉兔精","蜘蛛精"];
	var arr3 = ["二郎神","太上老君","玉皇大帝"];
	var result = arr.concat(arr2,arr3,"牛魔王","铁扇公主");
	console.log(result);
	//"孙悟空,猪八戒,沙和尚,白骨精,玉兔精,蜘蛛精,二郎神,太上老君,玉皇大帝,牛魔王,铁扇公主"
join()可以将数组转换为一个字符串
  • 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
  • 在( )中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符,如果不指定连接符,则默认使用,作为连接符
	arr = ["孙悟空","猪八戒","沙和尚","唐僧"];
	result = arr.join("@-@");
	console.log(result);
	// "孙悟空@-@猪八戒@-@沙和尚@-@唐僧"
reverse()方法用来反转数组

该方法会直接修改原数组

sort()可以用来对数组中的元素进行排序

该方法会影响原数组,默认会按照Unicode编码进行排序

  • 即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,所以对数字进排序时,可能会得到错误的结果

可以自己来指定排序的规则

  • 可以在sort()添加一个回调函数,来指定排序规则,浏览器会根据回调函数的返回值来决定元素的顺序,如果返回一个大于0的值,则元素会交换位置,返回一个小于等于0的值,则元素位置不变
  • 如果需要升序排列,则返回 a-b,如果需要降序排列,则返回b-a
arr = [5,4,2,19,3,11,6,8,7];
arr.sort(function(a,b){
// 降序排列
return b - a;				
});
// 注意回调函数写在sort的括号内,所以最后是}),不要漏掉圆括号
// 排序结果为"19,11,8,7,6,5,4,3,2"

12.16

遍历数组

for循环即可,同C:

	var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
	for(var i=0 ; i<arr.length ; i++){
		console.log(arr[i]);
	}

提取元素练习

将perArr中的满18岁的Person提取出来,然后封装到一个新的数组中并返回。


	function Person(name , age , gender){
		this.name = name;
		this.age = age;
	}
	//修改Person原型的toString
	Person.prototype.toString = function(){
		return "Person[name="+this.name+",age="+this.age+"]";
	};
	//创建一个Person对象
	var per = new Person("孙悟空",18);
	var per2 = new Person("猪八戒",28);
	var per3 = new Person("红孩儿",8);
	var per4 = new Person("蜘蛛精",16);
	var per5 = new Person("二郎神",38);
	/*
	 * 将这些person对象放入到一个数组中
	 */
	var perArr = [per,per2,per3,per4,per5];
	/*
	 * 创建一个函数,可以将perArr中的满18岁的Person提取出来,
	 * 	然后封装到一个新的数组中并返回
	 * arr
	 * 	形参,要提取信息的数组
	 */
	function getAdult(arr){
		//创建一个新的数组
		var newArr = [];
		//遍历arr,获取arr中Person对象
		for(var i=0 ; i<arr.length ; i++){
			var p = arr[i];
			//判断Person对象的age是否大于等于18
			if(p.age >= 18){
				//如果大于等于18,则将这个对象添加到newArr中
				//将对象放入到新数组中
				newArr.push(p);
			}
		}
		//将新的数组返回
		return newArr;
		
	}
	
	var result = getAdult(perArr);
	
	console.log(result);

12.17

foreach

  • JS中还提供了一个方法,用来遍历数组,即forEach()
  • 这个方法只支持IE8以上的浏览器E8及以下的浏览器均不支持该方法,所以如果需要兼容IE8,则不要使用forEach,还是使用for循环来遍历。

forEach()方法需要一个函数作为参数

  • 像这种函数,由我们创建但是不由我们调用的,称为回调函数
  • 数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素,以实参的形式传递进来,我们可以来定义形参,来读取这些内容

浏览器会在回调函数中传递三个参数:

  • 第一个参数,是当前正在遍历的元素
  • 第二个参数,是当前正在遍历的元素的索引
  • 第三个参数,是正在遍历的数组
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
arr.forEach(function(value , index , obj){
	console.log(value);
	/*将数组内所有元素输出在控制台,每个元素占据一行*/
});

数组去重练习

j自减这一步非常重要,而且需要写在if内部,否则会陷入死循环。

	//创建一个数组
	var arr = [1,2,3,2,2,1,3,4,2,5];
	
	//去除数组中重复的数字
	//获取数组中的每一个元素
	for(var i=0 ; i<arr.length ; i++){
		//console.log(arr[i]);
		/*获取当前元素后的所有元素*/
		for(var j=i+1 ; j<arr.length ; j++){
			//console.log("---->"+arr[j]);
			//判断两个元素的值是否相等
			if(arr[i] == arr[j]){
				//如果相等则证明出现了重复的元素,则删除j对应的元素
				arr.splice(j,1);
				//当删除了当前j所在的元素以后,后边的元素会自动补位
				//此时将不会再比较这个元素,需要在比较一次j所在位置的元素
				//使j自减
				j--;
			}
		}
	}
	
	console.log(arr);
	

函数的方法call&apply(this补充)

call()和apply()

  • 这两个方法都是函数对象的方法,需要通过函数对象来调用
  • 当对函数调用call()和apply()都会调用函数执行
  • 在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
  • call()方法可以将实参在对象之后依次传递
  • apply()方法需要将实参封装到一个数组中统一传递

this的情况:

  • 1.以函数形式调用时,this永远都是window
  • 2.以方法的形式调用时,this是调用方法的对象
  • 3.以构造函数的形式调用时,this是新创建的那个对象
  • 4.使用call和apply调用时,this是指定的那个对象
	function fun(a,b) {
			console.log("a = "+a);
			console.log("b = "+b);
			console.log(this.name);
		}
		
	var obj = {
		name: "obj",
		sayName:function(){
			alert(this.name);
		}
	};
	var obj2 = {
		name: "obj2"
	};
	fun.call(obj,2,3);
	//相当于fun.apply(obj,[2,3]);
	//传入obj对象,因此此时this为obj,this.name=obj
	//此时在控制台输出:a=2,b=3,obj
	fun.call(obj2,2,3);
	//此时this为obj2,在控制台输出:a=2,b=3,obj2

12.18

arguments

在调用函数时,浏览器每次都会传递进两个隐含的参数:

  • 函数的上下文对象 this
  • 封装实参的对象 arguments

arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度

  • 在调用函数时,传递的实参都会在arguments中保存
  • arguments.length可以用来获取实参的数量
  • 即使不定义形参,也可以通过arguments来使用实参,但比较麻烦
  • arguments[0] 表示第一个实参,arguments[1] 表示第二个实参 …
  • 它有一个属性叫做callee,这个属性对应当前正在执行的函数的对象
	function fun(a,b){
		console.log(arguments instanceof Array);
		//false,因为arguments不是数组
		console.log(Array.isArray(arguments));
		//false,同上
		console.log(arguments[1]);
		//"hello"
		console.log(arguments.length);
		//2
		console.log(arguments.callee == fun);
		//true,arguments.callee就是当前函数的对象
	}
	
	fun("hello",true);

Date对象

创建

创建一个Date对象

  • 如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
    var d = new Date();

  • 创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数
    日期的格式 月份/日/年 时:分:秒
    var d2 = new Date(“2/18/2011 11:10:30”);

方法

  • getDate() 获取当前日期对象是几日
  • getDay() 获取当前日期对象时周几,会返回一个0-6的值,0 表示周日,1表示周一
  • getMonth() 会返回一个0-11的值,0 表示1月,11 表示12月
  • getFullYear() 获取当前日期对象的年份
  • getTime() 获取当前日期对象的时间戳
    时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒,到当前日期所花费的毫秒数(1秒 = 1000毫秒)计算机底层在保存时间时使用都是时间戳

    它和时区有关,如果在中国的电脑上,默认为东八区。

利用时间戳测试代码执行性能

	var start = Date.now();			
	for(var i=0 ; i<100 ; i++){
		console.log(i);
	}
	var end = Date.now();
	console.log("执行了:"+(end - start)+"毫秒");

Math

Math和其他的对象不同,它不是一个构造函数,它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法

它的属性和方法都可以在JS手册中查找,此处列出一些常用方法:

  • abs()可以用来计算一个数的绝对值
    //console.log(Math.abs(-1));
  • Math.ceil() 可以对一个数进行向上取整,小数位只有有值就自动进1
  • Math.floor() 可以对一个数进行向下取整,小数部分会被舍掉
  • Math.round() 可以对一个数进行四舍五入取整
  • max() 可以获取多个数中的最大值
  • min() 可以获取多个数中的最小值
  • Math.pow(x,y) 返回x的y次幂
  • Math.sqrt() 用于对一个数进行开方运算

任意范围的随机数

Math.random() 可以用来生成一个0-1之间的随机数

生成一个x-y之间的随机数

  • Math.ceil(Math.random()*(y-x)+x-1)
  • 或 Math.floor(Math.random()*(y-x+1)+x)

根据b站弹幕所言,使用round会影响概率,不能使用。

包装类

JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象

  • String() 可以将基本数据类型字符串转换为String对象
  • Number() 可以将基本数据类型的数字转换为Number对象
  • Boolean() 可以将基本数据类型的布尔值转换为Boolean对象
  • 但是注意:我们在实际应用中不会使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果

方法和属性之能添加给对象,不能添加给基本数据类型,对一些基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法,调用完以后,再将其转换为基本数据类型

	var s = 123;
	//s为基本数据类型
	s = s.toString();
	//s是不能添加toString方法的,故浏览器先将它临时转换为对象
	s.hello = "你好";
	//s是不能添加hello属性的,故浏览器先将它临时转换为对象,之后又立刻删除该对象
	console.log(s.hello);
	//之前的对象已被删除,现在浏览器再次将s转换为对象,此时a属性未定义,所以控制台打印"undefined"

字符串的相关方法

由于字符串都是以数组的形式存储的,每个字符为一个元素,所以这些方法会和之前数组的方法有高度重复性。

注:此处的方法都是不改变原字符串的,也就是都需要var result…然后打印result,并不在括号内写原字符串,括号内可以为空,有时写一些参数。

  • length属性(略)

  • charAt( ):可以根据索引返回字符串中指定位置的字符

	str = "嘿Hello Atguigu";
	var result = str.charAt(3);
	console.log(result);
	//结果为l
	console.log(str[3]);
	//结果为l
  • charCodeAt( ):获取指定位置字符的字符编码(Unicode编码)
    result = str.charCodeAt(0);

  • String.formCharCode( ):可以根据字符编码去获取字符
    result = String.fromCharCode(0x2692);

  • concat( ):可以用来连接两个或多个字符串,作用和+一样
    result = str.concat(“你好”,“再见”);
    结果为:嘿Hello Atguigu你好再见

  • indexof( ) 该方法可以检索一个字符串中是否含有指定内容,如果字符串中含有该内容,则会返回其第一次出现的索引;如果没有找到指定的内容,则返回-1。可以指定第二个参数,指定开始查找的位置。

  • lastIndexOf():该方法的用法和indexOf()一样,但它从前往后找,而lastIndexOf是从后往前找,它也可以指定开始查找的位置。

	str = "hello hatguigu";
	
	result = str.indexOf("h",1);
	//从索引1开始往后找,结果为6
	result = str.lastIndexOf("h",7);
	//从索引7开始往前找,结果为6
  • slice( ):可以从字符串中截取指定的内容,不会影响原字符串,而是将截取到内容返回
    参数:

    • 第一个,开始位置的索引(包括开始位置)
    • 第二个,结束位置的索引(不包括结束位置)
    • 如果省略第二个参数,则会截取到后边所有的,也可以传递一个负数作为参数,负数的话将会从后边计算。
  • substring( ):可以用来截取一个字符串,可以slice()类似(目测用处不大
    参数:

    • 第一个:开始截取位置的索引(包括开始位置)
    • 第二个:结束位置的索引(不包括结束位置)
    • 不同的是这个方法不能接受负值作为参数,如果传递了一个负值,则默认使用0,而且它还自动调整参数的位置,如果第二个参数小于第一个,则自动交换
  • substr( ):用来截取字符串(好处是可以输入截取长度,并且不像之前的splice一样影响原来的)
    参数:

    • 第一个:截取开始位置的索引
    • 第二个:截取的长度
  • split( ):可以将一个字符串拆分为一个数组
    参数:需要一个字符串作为参数,将会根据该字符串去拆分数组,如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素

	str = "abcbcdefghij";		
	result = str.split("d");
	console.log(result);
	//"abcbc,efghij"
	result = str.split("");
	console.log(result);
	//"a,b,c,b,c,d,e,f,g,h,i,j"
  • toUpperCase( ):将一个字符串转换为大写并返回
  • toLowerCase( ):将一个字符串转换为小写并返回

正则表达式

正则表达式用于定义一些字符串的规则,计算机可以根据正则表达式,来检查一个字符串是否符合规则,或者将字符串中符合规则的内容提取出来。

构造函数创建正则表达式的对象

  • 语法:var 变量 = new RegExp(“正则表达式”,“匹配模式”);
  • 在构造函数中可以传递一个匹配模式作为第二个参数,可以是
    • i 忽略大小写
    • g 全局匹配模式
  • 使用typeof检查正则对象,会返回object
  • 正则表达式var reg = new RegExp(“a”); 可以来检查一个字符串中是否含有a

test()

使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,如果符合则返回true,否则返回false。

	var reg = new RegExp("ab","i");
	console.log(reg.test("Ac"));
	//检测字符串"Ac"中有没有"ab",且忽略大小写,因为没有,打印false

12.19

使用字面量创建正则表达式

语法:var 变量 = /正则表达式/匹配模式,这种方式创建更加简单,但是如果要动态创建正则表达式,必须要用构造函数创建(p137的20分钟处)

例如:var reg = /a/i;

逻辑运算符在这里可以使用, | 表示或,[^ ] 非

创建一个正则表达式,检查一个字符串中是否有a或b:reg = /a|b|c/;

[ ]里的内容也是或的关系:

  • [ab] == a|b
  • [a-z] 任意小写字母
  • [A-Z] 任意大写字母
  • [A-z] 任意字母
  • [0-9] 任意数字

检查一个字符串中是否含有 abc 或 adc 或 aec:
reg = /a[bde]c/;

字符串和正则表达式相关的方法

split()

split()可以将一个字符串拆分为一个数组

  • 可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
  • 这个方法即使不指定全局匹配,也会全都插分
var str = "1a2b3c4d5e6f7";
var result = str.split(/[A-z]/);
/*根据任意字母来将字符串拆分*/
console.log(result);

search

search( )可以搜索字符串中是否含有指定内容

  • 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
  • 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
  • search( )只会查找第一个,即使设置全局匹配也没用
str = "hello abc hello aec afc";
result = str.search(/a[bef]c/);
/*搜索字符串中是否含有abc 或 aec 或 afc*/
console.log(result);
/*6*/

match()

match( )可以根据正则表达式,从一个字符串中将符合条件的内容提取出来

  • 默认情况下match只会找到第一个符合要求的内容,找到以后就停止检索
  • 可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
  • 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
  • match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
	str = "1a2a3a4a5e6f7A8B9C";
	result = str.match(/[a-z]/ig);
	/*提取出所有字母,存在数组内,虽然前面写的是小写,但是匹配模式中有i忽略大小写
	如果不加g,则只提取一个a*/
	console.log(result);
	/* "a,a,a,a,e,f,A,B,C" */
	

replace()

replace( )可以将字符串中指定内容替换为新的内容
参数:

  1. 被替换的内容,可以接受一个正则表达式作为参数
  2. 新的内容
    (默认只会替换第一个)
	str = "1a2a3a4a5e6f7A8B9C";
	result = str.replace(/[a-z]/gi , "");
	console.log(result);
	/* "123456789" */

量词

设置出现次数

通过量词可以设置一个内容出现的次数,量词只对它前边的一个内容起作用(注意加括号)

  • {n} 出现n次而且必须得挨着
  • {m,n} 出现m-n次
  • {m,} m次以上
  • + 至少一个,相当于{1,}
  • * 0个或1个或多个,相当于{0,},有没有都行
  • ? 0个或1个,相当于{0,1}

备注:只要一串数/字符中有完整的一段符合正则表达式,就可以为true。
比如 var reg = /a{3}/,如果是aaaa,前面三个a检查后,即便再来第四个a,仍然为true。
再比如 reg = /ab{1,3}c/,如果是ccccababcc,可以断开看cccc ababc c,中间有一段符合,所以为true。

	var reg = /a{3}/;
	// 出现3次a,并且三个a必须挨着才是true
	reg = /(ab){3}/;
	// 出现3次以上的ab,并且三个ab必须挨着才是true
	reg = /b{3}/;
	
	reg = /ab{1,3}c/;
	// 必须是前边是a,紧挨着出现1~3次b,后面连着c
	reg = /ab{3,}c/;
	// a紧挨着出现三次以上b连着c
	reg = /ab+c/;
	//a紧挨着出现至少一个b再连着c
	reg = /ab*c/;
	//a后有或无b再连着c
	reg = /ab?c/;
	//a后有0或1个b再连着c

设置出现位置

  • ^ 表示开头
  • $ 表示结尾
  • 如果在正则表达式中同时使用^ $则要求字符串必须完全符合正则表达式
	reg = /^a/; //匹配开头的a
	reg = /a$/; //匹配结尾的a
	reg = /^a$/;//字符串要求只有一个a
	console.log(reg.test("aa"));//false

检查手机号是否合法

规则:

  1. 以1开头
  2. 第二位3-9任意数字
  3. 三位以后任意数字9个
	var phoneStr = "13067890123";
	var phoneReg = /^1[3-9][0-9]{9}$/;
	console.log(phoneReg.test(phoneStr)); //true

prompt接收输入

var str = prompt(“请输入你的用户名:”);

转义字符/其他字符

在正则表达式中使用\作为转义字符
. 表示任意字符
用. 来表示.
用\ 表示\

注意:使用构造函数时,由于它的参数是一个字符串,而\是字符串中转义字符,如果要使用\则需要使用\来代替

	// 注意构造函数和字面量创建的区别: 
	var reg = /\./;	
	reg = /\\/;	
	reg = new RegExp("\\.");
	reg = new RegExp("\\\\");

其它字符:

  • \w 任意字母、数字、_
  • \W 除了字母、数字、_ (大写字母表示非 小写字母)
  • \d 任意的数字 [0-9]
  • \D 除了数字 [^0-9]
  • \s 空格
  • \S 除了空格
  • \b 单词边界
  • \B 除了单词边界
/*创建一个正则表达式检查一个字符串中是否含有单词child*/
reg = /\bchild\b/;
/*表示child必须是独立的单词,两侧不能连着其它字母或数字*/
console.log(reg.test("hello child ")); //true

删除多余空格

有时候用户在输入信息时会不小心在前面或后面多输入空格,我们去掉前后的空格,保留中间的空格,去除空格就是使用""来替换空格

	var str = "              he      llo                ";
	//去除开头的空格
	//str = str.replace(/^\s*/, "");
	//去除结尾的空格
	//str = str.replace(/\s*$/, "");
	// /^\s*|\s*$/g 匹配开头和结尾的空格,必须在最后加全局匹配g
	str = str.replace(/^\s*|\s*$/g,"");		

12.20

邮件的正则

任意字母数字下划线 .任意字母数字下划线(可有可无) @ 任意字母数字 .任意字母(2-5位) .任意字母(2-5位,可有可无)

先分段写出:
\w{3,} (.\w+)* @ [A-z0-9]+ (.[A-z]{2,5}){1,2}
再删除空格

注意中间[A-z0-9]表示任意字母和数字,最后的{1,2}表示出现一次到两次。因为最后两段的结构相同,而最后一段可有可无,故简写成这种形式。

var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;

var email = "abc.hello@163.com";

console.log(emailReg.test(email));
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值