javascript (JS组成、书写位置、基本概念、作用域、内存问题、变量)

1 JavaScript的组成和书写位置

Javascript:运行在客户端(浏览器)的脚本语言,JavaScript的解释器被称为JavaScript引擎,为浏览器的一部分,与java没有直接的关系。

Java:服务器端的编程语言。

API:Application Programming Interface,应用程序编程接口。

1.1 JavaScript的组成


  • ECMAScript核心:描述了语言的基本语法和数据类型,提供核心语言功能。主要包含语法、类型、语句、关键字、保留字、操作符、对象。
  • BOM:浏览器对象模型[Browner Object Model],提供与浏览器交互的方法和接口,通过BOM可以操作浏览器窗口。根本上只处理浏览器窗口和框架,但是针对浏览器的JS扩展也算在BOM,扩展:
    • 弹出新浏览器窗口的功能
    • 移动、缩放、关闭浏览器窗口的功能
    • 提供浏览器详细信息的navigator对象
    • 提供浏览器所加载页面的详细信息的location对象
    • 提供用户显示器分辨率详细信息的screen对象
    • 对cookie的支持
    • 向XMLHttpRequest和IE的ActiveXObject这样的自定义对象
  • DOM:文档对象模型[Document Object Model],提供访问和操作页面网页内容的方法和接口,DOM可以把HTML看做是文档树,通过DOM提供的API可以把树上的节点进行操作。
    • DOM1级,有两个模块组成:DOM核心(DOM Core)和DOM HTML。DOM HTML是在DOM核心上扩展,增加了HTML的对象和方法。
    • DOM2级,增加模块:DOM视图、DOM事件、DOM样式、DOM遍历和范围。
    • DOM3,引入了以统一方式加载和保存文档的方法,在DOM加载和保存模块中定义、新增验证文档的方法、DOM核心进行扩展,支持XML1.0规范,涉及XML Infoset、XPath、XML Base。

eg:DOM把整个页面映射为一个多层节点结构。

<html>
  <head>
    <title>
      Sample Page
    </title>
  </head>
  <body>
    <p>Hello World!</p>
  </body>
</html> 

在DOM中,页面可以通过如下分层节点图表示:

1.2 JavaScript的书写位置

在HTML页面中插入JS的主要方法,就是使用<script>元素,其中有6个属性:

  1. async:可选,异步脚本,[async或async="async"]告诉浏览器立即下载脚本,但不妨碍页面中其他操作。只对外部脚本有效。
  2. charset:可选,表示通过src属性指定的代码的字符集。
  3. defer:可选,延迟脚本,[defer="defer"]告诉脚本可以延迟到文档完全被解析和显示之后再执行[脚本将延迟到遇到</html>标签后再执行]。只对外部脚本有效。
  4. src:可选,表示包含要执行代码的外部文件。
  5. type:可选,可以看成是language的替代属性。
  6. language:废弃。

使用<script>元素方式有三种:直接在页面中嵌入JS(包含行内、嵌入样式)和包含外部JS文件。嵌入JS代码时,只须为其指定type属性。

//行内
    <input type="button" value="按钮" onclick="alert('Hello World')" />
//嵌入样式,放在<head>元素中,其中type属性可不写
    <head>
         <script type="text/javascript">
         alert('Hello World!');
         </script>
    </head>
//外部js:写在外部main.js文件中,在页面引入,src属性必写的,它指向外部JS文件的链接
  <script src="main.js"></script> 

2 基本概念

语法:

  • 区分大小写
  • 标识符:就是指变量名、函数名、属性名、函数的参数名,一般采用驼峰格式。比如firstSecond、myCar、doSomethingImportant。
  • 注释:单行注释(//)、多行注释(/*...*/)。
  • 严格模式
  • 语句:分号结尾。

2.1 变量 

变量:计算机内存中存储数据的标识符,根据变量名称可以获取到内存中存储的数据。ECMAScript的变量是松散类型的,可以用来保存任何类型的数据。

目的:使用变量可以方便的获取或者修改内存中的数据。

2.1.1 如何使用变量

定义变量: var操作符[var是一个关键字]+变量名[即一个标识符]。var操作符定义出来的变量,它的作用域属于局部变量。

//var声明变量,会保存一个特殊的值 = undefined[默认值]
//给age赋值后,age保存的数据变成10
var age;
age =10

//同时声明多个变量并赋值,message声明没有赋值会保存一个特殊的值defined。
var age = 10, name = 'zs',message; 

//var作用域定义的变量属于局部变量
function test(){
   var message001="hi"; //局部变量
    message002="hello";//全局变量,不过不推荐,很难维护
}
test()
alert(message001); //错误!原因:调用函数时,会创建该变量并为其赋值,在此变量会销毁。
alert(message002); //"hi"

2.1.2 变量的命名规则和规范

变量的命名规则和规范

规则-必须遵守的,不遵守会报错

  • 由字母、数字、下划线、$符号组成,不能以数字开头
  • 不能是关键字和保留字,例如:for、while
  • 区分大小写

规范-建议遵守的,不遵守不会报错

  • 变量名必须有意义
  • 遵守驼峰命名法,首字母小写,后面单词的首字母需要大写,例如:userName、userPasswd

案例

  1. 交换2个变量的值

 思路1:使用三方的变量进行交换

 思路2:一般适用于数字的交换

  1. 不使用临时变量,交换两个数值变量的值

2.2 数据类型

5种简单数据类型:Number、String、Boolean、Undefined、Null。

1种复杂数据类型:Object[本质上是一组无序的明值对组成的]。

6种数据类型,如何进行检测给定变量的数据类型:typepf操作符。

//typeof操作符的操作数可以是变量(message)、也可以是数值字面量,操作符返回下列字符串
"undefined":这个值未定义
"boolean":布尔值
"string":字符串
"number":数值
"object":对象或null
"function":函数

eg:
var message="some string";
alert(typeof message);    //"string"
alert(typeof(message));    //"string"
alert(typeof 95);    //"number"   

2.2.1 Number类型

1.数值字面量:数值的固定值的表示法。

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

//
1.浮点数值:数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。 //保存浮点数值需要的内存空间是保存整数值的两倍 eg: var floatNum1=1.1 var floatNum1=0.1 //极大或极小的值,用e表示法(即科学计数法)表示的浮点数值表示,e前面的数值乘以10的指数次幂。 var n = 3.125e7; //等于31250000 //浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数 var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004 console.log(0.07 * 100); // 不要判断两个浮点数是否相等 //2.数值范围   最小值:Number.MIN_VALUE,这个值为: 5e-324   最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308   无穷大[正无穷]:Infinity   无穷小[负无穷]:-Infinity //3.NaN // NaN:not a number(非数值),一个特殊的数值,返回数值的操作数未返回数值的情况,NaN 与任何值都不相等,包括他本身 // isNaN: is not a number,isNaN()函数,接受一个参数,可以是任何类型,而函数会帮我们确定这个参数是否"不是数值"。在接收一个值之后,会尝试将这个值转换为数值。 //任何不能被转换为数值的值都为true。 eg: alert(isNaN(NaN)); //true alert(isNaN(10)); //false(10是一个数值) alert(isNaN("10")); //false(可以被转换成数值10) alert(isNaN("blue")); //true(不能转换成数值) alert(isNaN(true)); //false(可以被转换成数值1)
2.数值转换,3个函数可以把非数值转换为数值:number()、parseInt()、parseFloat()。
2.1 number转换规则
  • boolean值:true和false分别被转换为1和0.
  • 数字值:简单的传入和返回.
  • null:返回0.
  • undefined:返回NaN.
  • 字符串:
    • 只包含数字(转换为十进制数值,忽略前导值)
    • 有效的浮点(转换为对应的十进制浮点数值,忽略前导值)
    • 有效的十六进制格式(0xf,转换为相同大小的十进制整数值)
    • 字符串为空(转换为0)
    • 字符串其他格式(转换为NaN)
  • 对象:调用valueOf()方法,按规则返回值,如果转换后是NaN(),调用对象toString()方法,然后再次依照前面的规则转换返回的字符串值。
//Number()函数
eg:
var num1=Number("Hello world!") //NaN var num2=Number("") //0 var num3=Number("00011") //11 var num4=Number(true) //1 //parseInt()函数,是否符合数值模式,默认找第一个非空格字符。 //第一个字符是数字字符,会往后解析,直到解析完所有后续字符或者遇到一个非数字字符 //可以识别出各种整数格式,以0x开头的数字字符,当成16进制,以0开头的数字字符,当成8进制来解析 eg: var num1=parsetInt("1234blue") //1234 var num2=parsetInt("") //NaN var num3=parsetInt("0xA") //10(十六进制) var num4=parsetInt("22.5") //22 var num5=parsetInt("070") //56(八进制),ECMAScript3认为是58(八进制),ECMAScript 5认为是0(十进制),前导的0会被认为无效 var num6=parsetInt("70") //70(10进制) var num7=parsetInt("0xf") //15(十六进制数) //指定基数会影响到转换的输出结果
eg:
var num1=parsetInt("10",2) //2(按二进制解析) var num2=parsetInt("10",8) //8(按八进制解析) var num3=parsetInt("10",10) //10 (按十进制解析) var num4=parsetInt("10",16) //16(按十六进制解析) //parseFloat()可以识别前面讨论过的所有浮点数值格式,也包括十进制整数格式
eg:
var num1=parseFloat("1234blue") //1234 var num2=parseFloat("0xA") //0,忽略前导的0 var num3=parseFloat("22.5") //22.5 var num4=parseFloat("22.34.5") //22.34,忽略后面那个点 var num5=parseFloat("09008.5") //9008.5 var num6=parseFloat("3.125e7") //31250000

2.2.2 String类型

//string类型用于表示由零或多个16位Unicode字符组成的字符序列,即字符串。可以由单引号或双引号表示.
eg:
'abc'   "abc"
//1.字符串字面量,字符串长度, length属性用来获取字符串的长度
  '程序猿','程序媛'var str = '程序猿 Hello World';
  console.log(str.length);  //输出str的长度
//2.字符串拼接,字符串拼接使用 + 连接
  console.log(11 + 11);
  console.log('hello' + ' world');
  console.log('100' + '100');
  console.log('11' + 11);
  console.log('male:' + true);
PS:
//  1. 两边只要有一个是字符串,那么+就是字符串拼接功能
//  2. 两边如果都是数字,那么就是算术功能。

//3.转换为字符串,将一个值转换为一个字符串有两种方式:toString()方法和String()方法。
eg://数值、布尔值、对象和字符串值都有toString()方法。调用toString()方法不必传递参数,调用数值的toString()方法时,可以传递一个参数:输出数值的基数。
var age=11;
var ageAsString=age.toString(); //字符串"11"
var found=true;
var foundAsString=found.toString(); //字符串"true"

//String转换函数:String(),这个函数能够将任何类型的值转换为字符串,String()函数遵循下列转换规则
toString()方法:调用,返回相应的结果
null:则返回null,无toString()方法
undefined:返回undefined,无toString()方法

eg:
var value1=10;
var value2=true;
var value3=null;
var value4;
alert(String(value1));  //"10"
alert(String(value2));  //"true"
alert(String(value3));  //"null"
alert(String(value4));  //"undefined"

2.2.3 Boolean类型

Boolean转换规则:

//转换规则对流控制语句(如if语句)自动执行相应的Boolean转换非常重要。
eg:
var message="Hello world!"
if (message){
   alert("value is true");
}

- Boolean字面量:true和false,区分大小写。
- 计算机内部存储:true为1,false为0

2.2.4 Undefined和Null

1. undefined表示已声明未赋值的变量,变量只声明的时候值默认是undefined。
2. null表示一个空,变量的值如果想为null,必须手动设置。

2.2.5 复杂数据类型

对象:一组数据和功能的集合。对象可以通过执行new操作符后要跟创建的对象类型的名称来创建。

​   Object

//创建自定义对象
var o=new Object()
Object的每个实例都具有下列属性和方法:
Constructor:保存着用于创建当前对象的函数。构造函数(constructor)就是Object().
hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。比如:hasOwnProperty("name")。
isPrototypeOf(object):用于检查传入的对象是否是另一个对象的原型。
PropertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
toLocalString():返回对象的字符串表示,该字符串与执行环境的地区对应。
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔值表示。

2.2.6 数据类型转换

字符串的颜色是黑色的,数值类型是蓝色的,布尔类型也是蓝色的,undefined和null是灰色的。

Js中的原始数据类型:number、string、boolean、null、undefined、object。

//转换成字符串类型:toString()和String()  
  var num = 5;
  console.log(num.toString());
//PS:有些值没有toString(),这个时候可以使用String()。比如:undefined和null

//拼接字符串方式,num  +  "",有字符串拼接时,默认其他字符转换成字符串,并返回字符串

//转换成数值类型:Number()
//Number()可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaN

//parseInt()  
var num1 = parseInt("12.3abc");  // 返回12,如果第一个字符是数字会解析知道遇到非数字结束
  var num2 = parseInt("abc123");   // 返回NaN,如果第一个字符不是数字或者符号就返回NaN
//parseFloat()
//parseFloat()把字符串转换成浮点数,parseFloat()和parseInt非常相似,不同之处在与parseFloat会解析第一个. 遇到第二个.或者非数字结束。如果解析的内容里只有整数,解析成整数- +,-0等运算
  var str = '500';
  console.log(+str);      // 取正
  console.log(-str);      // 取负
  console.log(str - 0); 

//转换成布尔类型:0  ''(空字符串) null undefined NaN 会转换成false  其它都会转换成true

2.3 操作符

操作符:描述了一组用于操作数据值的操作符。包含算数操作符(如加号、减号)、位操作符、关系操作符、相等操作符。适应于很多值:字符从、数字值、布尔值、对象。在操作对象时,相应的操作符通常都会调用对象的valueOf()和(或)toString()方法,以便取得可以操作的值。

2.3.1 位操作符

位操作符:按内存中表示数值的位来操作数值,按64位格式存储。对于有符号的整数,32位中的前31位用于表示整数的值,第32位用于表示数值的符号(0为正,1位负)。

数值18的二进制:

//按位非(NOT),按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。
eg1:
var num1=25;
var num2=~num1;
alert(num2);  //-26

//按位与(AND),按位与操作符由一个和号字符(&)表示,它有两个操作符数。从本质上将,按位与操作就是将两个数值的每一位对齐,然后根据下表中的规则,对相同位置上的两个数执行AND操作
eg2:
var result=25&3;// 先转换为32位长度的2进制,为0000....0001
alert(result);   //1

//按位或(OR),按位或操作符由一个竖线符号(|)表示,它有两个操作符数。
eg3:
var result=25 | 3;// 先转换为32位长度的2进制,为0000....0001 1011
alert(result);   //27

//按位异或(XOR),按位异或操作符由一个插入符号(^)表示,也有两个操作符。两个数值对应位上只有一个1时才返回1,如果对应2个1或2个0,则返回0.
eg4:
var result=25 ^ 3;  //转换为2进制,0000....0001 1010
alert(result);  //26

//左移,左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数。
eg5:
var oldValue=2;     //等于二进制的10
var newValue=oldValue <<5; //等于二进制的1000000,十进制的64

//有符号的右移,左移操作符由两个大于号(>>)表示,这个操作符会将数值的所有位向右移动指定的位数,但保留符号位(正负号标记)。
eg6:
var oldValue=64;    //等于二进制的1000000,十进制的64
var newValue=oldValue <<5;  //等于二进制的10,即10进制的2

//无符号的右移,左移操作符由三个大于号(>>>)表示,这个操作符会将所有32位都向右移动。对于正数来说,无符号右移的结果与有符号右移相同。对于负数来说,无符号位以0来填充空位。
eg7:
var oldValue=64;    //等于二进制的1000000,十进制的64
var newValue=oldValue <<5;  //等于二进制的10,即10进制的2

eg8:
var oldValue=-64;    //等于二进制的1....(总共27个1)..11100000
var newValue=oldValue >>>5; //等于10进制的134217726

左移:

 

右移:

2.3.2 一元操作符(一元运算符)

A.一元操作符:只能操作一个值的操作符。

//1.递增和递减操作符[前置型和后置型]
//前置型位于操作变量之前,以变量为中心,先变更变量的值,在进行运算。
//前置递增、前置递减与执行语句的优先级相等,整个语句从左到右被求值。
eg1:
var age=29;
++age;  //类似于 age=age+1; //前置递增,从29变更为30
--age; //类似于age=age-1; //前置递减,从29变更为28
eg2:
var age=29;
var anotherAge=--age+2; 
alert(age)       //输出28 
alert(anotherAge)   //输出30

//后置型位于操作变量之后,递增和递减操作是在包含它们的语句被求值之后才执行的。
eg3:
var num1=2;
var num2=20;
var num3=num--+num2; //等于22
var num4=num1+num2; //等于21

**总结**
**前置++:先自身加1,后参与运算**
**后置++:先参与运算,后自身加1**
**上面两个理解后,下面两个自通**
**前置--  :先减1,后参与运算**
**后置--  :先参与运算,后减1** 

递增(++)和递减(--)操作符遵循的规则:

  1. 应用包含有效数字字符的字符串时,先将其转换为数字值,再执行加减1的操作。字符串变量变成数值变量。
  2. 应用不包含有效数字字符的字符串时,将变量的值设置为NaN,字符串变量变成数值变量。
  3. 应用布尔值false时,先将其转换为0再执行加减1的操作。布尔值变成数值变量。
  4. 应用布尔值true时,先将其转换为1再执行加减1的操作。布尔值变成数值变量。
  5. 应用浮点值时,执行加减1的操作
  6. 应用于对象时,先调用对象的valueOf()方法,以取得一个可供操作的值,如果结果为NaN,则在调用toString()方法后再应用前述规则。对象变量变成数值变量。
eg:
var s1="2";
var s2="z";
var b=false;
var f=1.1;
var o={
    valueOf:function(){
        return -1;
    }
};
s1++;   //数值为3
s2++;   //数值为NaN
b++;   //数值为1
f--;     //数值为0.10000000000000009
o--;    //值变成了-2

B.一元加和减操作符

//一元加和减操作符主要用于基本的算数运算。
//一元加操作符,该操作符会像Number()转型函数一样对这个值执行转换。
eg:
var s1="01";
var s2="1.1";
var s2="z";
var b=false;
var f=1.1;
var o={
    valueOf:function(){
        return -1;
    }
};
s1=+s1;   //值变成数值1
s2=+s2;  //值变成数值1.1
s3=+s3;  //值变成NaN
b=+b;     //值变成数值0
f=+f;   //值未变,仍然是1.1
o=+o;  //值变成数值-1
//一元减操作符,主要用于表示负数,例如将1转换成-1.
var num=25;
num=-num; //变成了-25

2.3.3 算术操作符

一、乘性操作符,主要包含3个:乘法、除法、求模。如果参与乘法计算的某个操作数不是数值,后台会先使用Number()转型函数将其转换为数值。空字符串将被当做0,布尔值true将被当作1。

A.乘法操作符遵循的规则:

  1. 如果操作数是数值,常规乘法计算;如果乘积超过数值的表示范围,则返回Infinity或-Infinity.
  2. 如果有一个操作数是NaN,则结果是NaN
  3. Infinity与0相乘,则结果是NaN
  4. Infinity与非0数值相乘,则结果是Infinity或-Infinity,取决于有符号操作数的符号
  5. 如果是Infinity与Infinity相乘,则结果是Infinity
  6. 如果有一个操作数不是数值,则在后台调用Number()将其转换为数值,然后在应用上面的规则
//1.乘法操作符(*),由一个星号(*)表示,用于计算两个数值的乘积。
eg:
var result=34*56;

B.除法操作符由一个斜线符号(/)表示,执行第二个操作数除第一个操作数的计算。

除法操作符遵循的规则:

  1. 如果操作数都是数值,执行常规除法计算,超出数值的表示范围,则返回Infinity或-Infinity.
  2. 如果有一个操作数是NaN,则结果是NaN
  3. 如果是Infinity被Infinity除,则结果是NaN
  4. 如果是零被零除,则结果是NaN
  5. 如果是非零的有限数被零除,则结果是Infinity或-Infinity,取决于有符号操作数的符号
  6. 如果是Infinity被任何非零数值除,则结果是Infinity或-Infinity,取决于有符号操作数的符号。
  7. 如果有一个操作数不是数值,则在后台调用Number()将其转换为数值,然后再应用上面的规则
//除法
var result=66/11;

C.求模(余数)操作符由一个百分号(%)表示

求模操作符遵循的规则:

  1. 如果操作数都是数值,执行常规的除法计算,返回除得的余数
  2. 如果被除数是无穷大值而除数是有限大的数值,则结果是NaN
  3. 如果被除数是有限大的数值而除数是0,则结果是NaN
  4. 如果是Infinity被Infinity除,则结果是NaN
  5. 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数
  6. 如果被除数是零,则结果是零。
  7. 如果有一个操作数不是数值,则在后台调用Number()将其转换为数值,然后再应用上面的规则
//求模,结果为1
var result=26%5 

二 加性操作符

A.加法操作符(+)遵循的规则

  1. 如果两个操作符都是数值,执行常规的加法计算
  2. 如果一个操作数是NaN,则结果是NaN
  3. 如果是Infinity+Infinity,则结果是Infinity
  4. 如果是Infinity+Infinity,则结果是Infinity
  5. 如果是-Infinity加-Infinity,则结果是-Infinity
  6. 如果是Infinity加-Infinity,则结果是NaN
  7. 如果+0加+0,则结果是+0
  8. 如果-0加-0,则结果是-0
  9. 如果+0加-0,则结果是+0
  10. 如果两个操作数都是字符串,则进行拼接
  11. 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,再进行拼接

B.减法操作符(-)是另一个极为常用的操作符

  1. 如果两个操作符都是数值,执行常规的算术减法操作
  2. 如果一个操作数是NaN,则结果是NaN
  3. 如果是Infinity-Infinity,则结果是NaN
  4. 如果是Infinity-Infinity,则结果是NaN
  5. 如果是Infinity减-Infinity,则结果是Infinity
  6. 如果是-Infinity减Infinity,则结果是-Infinity
  7. 如果+0减+0,则结果是+0
  8. 如果-0减-0,则结果是-0
  9. 如果+0减-0,则结果是+0
  10. 如果有一个操作数是字符串、布尔值、null或undefined,则现在后台调用Number()函数将其转换为数值,然后在根据前面的规则执行减法计算,如果转换的结果是NaN,则减法的结果就是NaN。
  11. 如果有一个操作数是对象,则调用对象的valueOf()方法以取得表示该对象的数值,如果得到的值是NaN,则减法的结果是NaN.如果对象没有valueOf()方法,则调用toString()方法并将得到的字符串转换为数值。
//减法
var result=2-1;
var result1=5-true;  //4,true被转换成了1
var result2=NaN-1;  //NaN
var result3=5-3;    //2
var result4=5-"";   //5,  ""被转换成了0
var result5=5-"2";  //3,"2"被转换成了2
var result6=5-null;   //5,null被转换成了0

2.3.4 逻辑运算符(布尔操作符

布尔操作符 = 相等操作符,布尔操作符有3个:非(NOT)、与(AND)、或(OR)。

A.逻辑非操作符的规则:

  1. 操作数是一个对象,返回false
  2. 操作数是一个空字符串,返回true
  3. 操作数是一个非空字符串,返回false
  4. 操作数是数值0,返回true
  5. 操作数是任意非0数值(包括Infinity),返回false
  6. 操作数是null,返回ture
  7. 操作数是NaN,返回true
  8. 操作数是undefined,返回true
//逻辑非
alert(!false)  //true
alert(!0)  //true
alert(!NaN)  //true
alert(!"")  //true
alert(!"blue")  //false
alert(!12345)  //false
//2个逻辑非操作符,会模拟Boolean()转型函数的行为。
alert(!!0)  //false
alert(!!NaN)  //false
alert(!!"")  //false
alert(!!"blue")  //true
alert(!!12345)  //true

B.逻辑与

逻辑与操作符由两个和号(&&)表示,有2个操作数。

逻辑与遵循的规则:

  1. 第一个操作数是对象,则返回第二个操作数
  2. 第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象
  3. 如果两个操作数都是对象,则返回第二个操作数
  4. 如果有一个操作数是null,则返回null
  5. 如果有一个操作数是NaN,则返回NaN
  6. 如果有一个操作数是undefined,则返回undefined
//逻辑与操作可以应用于任何类型的操作数
//逻辑与操作属于短路操操作,第一个操作数是false,则无论第二个操作数是什么值,都不会执行
eg1:
var found = true;
var result=(found && someUndefinedVariable); //发生错误
alert(result);  //这一行不会执行
eg2:
var found = false;
var result=(found && someUndefinedVariable); //不会发生错误
alert(result);  //会执行false 

C.逻辑或

逻辑或操作符由两个(||)表示,有2个操作数。

逻辑或遵循的规则:

  1. 第一个操作数是对象,则返回第二个操作数
  2. 第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象
  3. 如果两个操作数都是对象,则返回第二个操作数
  4. 如果有一个操作数是null,则返回null
  5. 如果有一个操作数是NaN,则返回NaN
  6. 如果有一个操作数是undefined,则返回undefined
//逻辑或操作可以应用于任何类型的操作数
//逻辑或操作属于短路操操作,第一个操作数的求值结果为true,就不会对第二个操作数求值了。
eg1:
var found = true;
var result=(found || someUndefinedVariable); //不会发生错误
alert(result);  //会执行true
eg2:
var found = false;
var result=(found && someUndefinedVariable); //会发生错误
alert(result);  //这一行不会执行 

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

> < >= <= == != ===  !==

== 与 ===的区别: ==只比较值,===类型和值同时相等,则相等

var result =’55’ ==55; //true

var result =’55’ ===55; //false 值相等,类型不相等

var result = 55 ===55; //true 

2.3.6 赋值运算符

简单的赋值操作符由等于号(=)表示,其作用就是把右侧的值赋给左侧的变量。

//算术操作符(以及个别的其他操作符)
加/赋值:+=  
减/赋值:-=  
乘/赋值:*=  
除/赋值:/=/赋值:%=
左移/赋值:<<=
有符号右移/赋值:>>=
无符号右移/赋值:>>>=

2.3.7 运算符的优先级

优先级从高到低

  1. () 优先级最高
  2. 一元运算符 ++ -- !
  3. 算数运算符 先*  /  % 后 + -
  4. 关系运算符 > >=  <  <=
  5. 相等运算符 == !=  ===  !===
  6. 逻辑运算符 先&&  后||
  7. 赋值运算符
// 练习1
4 >= 6 || '人' != '阿凡达' && !(12 * 2 == 144) && true
// 练习2
var num = 10;
5 == num / 2 && (2 + 2 * num).toString() === '22'

2.4 表达式和语句

表达式:可以产生一个值,有可能是运算、函数调用、有可能是字面量。表达式可以放在任何需要值的地方。

语句:一个行为,循环语句和判断语句就是典型的语句。一个程序有很多个语句组成,一般情况下,分割一个一个的语句。

流程控制:程序的三种基本结构。

顺序结构:从上到下执行的代码就是顺序结构、程序默认就是从上到下顺序执行的。

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

循环结构:重复做一件事情。

2.4.1 分支结构-if语句

语法结构:

//condition(条件)可以是任意表达式;而且对这个表达式求值的结果不一定是布尔值,会通过Boolean()转换函数将这个表达式的结果转换为一个布尔值
if (condition1) {
  // 执行语句1
}

if (condition1){
  // 成立执行语句1
} else {
  // 否则执行语句2
}

if (condition1){
  // 成立执行语句1
} else if (condition2){
  // 成立执行语句2
} else if (condition3){
  // 成立执行语句3
} else {
  // 最后默认执行语句4
}

eg:
if (i >25) {
    alert("Greater than 25.");
}else if (i < 0) {
    alert("Less than 0.");
}else {
  alert("between 0 and 25,inclusive.")  
}

案例:
    求两个数的最大数
    判断一个数是偶数还是奇数
    分数转换,把百分制转换成ABCDE   <60  E  60-70 D  70-80 C  80-90 B  90 - 100 A
作业:
    判断一个年份是闰年还是平年
      闰年:能被4整除,但不能被100整除的年份 或者 能被400整除的年份
    判断一个人的年龄是否满18岁(是否成年)

三元运算符:表达式1 ? 表达式2 : 表达式3,是对if……else语句的一种简化写法

案例:
   是否年满18岁
   从两个数中找最大值

2.4.2 循环结构

在JavaScript中有3种循环语句:while、do..while、for循环

1 while语句

//while语句属于前测试循环语句,在循环体内的代码被执行之前,就会对出口条件求值,语法
while (expression) {
  statement(循环体)  
}
// 判断循环条件为true时,执行循环体, 当循环条件为false时,结束循环。

eg:
var i=0;
while (i<10){
    i+=2;
}

do-while语句

do-while语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。语法:

//条件表达式求值之前,循环体内的代码statement至少会被执行一次
do {
  statement  
} while (expression);
eg:
var i=0;
do {
  i+=2;  
}while(i<10);
alert(i);

3 for语句

//for语句也是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代码的能力,for的语法
for(initialization1;expression2;post-loop-expression3) {
   statement(循环体4) 
}

for (初始化表达式1; 判断表达式2; 自增表达式3) {
  // 循环体4
}

执行顺序:1243  ----  243   -----243(直到判断表达式变成false)
1. 初始化表达式
2. 判断表达式
3. 自增表达式
4. 循环体

eg:
var count=10;
for(var i=0;i<count;i++){
  alert(i);  
}
alert(i);  //10

4 for-in语句

for-in语句是一种精准的迭代语句,可以用来枚举对象的属性。

//for...in语法
for (property in expression){
  statement  
}

eg:
for(var propName in window){ //循环显示BOM中window对象的所有属性
  document.write(propName);  //每次执行循环时,都会将window对象中存在的一个属性名赋值给变量proName,直到对象中的所有属性都被枚举一遍为止。
}

2.4.3 label语句

使用label语句可以在代码中添加标签,以便将来使用。

//label语法
label:statement

eg1:
start:for(var i=0;i<count;i++){ //定义start标签可以在将来由break或continue语句引用,加的标签语句一般与for语句循环使用
  alert(i);  
}

eg2:
//outermost标签表示外部的for语句。如果每个循环正常执行10次,则num++会执行100次。
var num=0;
outermost:
for(var i=0;i<10;i++){
  for (var j=0;j<10;j++){
         if (i==5 && j==5){  //i==5 和j==5的时候,退出所有循环,此时的num的值等于55
             break outermost;      
         }
    }  
    num++;
}    
alert(num); //55  

eg3: //outermost标签表示外部的for语句。如果每个循环正常执行10次,则num++会执行100次。 var num=0; outermost: for(var i=0;i<10;i++){ for (var j=0;j<10;j++){ if (i==5 && j==5){ //i==5 和j==5的时候,退出当前内部循环,从i重新开始执行,所以只少循环了i==5 && j=6、7、8、9、10这5次 countinue outermost; } } num++; } alert(num); //95

2.4.4 continue和break

Break关键字:立刻退出所有循环,强制继续执行循环后面的语句。

Continue:立刻退出循环,但退出循环后从循环的顶部继续执行(开始下一轮循环)。

break和continue语句用于在循环中精确地控制代码的执行。

eg1:
var num=0;
for(var i=1;i<10;i++){
  if(i%5==0){
       break;          
   }  
    num++;    
}

alert(num);  //4

eg2:
var num=0;
for(var i=1;i<10;i++){
  if(i%5==0){
       continue;          
   }  
    num++;    
}

alert(num);  //8,循环体总共执行了8次

2.4.5 with语句

with语句的作用:将代码的作用域设置到一个特定的对象中。

//with语句语法
with(expression){
       statement;
}
eg:
var qs=location.search.substring(1);
var hostname=location.hostname;
var url=location.href;

with(location){
      var qs=search.substring(1);
      var hostname=hostname;
      var url=href;
}

2.4.6 Switch语句

//switch语法格式,expression条件为真时,执行下面的句子
switch (expression) {
  case value常量1: statement语句1;
    break;
  case value常量2: statement语句2;
    break;
  case value常量3: statement语句3;
    break;
  …
  case value常量n: statement语句n;
    break;
  default:    statement语句;
}

案例:
   显示星期几
   素质教育(把分数变成ABCDE)千万不要写100个case哟

2.5 函数

通过使用function关键字来声明,后跟一组参数以及 函数体。

//function语法
function functionName(arg0,arg1,...,argN){
      statements
}

eg:
function sayHi(name,message){
     alert("Hello"+name+","+message);
}

saiHi("Nicholas","how are you today?");

3 变量、作用域和内存问题 

3.1 基本类型的值和引用类型的值

ECMAScript变量可以用来保存两种不同数据类型的值:基本类型的值和引用类型的值。

基本类型的值:简单的数据段,内存中占据固定大小的空间,保存在栈内存中。比如5种基本数据类型就是按值访问的。[可以操作保存在变量中的实际的值]

引用类型值:那些可能由多个值构成的对象,引用类型的值是按引用访问的,保存在堆内存中。[引用类型的值是保存在内存中的对象]

ps:确定值类型用typeof操作符,确定引用类型可以使用instanceof操作符。

复制基本类型值和引用类型值的过程对比:

//1.动态的属性,只能对引用类型的值为其添加属性和方法,也可以改变和删除其属性和方法。
eg1:
var person=new Object();
person.name="nick";
alert(person.name);  //"nick"

//2.复制变量值,基本类型的值
eg2:
var num1=5; var num2=num1; //3.复制变量值,引用类型的值
eg3:
var obj1=new Object() var obj2=obj1; obj1.name="nick"; alert(obj2.name); //"nick" 

eg2和eg3复制变量值的过程图:

 

 传递参数:所有函数的参数都是按值传递的。在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量。

eg:
function addTen(num){  //参数num是函数的局部变量,调用addTen(),变量count作为参数传递给函数,这个变量的值为20
     num+=10;
     return num;
}
var count=20;
var result=addTen(count);
alert(count);   //20,没有变化
alert(result);   //30 

3.2 理解执行环境[作用域]

执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。

所有变量(包括基本类型和引用类型)都存在于一个执行环境(也称为作用域)当中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。

  • 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分。
  • 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链。
  • 函数的局部环境不仅有权访问作用域中的变量,而且有权访问其包含父环境,乃至全局环境。
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据。
  • 变量的执行环境有助于确定应该何时释放内存
//当代码在一个环境中执行时,会创建变量对象的一个作用域链
//作用域链的用途:保证对执行环境有权访问的所有变量和函数的有序访问。
//标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直至找到标识符为止

eg1:
var color="blue"
function changeColor(){  
//函数changeColor()的作用域链有2个对象:自己的变量对象和全局环境的变量对象。
  if(color === "blue"){
      color ="red";
}  else {
      color ="blue";
}  
}
changeColor();
alert("Color is now"+color);

eg2://3个执行环境:全局环境、changeColor()的局部环境和swapColors()的局部环境。
//全局环境:一个变量color和changeColor()
//changeColor()的局部环境:变量anotherColor、函数swapColors(),同时可以访问全局变量中的color.
//swapColors()的局部变量:变量tempColor,在内部可以访问其他2个环境中的所有变量[父执行环境]
var color="blue"
function changeColor(){  
   var anotherColor="red";
   function swapColors(){  
       var tempColor= anotherColor;
       anotherColor= color;
       color= tempColor;
//这里可以访问color、anotherColor、tempColor
}
     swapColors();
//这里可以访问color、anotherColor,但不能访问tempColor
}
//这里只能访问color
changeColor();

 从下往上进行搜索:

3.3 理解垃圾收集

JS具有自动垃圾收集机制[执行环境会负责管理代码执行过程中使用的内存]:找出那些不在继续使用的变量,然后释放其占用的内存。

离开作用域的值,会被自动标记为可以回收,且在垃圾收集期间被删除。

"标记清除"是目前主流的垃圾收集算法。

当代码中存在循环引用现象时,引用计数算法就会导致问题

解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。

数组

为什么要学习数组

之前学习的数据类型,只能存储一个值(比如:Number/String,我们想存储班级中所有学生的姓名,此时该如何存储?)

数组的概念

所谓数组,就是将多个元素(通常是同一类型)按一定顺序排列放在一个集合中,那么这个集合我们就成为数组。

数组的定义

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

通过数组字面量创建数组

// 创建一个空数组
var arr1 = [];
// 创建一个包含3个数值的数组,多个数组项以逗号隔开
var arr2 = [1, 3, 4];
// 创建一个包含2个字符串的数组
var arr3 = ['a', 'c'];

// 可以通过数组的length属性获取数组的长度
console.log(arr3.length);
// 可以设置length属性改变数组中元素的个数
arr3.length = 0;

获取数组元素

数组的取值

// 格式:数组名[下标]  下标又称索引
// 功能:获取数组对应下标的那个值,如果下标不存在,则返回undefined。
var arr = ['red', 'green', 'blue'];
arr[0];    // red
arr[2]; // blue
arr[3]; // 这个数组的最大下标为2,因此返回undefined

遍历数组

遍历:遍及所有,对数组的每一个元素都访问一次就叫遍历。

数组遍历的基本语法:
for(var i = 0; i < arr.length; i++) {
   // 数组遍历的固定结构
}

var  arr=[10,20,30,40,50,60];
for (var i=0;i<arr.length;i++){
  console.log(arr[i]);
}

数组中新增元素

数组的赋值

// 格式:数组名[下标/索引] = 值;
// 如果下标有对应的值,会把原来的值覆盖,如果下标不存在,会给数组新增一个元素。
var arr = ["red", "green", "blue"];
// 把red替换成了yellow
arr[0] = "yellow";
// 给数组新增加了一个pink的值
arr[3] = "pink";

案例

### 案例
求一组数中的所有数的和和平均值
求一组数中的最大值和最小值,以及所在位置
将字符串数组用|或其他符号分割
要求将数组中的0项去掉,将不为0的值存入一个新的数组,生成新的数组
翻转数组
冒泡排序,从小到大

数组

为什么要有函数

如果要在多个地方求1-100之间所有数的和,应该怎么做?

什么是函数

把一段相对独立的具有特定功能的代码块封装起来,形成一个独立实体,就是函数,起个名字(函数名),在后续开发中可反复调用。

函数的作用就是封装一段代码,将来可以重复使用

函数的定义

函数的声明:

function 函数名(){

//函数体

}

函数表达式:

var fn=function(){

//函数体

}

特点

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

函数一般都用来干一件事情,需要使用动词+名词,表示一件事情 ‘sayHello’等

函数的调用

调用函数的语法:

函数名();

特点

函数体只有在调用的时候才会执行,调用需要()进行调用

可以调用多次(重复使用)

//声明函数

function sayHi(){

Console.log(“吃了吗?”);

}

//调用

sayHi();

函数的参数

函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部

带参数的函数声明:

Function 函数名(形参1,形参2,形参3,....){

//函数体

}

带参数的函数调用:

函数名(实参1,实参2,实参3.....); 

形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是不固定的,对于这些固定不了的值,我们可以给函数设置参数。这个参数没有具体的值,仅仅起到了一个占位置的作用,称为形式参数,也叫形参。

实际参数:函数调用的时候需要传入对应的参数,把传入的参数叫做实际参数。

案例

求1-n 之间所有数的和

求n-m之间所有数的和

圆的面积

求2个数中的最大值

求2个数中的最小值

判断一个数是否是素数

函数的返回值

当函数执行完的时候,并不是所有时候都要把结果打印,我们期望函数给我一些反馈,可以让函数返回一些东西,也就是返回值,函数通过return返回一个返回值。

返回值的语法:

//声明一个带返回值的函数

function 函数名(形参1,形参2,....){

 //函数体

return 返回值;

}

可以通过变量来接收这个返回值:

var 变量=函数名(实参1,实参2,实参3....);

函数的调用结果就是返回值,因此我们可以直接对函数调用结果进行操作。

返回值详解:

如果函数没有显示的使用return语句,那么函数有默认的返回值:undefined

如果函数使用return语句,那么跟在return后面的值,就成了函数的返回值

如果函数使用return语句,但是return后面没有任何值,那么函数的返回值也是:undefined

函数使用return语句后,这个函数会在执行完return语句之后停止并立即退出,也就是说return后面的所有其他代码都不会执行。

推荐的做法就是:要么让函数始终返回一个值,要么永远都不要返回值。 

案例

求阶乘

求1!+2!+3!+4!+n!

求一组数中的最大值

求一组数中的最小值

Arguments 的使用

arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。也就是说所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有的实参。arguments是一个伪数组,因此可以进行遍历。

案例

求任意个数的最大值

求任意个数的和

求斐波那契数列Fibonacci中的第n个数是多少?      1 1 2 3 5 8 13 21...
翻转数组,返回一个新数组
对数组排序,从小到大
输入一个年份,判断是否是闰年[闰年:能被4整数并且不能被100整数,或者能被400整数]
输入某年某月某日,判断这一天是这一年的第几天?

函数其他

匿名函数

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

匿名函数如何使用:

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

预解析

预解析:在执行代码之前做的事情

变量的声明和函数的声明被提前了,变量和函数的声明会提升到当前所在的作用域的最上面。

函数中的变量声明,会提升到该函数的作用域的最上面(里面)。

如果有多对的script标签都有相同名字的函数,预解析的时候是分段的,互不影响。

自调用函数

关于自执行函数(匿名函数自调用)的作用:防止全局变量污染。
### 自调用函数
>匿名函数不能通过直接调用来执行,因此可以通过匿名函数的自调用的方式来执行
(function () {
  alert(123);
})();

函数是一种数据类型

### 函数是一种数据类型
function fn() {}
console.log(typeof fn);

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

- 函数做为返回值
因为函数是一种类型,所以可以把函数可以作为返回值从函数内部返回,这种用法在后面很常见。
function fn(b) {
  var a = 10;
  return function () {
    alert(a+b);
  }
}
fn(15)();

代码规范

### 代码规范
    1.命名规范
    2.变量规范   
       var name = 'zs';   
    3.注释规范
       // 这里是注释
    4.空格规范
    5.换行规范
       var arr = [1, 2, 3, 4];
       if (a > b) {
       }
       for(var i = 0; i < 10; i++) {
       }
       function fn() {
       }

作用域

作用域:变量的使用范围

全局变量和局部变量

全部变量:在任何位置都可以使用的范围

局部变量:在函数中定义的变量

块级作用域

任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
**在es5之前没有块级作用域的的概念,只有函数作用域**,现阶段可以认为JavaScript没有块级作用域

词法作用域

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

作用域链

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

将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。

在一个函数中使用一个变量,先在该函数中搜索这个变量,找到了则使用,找不到则继续向外找这个变量,找到则使用,一直找到全局作用域,找不到则是undefined。

预解析

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

预解析过程:
1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
3. 先提升var,在提升function

全局解析规则

函数内部解析规则

变量提升

- 变量提升

  定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。

- 函数提升

  JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面 

对象

为什么要有对象

function printPerson(name, age, sex....) {
}
// 函数的参数如果特别多的话,可以使用对象简化
function printPerson(person) {
  console.log(person.name);
  ……
}

什么是对象

现实生活中:万物皆对象,对象是一个具体的事物,一个具体的事物就会有行为和特征。
举例: 一部车,一个手机
车是一类事物,门口停的那辆车才是对象
   特征:红色、四个轮子
   行为:驾驶、刹车

看得见,摸得到,具体特指的某个东西。

分析对象有什么特点:特征和行为

对象:有特征和行为,具体特指的某一个事物

对象:有属性和方法,具体特指的某个事物

对象:一组无序属性的集合,属性的值可以是任意的类型。

JavaScript中的对象

JavaScript中的对象其实就是生活中对象的一个抽象
JavaScript的对象是无序属性的集合。
   其属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。
对象的行为和特征
   特征---属性
   行为---方法

+ 事物的特征在对象中用属性来表示。
+ 事物的行为在对象中用方法来表示。

对象字面量

> 字面量:11 'abc'  true  [] {}等

var obj={};

var o = {
  name: 'zs,
  age: 18,
  sex: true,
  sayHi: function () {
    console.log(this.name);
  }
};

- new Object()创建对象
var person = new Object();
  person.name = 'lisi';
  person.age = 35;
  person.job = 'actor';
  person.sayHi = function(){
  console.log('Hello,everyBody');
}

- 工厂函数创建对象

function createPerson(name, age, job) {
  var person = new Object();
  person.name = name;
  person.age = age;
  person.job = job;
  person.sayHi = function(){
    console.log('Hello,everyBody');
  }
  return person;
}
var p1 = createPerson('张三', 22, 'actor');

- 自定义构造函数

function Person(name,age,job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayHi = function(){
   console.log('Hello,everyBody');
  }
}
var p1 = new Person('张三', 22, 'actor');

对象创建方法

创建对象三种方式:

  1. 调用系统的构造函数创建对象

Var 变量名=new Object()

example:

var iphone = new Object();
iphone.color="红色";
iphone.model="da";
var sayIphone= function () {
  console.log("可以打电话");
};
var sayDuanxin= function () {
  console.log("发短信");
};

  1. 自定义构造函数创建对象(结合第一种和需求通过工厂模式创建对象)

工厂模式创建对象:

function createObject(color,model) {
    var iphone = new Object();
    iphone.color=color;
    iphone.model=model;
    iphone.sayIphone= function () {
      console.log("可以打电话"+model);
    };
    iphone.sayDuanxin= function () {
      console.log("发短信"+color);
    };
  return iphone;
}

  1. 字面量的方式创建对象

Var obj={};

属性和方法

如果一个变量属于一个对象所有,那么该变量就可以称之为该对象的一个属性,属性一般是名词,用来描述事物的特征
如果一个函数属于一个对象所有,那么该函数就可以称之为该对象的一个方法,方法是动词,描述事物的行为和功能

New关键字

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

1. 构造函数用于创建一类对象,首字母要大写。
2. 构造函数要和new一起使用才有意义。
new在执行时会做四件事情
new会在内存中创建一个新的空对象
new 会让this指向这个新的对象
执行构造函数  目的:给这个新对象加属性和方法
new会返回这个新对象
``

this详解

JavaScript中的this指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解
现在我们需要掌握函数内部的this几个特点
   1. 函数在定义的时候this是不确定的,只有在调用的时候才可以确定
   2. 一般函数直接执行,内部this指向全局window
   3. 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
   4. 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到了这个隐式对象身上,后续通过new关键字来调用,从而实现实例化

对象的使用

遍历对象的属性

> 通过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

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

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

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

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

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

内置对象

JS学习中三种对象:内置对象、浏览器对象、自定义对象。

内置对象:JS系统自带的对象,JavaScript 提供多个内置对象:Math/Array/Number/String/Boolean...

自定义对象:自己定义的构造函数创建的对象

浏览器对象:BOM的时候讲

内置对象:

Math

Date

String

Array

Object

实例对象:通过构造函数创建出来,实例化的对象

静态对象:不需要创建,直接就是一个对象,方法(静态方法)直接通过

MDN

- [MDN](https://developer.mozilla.org/zh-CN/)
- 通过查询MDN学习Math对象的random()方法的使用

如何学习一个方法

1. 方法的功能
2. 参数的意义和**类型**
3. 返回值意义和**类型**
4. demo进行测试

Math对象

Math对象不是构造函数,它具有数学常数和函数的属性和方法,都是以静态成员的方式提供
跟数学相关的运算来找Math中的成员(求绝对值,取整)
[Math](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math)
演示:Math.PI、Math.random()、Math.floor()/Math.ceil()、Math.round()、Math.abs()  、Math.max(
Math.PI                   // 圆周率
Math.random()           // 生成随机数
Math.floor()/Math.ceil()    // 向下取整/向上取整
Math.round()            // 取整,四舍五入
Math.abs()             // 绝对值
Math.max()/Math.min()      // 求最大和最小值
Math.sin()/Math.cos()      // 正弦/余弦
Math.power()/Math.sqrt()    // 求指数次幂/求平方根

案例

- 求10-20之间的随机数
- 随机生成颜色RGB
- 模拟实现max()/min()

Date对象

创建 `Date` 实例用来处理日期和时间。Date 对象基于1970年1月1日(世界标准时间)起的毫秒数。

~~~javascript
// 获取当前时间,UTC世界时间,距1970年1月1日(世界标准时间)起的毫秒数
var now = new Date();
console.log(now.valueOf());    // 获取距1970年1月1日(世界标准时间)起的毫秒数
Date构造函数的参数
1. 毫秒数 1498099000356      new Date(1498099000356)
2. 日期格式字符串  '2015-5-1'  new Date('2015-5-1')
3. 年、月、日……            new Date(2015, 4, 1)   // 月份从0开始
~~~
- 获取日期的毫秒形式
var now = new Date();
// valueOf用于获取对象的原始值
console.log(date.valueOf())    
// HTML5中提供的方法,有兼容性问题
var now = Date.now();  
// 不支持HTML5的浏览器,可以用下面这种方式
var now = + new Date();          // 调用 Date对象的valueOf()

- 日期格式化方法
toString()    // 转换成字符串
valueOf()     // 获取毫秒值
// 下面格式化日期的方法,在不同浏览器可能表现不一致,一般不用
toDateString()
toTimeString()
toLocaleDateString()
toLocaleTimeString()
- 获取日期指定部分
getTime()        // 返回毫秒数和valueOf()结果一样,valueOf()内部调用的getTime()
getMilliseconds()
getSeconds()  // 返回0-59
getMinutes()  // 返回0-59
getHours()    // 返回0-23
getDay()      // 返回星期几 0周日   6周6
getDate()     // 返回当前月的第几天
getMonth()    // 返回月份,***从0开始***
getFullYear() //返回4位的年份  如 2016

案例

- 写一个函数,格式化日期对象,返回yyyy-MM-dd HH:mm:ss的形式
function formatDate(d) {
  //如果date不是日期对象,返回
  if (!date instanceof Date) {
    return;
  }
  var year = d.getFullYear(),
      month = d.getMonth() + 1,
      date = d.getDate(),
      hour = d.getHours(),
      minute = d.getMinutes(),
      second = d.getSeconds();
  month = month < 10 ? '0' + month : month;
  date = date < 10 ? '0' + date : date;
  hour = hour < 10 ? '0' + hour : hour;
  minute = minute < 10 ? '0' + minute:minute;
  second = second < 10 ? '0' + second:second;
  return year + '-' + month + '-' + date + ' ' + hour + ':' + minute + ':' + second;
}
- 计算时间差,返回相差的天/时/分/秒
function getInterval(start, end) {
  var day, hour, minute, second, interval;
  interval = end - start;
  interval /= 1000;
  day = Math.round(interval / 60 /60 / 24);
  hour = Math.round(interval / 60 /60 % 24);
  minute = Math.round(interval / 60 % 60);
  second = Math.round(interval % 60);
  return {
    day: day,
    hour: hour,
    minute: minute,
    second: second
  }
}

- 计算时间差,返回相差的天/时/分/秒


function getInterval(start, end) {
  var day, hour, minute, second, interval;
  interval = end - start;
  interval /= 1000;
  day = Math.round(interval / 60 /60 / 24);
  hour = Math.round(interval / 60 /60 % 24);
  minute = Math.round(interval / 60 % 60);
  second = Math.round(interval % 60);
  return {
    day: day,
    hour: hour,
    minute: minute,
    second: second
  }
}

 

Array对象

案例

- 将一个字符串数组输出为|分割的形式,比如“刘备|张飞|关羽”。使用两种方式实现


function myJoin(array, seperator) {
  seperator = seperator || ',';
  array = array || [];
  if (array.length == 0){
    return '';
  }
  var str = array[0];
  for (var i = 1; i < array.length; i++) {
    str += seperator + array[i];
  }
  return str;
}
var array = [6, 3, 5, 6, 7, 8, 0];
console.log(myJoin(array, '-'));

console.log(array.join('-'))


- 将一个字符串数组的元素的顺序进行反转。["a", "b", "c", "d"] -> [ "d","c","b","a"]。使用两种种方式实现。提示:第i个和第length-i-1个进行交换


function myReverse(arr) {
  if (!arr || arr.length == 0) {
    return [];
  }
  for (var i = 0; i < arr.length / 2; i++) {
    var tmp = arr[i];
    arr[i] = arr[this.length - i - 1];
    arr[arr.length - i - 1] = tmp;
  }
  return arr;
}

var array = ['a', 'b', 'c'];
console.log(myReverse(array));

console.log(array.reverse());


- 工资的数组[1500, 1200, 2000, 2100, 1800],把工资超过2000的删除


// 方式1
var array =  [1500,1200,2000,2100,1800];
var tmpArray = [];
for (var i = 0; i < array.length; i++) {
  if(array[i] < 2000) {
    tmpArray.push(array[i]);
  }
}
console.log(tmpArray);
// 方式2
var array =  [1500, 1200, 2000, 2100, 1800];
array = array.filter(function (item, index) {
  if (item < 2000) {
    return true;
  }
  return false;
});
console.log(array);


- ["c", "a", "z", "a", "x", "a"]找到数组中每一个a出现的位置


var array =  ['c', 'a', 'z', 'a', 'x', 'a'];
do {
  var index = array.indexOf('a',index + 1);
  if (index != -1){
    console.log(index);
  }
} while (index > 0);


- 编写一个方法去掉一个数组的重复元素


var array =  ['c', 'a', 'z', 'a', 'x', 'a'];
function clear() {
  var o = {};
  for (var i = 0; i < array.length; i++) {
    var item = array[i];
    if (o[item]) {
      o[item]++;
    }else{
      o[item] = 1;
    }
  }
  var tmpArray = [];
  for(var key in o) {
    if (o[key] == 1) {
      tmpArray.push(key);
    }else{
      if(tmpArray.indexOf(key) == -1){
        tmpArray.push(key);
      }
    }
  }
  returm tmpArray;
}

console.log(clear(array));

 

基本包装类型

为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String/Number/Boolean


// 下面代码的问题?
// s1是基本类型,基本类型是没有方法的
var s1 = 'zhangsan';
var s2 = s1.substring(5);

// 当调用s1.substring(5)的时候,先把s1包装成String类型的临时对象,再调用substring方法,最后销毁临时对象, 相当于:
var s1 = new String('zhangsan');
var s2 = s1.substring(5);
s1 = null;



// 创建基本包装类型的对象
var num = 18;               //数值,基本类型
var num = Number('18');    //类型转换
var num = new Number(18);  //基本包装类型,对象
// Number和Boolean基本包装类型基本不用,使用的话可能会引起歧义。例如:
var b1 = new Boolean(false);
var b2 = b1 && true;      // 结果是什么

 

String对象

- 字符串的不可变


var str = 'abc';
str = 'hello';
// 当重新给str赋值的时候,常量'abc'不会被修改,依然在内存中
// 重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
// 由于字符串的不可变,在大量拼接字符串的时候会有效率问题


- 创建字符串对象


var str = new String('Hello World');

// 获取字符串中字符的个数
console.log(str.length);


- 字符串对象的常用方法

  字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串


// 1 字符方法
charAt()       //获取指定位置处字符
charCodeAt()   //获取指定位置处字符的ASCII码
str[0]        //HTML5,IE8+支持 和charAt()等效
// 2 字符串操作方法
concat()          //拼接字符串,等效于+,+更常用
slice()           //从start位置开始,截取到end位置,end取不到
substring()    //从start位置开始,截取到end位置,end取不到
substr()          //从start位置开始,截取length个字符
// 3 位置方法
indexOf()      //返回指定内容在元字符串中的位置
lastIndexOf()  //从后往前找,只找第一个匹配的
// 4 去除空白   
trim()        //只能去除字符串前后的空白
// 5 大小写转换方法
to(Locale)UpperCase()  //转换大写
to(Locale)LowerCase()  //转换小写
// 6 其它
search()
replace()
split()
fromCharCode()
// String.fromCharCode(101, 102, 103);  //把ASCII码转换成字符串

 

String------->是一个对象

字符串可以看成是字符组成的数字,但是js中没有字符类型

字符时一个一个的,在别的语言中字符用一对单引号括起来

在js中字符串可以使用单引号也可以使用双引号

因为字符串可以看成是数组,所以,可以通过for循环进行遍历

 

字符串特性:不可变性,字符串的值是不能改变

字符串的值之所以看起来是改变的,那是因为指向改变了,并不是真的值改变了。

案例

作业

给定一个字符串如:“abaasdffggghhjjkkgfddsssss3444343”问题如下: 
1、 字符串的长度 
2、 取出指定位置的字符,如:0,3,5,9等 
3、 查找指定字符是否在以上字符串中存在,如:i,c ,b等 
4、 替换指定的字符,如:g替换为22,ss替换为b等操作方法 
5、 截取指定开始位置到结束位置的字符串,如:取得1-5的字符串
6、 找出以上字符串中出现次数最多的字符和出现的次数 
7、 遍历字符串,并将遍历出的字符两头添加符号“@”输出至当前的文档页面。

附录:JS工具的使用

使用的是webstorm 2019.3.1破解版,参考博文如下(亲测有效)

PS:要彻底卸载旧版的webstorm再安装,包括(c盘下的user文件夹下的.WebStorm*等config文件)。不然填写激活码时会报License key is in legacy format

https://www.jianshu.com/p/d120ab55bfdd

参考步骤如下:

//1.下载对应网址里面的安装包和jar包,安装webstorm 3.1 软件
//2.默认安装网址 C:\Program Files\JetBrains\WebStorm 2019.3.1\bin,放补丁文件jetbrains-agent.jar
//3.webstorm.exe.vmoptions、webstorm64.exe.vmoptions文件内添加一行代码,格式:-javaagent:[包含的是补丁文件路径],默认安装如下添加
-javaagent:C:\Program Files\JetBrains\WebStorm 2019.3.1\bin\jetbrains-agent.jar
//激活码
3AGXEJXFK9-eyJsaWNlbnNlSWQiOiIzQUdYRUpYRks5IiwibGljZW5zZWVOYW1lIjoiaHR0cHM6Ly96aGlsZS5pbyIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IklJIiwiZmFsbGJhY2tEYXRlIjoiMjA4OS0wNy0wNyIsInBhaWRVcFRvIjoiMjA4OS0wNy0wNyJ9LHsiY29kZSI6IkFDIiwiZmFsbGJhY2tEYXRlIjoiMjA4OS0wNy0wNyIsInBhaWRVcFRvIjoiMjA4OS0wNy0wNyJ9LHsiY29kZSI6IkRQTiIsImZhbGxiYWNrRGF0ZSI6IjIwODktMDctMDciLCJwYWlkVXBUbyI6IjIwODktMDctMDcifSx7ImNvZGUiOiJQUyIsImZhbGxiYWNrRGF0ZSI6IjIwODktMDctMDciLCJwYWlkVXBUbyI6IjIwODktMDctMDcifSx7ImNvZGUiOiJHTyIsImZhbGxiYWNrRGF0ZSI6IjIwODktMDctMDciLCJwYWlkVXBUbyI6IjIwODktMDctMDcifSx7ImNvZGUiOiJETSIsImZhbGxiYWNrRGF0ZSI6IjIwODktMDctMDciLCJwYWlkVXBUbyI6IjIwODktMDctMDcifSx7ImNvZGUiOiJDTCIsImZhbGxiYWNrRGF0ZSI6IjIwODktMDctMDciLCJwYWlkVXBUbyI6IjIwODktMDctMDcifSx7ImNvZGUiOiJSUzAiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiUkMiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiUkQiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiUEMiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiUk0iLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiV1MiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiREIiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiREMiLCJmYWxsYmFja0RhdGUiOiIyMDg5LTA3LTA3IiwicGFpZFVwVG8iOiIyMDg5LTA3LTA3In0seyJjb2RlIjoiUlNVIiwiZmFsbGJhY2tEYXRlIjoiMjA4OS0wNy0wNyIsInBhaWRVcFRvIjoiMjA4OS0wNy0wNyJ9XSwiaGFzaCI6IjEyNzk2ODc3LzAiLCJncmFjZVBlcmlvZERheXMiOjcsImF1dG9Qcm9sb25nYXRlZCI6ZmFsc2UsImlzQXV0b1Byb2xvbmdhdGVkIjpmYWxzZX0=-WGTHs6XpDhr+uumvbwQPOdlxWnQwgnGaL4eRnlpGKApEEkJyYvNEuPWBSrQkPmVpim/8Sab6HV04Dw3IzkJT0yTc29sPEXBf69+7y6Jv718FaJu4MWfsAk/ZGtNIUOczUQ0iGKKnSSsfQ/3UoMv0q/yJcfvj+me5Zd/gfaisCCMUaGjB/lWIPpEPzblDtVJbRexB1MALrLCEoDv3ujcPAZ7xWb54DiZwjYhQvQ+CvpNNF2jeTku7lbm5v+BoDsdeRq7YBt9ANLUKPr2DahcaZ4gctpHZXhG96IyKx232jYq9jQrFDbQMtVr3E+GsCekMEWSD//dLT+HuZdc1sAIYrw==-MIIElTCCAn2gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE4MTEwMTEyMjk0NloXDTIwMTEwMjEyMjk0NlowaDELMAkGA1UEBhMCQ1oxDjAMBgNVBAgMBU51c2xlMQ8wDQYDVQQHDAZQcmFndWUxGTAXBgNVBAoMEEpldEJyYWlucyBzLnIuby4xHTAbBgNVBAMMFHByb2QzeS1mcm9tLTIwMTgxMTAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5ndaik1GD0nyTdqkZgURQZGW+RGxCdBITPXIwpjhhaD0SXGa4XSZBEBoiPdY6XV6pOfUJeyfi9dXsY4MmT0D+sKoST3rSw96xaf9FXPvOjn4prMTdj3Ji3CyQrGWeQU2nzYqFrp1QYNLAbaViHRKuJrYHI6GCvqCbJe0LQ8qqUiVMA9wG/PQwScpNmTF9Kp2Iej+Z5OUxF33zzm+vg/nYV31HLF7fJUAplI/1nM+ZG8K+AXWgYKChtknl3sW9PCQa3a3imPL9GVToUNxc0wcuTil8mqveWcSQCHYxsIaUajWLpFzoO2AhK4mfYBSStAqEjoXRTuj17mo8Q6M2SHOcwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQBonMu8oa3vmNAa4RQP8gPGlX3SQaA3WCRUAj6Zrlk8AesKV1YSkh5D2l+yUk6njysgzfr1bIR5xF8eup5xXc4/G7NtVYRSMvrd6rfQcHOyK5UFJLm+8utmyMIDrZOzLQuTsT8NxFpbCVCfV5wNRu4rChrCuArYVGaKbmp9ymkw1PU6+HoO5i2wU3ikTmRv8IRjrlSStyNzXpnPTwt7bja19ousk56r40SmlmC04GdDHErr0ei2UbjUua5kw71Qn9g02tL9fERI2sSRjQrvPbn9INwRWl5+k05mlKekbtbu2ev2woJFZK4WEXAd/GaAdeZZdumv8T2idDFL7cAirJwcrbfpawPeXr52oKTPnXfi0l5+g9Gnt/wfiXCrPElX6ycTR6iL3GC2VR4jTz6YatT4Ntz59/THOT7NJQhr6AyLkhhJCdkzE2cob/KouVp4ivV7Q3Fc6HX7eepHAAF/DpxwgOrg9smX6coXLgfp0b1RU2u/tUNID04rpNxTMueTtrT8WSskqvaJd3RH8r7cnRj6Y2hltkja82HlpDURDxDTRvv+krbwMr26SB/40BjpMUrDRCeKuiBahC0DCoU/4+ze1l94wVUhdkCfL0GpJrMSCDEK+XEurU18Hb7WT+ThXbkdl6VpFdHsRvqAnhR2g4b+Qzgidmuky5NUZVfEaZqV/g=

 

 

alert(typeof message); 
posted @ 2019-03-15 10:45  wendyw  阅读(6289)  评论(0编辑  收藏  举报