返回顶部

JavaScript基础学习

前端基础学习-JavaScript

JavaScript 简介

JS的简介

在上个世纪的1995年,当时的网景公司正凭借其 Navigator 浏览器成为 Web时代开启时最著名的第一代互联网公司。由于网景公司希望能在 静态HTML页面上 添加一些动态效果,于是叫 Brendan Eich 这哥们在两周之内设计出了JavaScript语言。

为什么起名叫 JavaScript?原因是当时Java语言非常红火,所以网景公司希望借Java的名气来推广,但事实上JavaScript除了语法上有点像 Java,其他部分基本上没啥关系。

在JavaScript中,是以对象为王的,在JavaScript中几乎所有的东西都是对象或者以对象的形式展现出来的。所以在学习之前,先理解一下什么叫面对对象编程。

面向对象编程介绍

面向对象是一种编程思想,其实跟Java、C++是一样的,JavaScript也是一门面向对象的编程语言。说到面向对象就不得不提出来面向过程的编程思想,可以和面向对象做一个对比。

面向过程就是分析出来解决问题所需要的步骤,然后使用方法函数将这些步骤一步一步的实现,使用的时候再一个一个的一次调用就可以了,比如C语言,性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。没有面向对象易维护、易复用、易扩展。

面向对象是把事务分解成一个个对象,然后由对象之间分工与合作,面向对象是以独享功能来划分问题的,而不是步骤。在面向对象程序开发思想中,每一个独享都是功能中心,具有明确的分工,面向对象编程具有灵活性、可复用性、易维护性、和容易开发等优点,适合多人合作的大型软件项目。

面对对象编程的特性:

  • 封装性

把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

  • 继承性

指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。

  • 多态性

指一个类实例的相同方法在不同情形有不同表现形式。

JS 的组成

js = ECMAScript + DOM + BOM + 高级

ECMAScript(前身为欧洲计算机制造商协会):JavaScript的语法规范

DOM(Document Object Model 的文档对象模型简称):JavaScript操作网页上元素的API

BOM(Browser Object Model 的浏览器对象模型简称):JavaScript操作浏览器部分功能的API

JS的作用与书写位置

JavaScript的最基本功能是控制网页中的元素

当然,第一点应该是把JavaScript脚本写在脚本对里。并且JavaScript语言是区分大小写的。所以一般情况下,JavaScript的书写位置有内嵌式外链式两种

内嵌式:
  一般放在body里面的最后,有时放在head标签中(需要写页面加载函数)。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  
</head>
<body>
    <div>
      <div>
        <span>hello</span>
      </div>
      <h2>JS 的书写位置</h2>
    </div>

  <script type="text/javaScript">
      var str = "hello, javaScript"
      alert(str)
  </script>
   <script src="../index/index.js" type="text/javascript"></script> 
</body>
</html>

​ 因为代码的顺序都是从上往下加载,在 body 中的元素,如果在js中获取body中元素的时候,会报错找不到。

外链式:
  src=”外部js文件路径”

变量和流程控制

变量的声明和初始化

var number               // 变量的声明,没有赋值 undefined
var name = "Hello";      // 变量的初始化
var NAME= "hello"
var 你好 = "你好" // 不推荐

命名规则(驼峰命名)

和Java一样,JavaScript采用的是驼峰式命名,

  • 变量命名必须以字母或是下标符号 "_" 或者 "$" 为开头。
  • 变量名长度不能超过 255 个字符。
  • 变量名中不允许使用空格,首个字不能为数字。
  • 不用使用脚本语言中保留的关键字及保留符号作为变量名。
  • 变量名区分大小写
  • 汉语可以作为变量名。但是不建议使用!

数据类型

基本数据类型
  • String 字符串
  • Number 数字
  • Boolean : true / false
  • undefined 未定义
  • null 空
  • symbol (ES6 引入了一种新的原始数据类型)
复杂数据类型
  • Object 对象
  • Function 函数
  • Array 数组
  • Date 日期
  • Error 错误
类型判断 instanceof / typeof
var arr = []
console.log(typeof arr) //object
console.log(arr instanceof Array) // true
类型转换
var weightIncrease ="2.5斤"
parseInt(weightIncrease)  //2
parseFloat(weightIncrease) //2.5
文本字符串操作
var words="十三是个大胖子"
words.length  //7
words.charAt(0)  //十
words.charAt(words.length-1)  //胖
words.indexOf("胖") //5
words.substring(0,2) //十三
words.replace('胖子','瘦子')  //"十三是个大瘦子"
var words="十三,是个大胖子"
words.split(',')  //["十三,是个大胖子"] 

文本字符串的操作跟其他语言的操作时差不多的,具体的用到时候可以再查。

数组操作
var arr=[]; 
typeof(arr) //"object"
arr=['十三','是个','大胖子']; //(3)["十三", "是个", "大胖子"]
arr.length; //3
arr[0]; //"十三"
arr[3] ='?'; //"?"    数组变成  (4)["十三", "是个", "大胖子", "?"]
arr.push('@');   //5   数组变成  (5)["十三", "是个", "大胖子", "?","@"]
arr.pop();  //@   删除掉数组中的最后一个元素,并返回这个元素   数组变成 (4)["十三", "是个", "大胖子", "?"]
arr.shift(); //十三  删除掉数组中的第一个元素,并返回这个元素   数组变成 (3)[ "是个", "大胖子", "?"]
delete arr[2]; //true  删除数组指定位置的元素,但不改变数组长度返回true  数组变成: ["是个", "大胖子", empty]
arr.splice(2)  //[empty]  删除指定位置元素,并返回删除的元素,改变数组长度  数组变成["是个", "大胖子"]
var arr1=["32","1","0"] 
var arr2=arr1.concat(arr);   //合并数组   (5) ["32", "1", "0", "是个", "大胖子"]

null和undefined的理解和应用

undefined是JavaScript中的一大特点,是JAVASCRIPT独有的数据和数据类型(这种数据类型只有这个一值,就是undefined,它的类型也是undefied),既然它是JAVASCRIPT独有的一种数据类型,所以需要特殊关注一下

在JAVASCRIPT里,null和undefined都表示不存在的数据,并且undefined也是从null中继承而来,那null是什么?undefined又是什么?它们两个又有什么共性和区别呢,请看下面的描述:

  1. null和undefined都是表示没有的、不存在的值。它们两个在进行逻辑转换时都是false,这两个值进行比较是true。
  2. null表示空引用,它是object类型。undefined表示未定义, 它是undefined类型。
  3. 如果一个变量的值是null,那么必须主动的给它赋值null。
  4. 一个变量未定义,或一个变量定义了未赋值,则是undefined。需要注意的是:一个变量如果没有定义,是不能直接在程序里使用的(就不是不能直接读取这个变量,但可以赋值)。比如说:本来没有定义一个叫a的变量
    但我直接去alert(a);//在浏览器里这样是个语法错误,但是可用typeof去运算
    但如果a定义了,未赋值,可以读,它的值就是undefined,如果用typeof去运算,那它的类型也是undefined。
  5. 对说属性来说:如果原来没有这个属性,根本就不存在这个属性,那么它的值就是undefined。对象的属性不需要定义,如果不存在也可以直接去读,不会报错,而会给出一个undefined的值来。
  6. 如果这个对象以后要用,但是现在还没有值,一般情况下,会给它一个null值。
  7. 在函数(方法)里,如果必须返回值,但是值又计算不出来,那就返回一个null(这是规范,而不是语法规定,JAVASCRIPT里遵循这一规范)。比如网页中没有一个id是div2的元素,则下面的这句脚本则返回null
    document.getElementById('div2');//返回null。
    但是,没有返回值的函数,它的返回值都是undefined。

在JavaScript编程实践中,如果一个变量以后要用到,现在就要定义,那我们就主动给它一个null值,虽然只定义不赋值也没有什么错误。比如以后在动画中要定义一个定时器变量,就是:var timer=null;就表示这个timer是提前定义的,以后要用,当然你也可以不给它这个null,就是直接写一个var timer;这样也没问题,不会有什么语法错误,它的值自动就是undefined,也表示一个不存在的值的。主动把null赋给timer,就是为了强调这个变量是提前预留出来的。

判断JavaScript中一些对象的属性时,也遵循这个原则,如果一个对象的属性根本就没定义过,则它是undefined;如果是null,则表示这是个本来就有的属性,只是没有值。比如说一个网页元素的parentNode这个属性,表示是这个网页元素的父节点,这是个系统规定的(法定的)的法性,一般情况这个属性的值是一个网页元素,但它的值也有为null的时候,比如:document.parentNode,这个就是null,因为它有parentNode这个属性,只不过它是顶级元素,不存父节点而已。但是它不是undefined,如果是undefined表示这个属性根本就没有定义(声明)过。

这个在调试JavaScript时非常有用,如果你调试某一个属性的值是undefined,那说明你可能把这个属性写错了,除非你在直接读取一个你从来没有操作过的自定义属性。

运算符

比较运算符

比如x=5

运算符 描述 比较 返回
== 等于 x == 8 false
x == 5 true
x == "5" true
=== 值相等并且类型相等 x === 5 true
x === "5" false
!= 不相等 x != 8 true
!== 值不相等或类型不相等 x !== 5 false
x !== "5" true
x !== 8 true
> 大于 x > 8 false
< 小于 x < 8 true
>= 大于或等于 x >= 8 false
<= 小于或等于 x <= 8 true
逻辑运算符

给定 x = 6 且 y = 3,下表解释了逻辑运算符:

运算符 描述 例子
&& (x < 10 && y > 1) 为 true
|| (x == 5 || y == 5) 为 false
! !(x == y) 为 true
条件(三元)运算符

JavaScript 也包含了可基于某些条件向变量赋值的条件运算符。

语法

variablename = (condition) ? value1:value2

实例

var voteable = (age < 18) ? "太年轻":"足够成熟";
js中不同类型作比较的规律(布尔运算)
类型 类型 规律 其它说明
对象 对象 比较是不是同一个内存地址
对象 字符串 对象先转化为字符串,然后做比较
对象 布尔类型 两边都要先转为数字(false是0,true是1)。是对象类型先隐式调用toString方法,然后再Number() alert([]false); alert([]0) alert([1]1); alert([1]true) alert([2]==true)
对象 数字 对象要转为数字,再进行比较(对象先隐式调用toString方法转化为字符串,然后再把这个字符串轮化为数字,相当于把这个字符串放到Number这个方法中)
数字 布尔 是进行的数字的比较
数字 字符串 把字符串转化为数,再比较
布尔 把两边都要转化为数字再进行比较
null undefined true
null,undefined 和其它类型 null和undefined和其它类型比较都是false(这两个对象没toString方法) alert(nullfalse) alert(null0) alert(null=="");;

流程控制

流程控制和java中是差不多的

  • if...else...
var weather='sunny',tempperature=26  ;

if((weather === 'sunny') && (tempperature <= 26) ){
	alter('happy');
}else{
    alter('sad');
}
  • while (true) {}
var i=0;
while(i<10){
    i++;
    if(i%2 === 0){
       continue;
    }
    console.log(i);
}
  • for(var a=0;a<10;a++){}
for (var i=1;i < 10;i++) {
    if (i % 2 === 0) {
        continue;
    }
    console.log(i);
}
  • switch
//注意: switch 底层用的是 === 比较
switch ("1"){
    case 1:
        alert(1);
        break;
    case 1:
        alert(1);
        break;
    case 3:
        alert(3);
        break;
    default :
        alert("都不是!");
        break;
}

注意:如果 switch 的判断条件为 false 的话,case的所有语句都不执行,只执行default的语句

js代码的注意问题:

  1. 在一对script的标签中有错误的js代码,那么该错误的代码后面的js代码不会执行
  2. 如果第一对的script标签中有错误,不会影响后面的script标签中的js代码执行。
  3. script标签里面可以写的内容:type="text/javascript" 标准写法,或者 language="JavaScript",都是可以省略的,原因是在html开头写了遵循h5标准。
  4. script标签可以出现多对
  5. 如果使用引入外部js文件的方式,那么不要在script标签里面写任何js代码,如果想写,就新开一对script标签。

异常捕获

try...catch...finally

在程序中都会有对于异常的处理,这里看一下JavaScript对于异常的处理和java中的异常处理是一样的,都是用try,catch去捕获处理的。

try{
	//可能会发生异常的代码
}catch(err){
	//错误的处理
}

写个demo

<script>
    function demo(){

    try{
        alert(str);
    }catch(err){
        alert(err);
    }
}
demo();   //页面弹出:ReferenceError: str is not defined
</script>

Throw

可以通过throw语句创建一个自定义错误,大致用法和java中一样,但是js中不分那么多异常类,都是弱类型,直接抛出字符串就可以,下面看一个demo

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Document</title>
</head>
<body>
    <input type="text" id="txt"  >
    <input type="button"  id="btn" onclick="demo()"  value="确定">
    <script>
       function demo(){
           var str=document.getElementById("txt").value;
           try{
               if(str == ''){
                  throw "未输入用户名,请输入";   //当用户输入为空,则会自动抛出异常,和java中一样   
               }else{
                  alert(str);
               }
               
           }catch(err){
                alert(err);
           }
       }
    </script>
</body>
</html>

其实还有一种onerror() 语法可以用来捕获网页中的错误,但是这是一种老式的标准,除了IE之外主流的浏览器不太支持。所以不多赘述。

函数和变量

函数

函是fnuction一词翻译过来的,也叫方法,其实叫“功能”我认为更妥当,就是对一个功能的描述或定义,在JavaScript中,function关键定义了一个功能(或叫函数、方法、行为)。

函数本来就是对象类型的数据,但由于在JavaScript语言中有着非常突出的地位,所以把函数也单独成一种数据类型了,就是function类型。就是说你首先要知道函数本身是对象类型的。

定义方法

定义方法有两种方式 声明式函数表达式

声明式

函数就是包裹在花括号中的若干代码块,前面使用了关键词 function:

function functionName (parmeter1,parmeter2...) {
		这里是要执行的代码
}
//执行的时候要在方法名后面加一对括号,并且还要有执行的主体
functionName(parmeter1,parmeter2...);

函数表达式

var functionName= function (parmeter1,parmeter2...){
	这里是要执行的代码
}    //这样把方法的定义赋给一个变量,叫函数表达式。
//执行方式和声明式是一样的
functionName(parmeter1,parmeter2...);

这个表达式其实是分三步运行的

第一步:先定义一个变量functionName,这一步是预解释的;

第二步:定义一个方法(函数);

第三步:把这个方法赋的引用地址赋给functionName这个变量。

匿名函数

定义一个方法但不起名字,那这个就叫做匿名方法。

function(){alert(“我是个匿名方法!”)}

单纯定义是没有意思,浏览器也会报错,由于匿名方法是没有方法名字所以所以单纯的定义后,方法是无法调用的,匿名函数也是可以执行的,并且还可以传参数

例如

<script>
    ;(function(){
        alert('这是自动执行的匿名方法!');
    })();
    ;(function (a,b) {
        var c=a*b;
        alert(c);
    })(45,34);  //1530
//注意,定义自动执行的匿名函数需要前面加分号;要不然后面的括号会和前面的表达式粘在一起,浏览器无法识别
//匿名方法在定义的时候也要用小括号把方法定义括起来。如果不加括号,后面表示运行的括号会与括号前的花括号结合,浏览器无法识别会出现语法错误
</script>

返回值

不管是声明式还是表达式的方式定义的函数,都可以使用return来表达函数的返回值

return的意思是中断当前这个方法的运行并且把它后面的数据返回,你需要把握好以下四点:

  1. return必须用在方法里,否则是语法错误。
  2. 在方法里只要是遇上return这个关键字,则当前的这个方法无条件的中止运行。
  3. return后面可以跟一个数据,表示中止当前的运行并且把后面的数据返回,即程序运行完成后,会留下这个数据。
  4. 如果return后没有数据(或根本就没有return),则这个方法会留下一个undefined

arguments

方法里还有两个内置的对象,就是说你定义一个方法,就会天生出现两个对象,一个叫arguments,一个叫this。先说arguments,它是一个类似于数组的对象,就是说它像数组一样保存着传入方法的所有参数。如下例:

**示例1

**
<script type="text/JavaScript">

function show(a, b){
         alert('参数1'+arguments[0]+'参数2'+arguments[1]+',参数长度:'+arguments.length);
}
show(3, 6);//输出:第一个参数是3第二个参数是6,参数的长度是:2
</script>

arguments[0]和arguments[1]分别表示第一个参数a和第二个参数b,就是它把传进来的参数,按顺序依次保存在自己的[0]和[1]的位置上了。并且arguments本身还有一个属性length,表示传进来的参数的个数。

当然,也可以不写这两个形参a和b,看下面的代码就没有写形参

示例2

写一个方法,求任意个数字之和,实现如下:

<script type="text/ecmascript">
function add(){//不指定形式参数
    var a=arguments;//参数集合,它也一个叫length属性。 

     var count=null;//为什么把null值赋给count呢,而不是0呢?

     for(var i=0;i<a.length;i++){//做一个循环,动态取得传进来的参数。
          count+=a[i];   
     }
     return count;  
}
alert(add()) //不传参数,输出null
alert(add(1,21,9)) //输出31
alert(add(-1,0,1,9,786))//这样就可以任意输入参数了,更灵活。输入的这些参数,都保存在add这个方法的arguments这个对象里
</script>

this关键字

每一个行为发生的时候,肯定会有一个发生这个行为的主体,在中文里有第一人称“我”,这个我在吃饭这个行为,就表示吃饭的那个人是我。张三吃饭,则张三吃饭行为中的那个我,就是张三,李四吃饭,则这个吃饭行为里的我就是李四。

在编程语言里,同样也有“我”的概念,那就是this关键字。每一个定义的方法里,都会有一个this关键字,这个this关键不是由在那儿定义的来决定的,而是由谁来执行的决定的。这是判断this关键表示什么的重要原则。比如:

张三.吃饭();//这个吃饭里的this就是张三这个对象

也就是判断点(.)前面的对象是谁,那这个this就是谁。

但有的方法是直接执行的,前面没有点,就更没有执行的对象了,那this关键是谁呢?像alert方法,直接执行的,那alert方法里的this是谁呢?凡是可以象alert这样直接运行的方法,都是全局方法(全局方法叫函数),全局方法的执行,都相当于前面省略掉了window.,也就是说alert()相当于window.alert(),那这样直接运行的方法里的this关键字,肯定就是window了。

方法里的this表示的是那个对象,是由谁来执行决定的。和在那儿定义的没有关系

变量

作用域

和java中一样,函数以外声明的变量是全局变量,在函数外部声明的变量是局部变量,局部变量只能是在当前函数中去访问到,也不会和函数外边同名的变量冲突,在函数外部是无法访问的,全局变量是函数内外都可以访问的,所以说,局部变量就是函数的隐私。

每一个方法在运行的时候,都会开辟一个独立的内存空间,这个方法所需要的资源开销,比如说定义的变量等,都在这个独立的内存空间内,这个内存空间就叫做方法的作用域。JavaScript里的不同代码运行,是按作用域划分的。每一个方法的一次运行,就形成一个作用域(当然,多次运行就形成多个作用域,也就是会占用多个内存空间)。数据本身当然也是要当用内存空间的,一个字符串,一个数字的使用都会占用内存空间,当然一个对象类型的数据也会占一个空间,当然一个方法的定义也要占一定的内存空间了,但你一定要理解,方法定义占的空间,和方法运行占用的空间是两码事。方法的定义是固定的状态,定义了,就会一直在那儿。但方法的运行占用的内存是动态的:开始运行就占用一块内存,然后在这个内存里创建属于这个方法自己的变量和数据,当方法结束时,把这块内存释放掉(如果方法里的数据没有被别的地方占用)。方法的运行是动态的作用域。

在JavaScript中可以把所以的对象和方法的运行都看成作用域,每一个对象又存在于其它的作用域中,(生存链和作用域链)

JavaScript中也差不多,浏览器是网页中所有代码活动的最大空间,在JavaScript中用window来表示浏览器,它就是顶级作用域。凡是在之间直接定义的变量,都是这个顶级作用域 的变量,可以叫全局变量。定义在方法里的变量,也属于这个方法运行的时候的那个作用域(再啰嗦一次:方法运行时形成的作用域和这个方法本身、或者说跟这个方法名没有关联),可以称做私有变量。

在顶级作用域中不能访问下一级作用域里的变量,但下一级作用域中可以访问上一级作用域中的变量。

示例: 如果知道直角三角形的两个直角边的长,求斜边的长度。根据勾股定理,可以实现如下方法

function bevelEdge(a,b){
	var c=Math.sqrt(a*a+b*b);
	//Math.sqrt是数学方法,开平方的作用
	return c;
}

下来看执行结果:

var c= bevelEdge(3,4);   //5

运行过程是这样的:

  1. 把3赋给bevelEdge这个方法的a,把4赋给b。这个3和4叫实参。
  2. 然后在这个方法里做运算,把运算结果赋给c。
  3. 然后把c里的值返回(注意是把c里的值返回,而不是把这个符号返回)
  4. 然后再把返回的这个结果赋给c这个变量。

把这个方法的返回值赋给了c。虽然在方法里也有一个变量叫c,这儿的变量同样也叫c,但这两个同名变量之间没有什么关系,也不会相互影响。bevelEdge方法里的变量c,只能在这个方法运行的时候(注意是运行的时候,如果这个方法不运行,不会出现这个c)出现,并且是只在这个bevelEdge方法的内部。

事件

JavaScript语言里大多的方法,是由事件来触发执行的,即事件驱动型。编程语言里的事件,就是诸如:鼠标单击(click)、鼠标双击(dblclick)、鼠标悬停(mouseover)、鼠标移动(mousemove)、鼠标离开(mouseout),还有很多键盘的事件,象什么键按下键抬起之类的等等,现在的移动端媒体上的事件就更多了。

那事件驱动就是对象上的某个事件被触发时,执行某个方法的意思。

如果想让事件触发的时候执行某个方法,那就要先把一个方法注册到这个事件上来,以备事件触发的时候执行相对应的方法。即先注册(也叫事件绑定方法),当事件触发的时候执行注册的方法。注意:注册的时候,也就是事件绑定的时候,不能执行这个方法,而是把这个方法的引用赋给这个属性,当事件触发的时候,这个方法自动执行。

<button id="button1">测试1</button>
<script>
    var ele=document.getElementById('button1');
    function fn (){
    	alert("hello");
    }
	ele.onclick=fn;
</script>

绑定到某个元素的事件上的方法在运行的时候,this关键表示的是当前这个网页元素。就像上面的那个fn方法,当它运行的时候,方法里的this表示的是ele这个元素。

总结一下事件

把一个方法绑定到某个事件上,相当于日常生活中的“做计划”,是让这个事件指向这个方法的定义,以备以后执行,这会儿不执行,所以不要加括号。

事件属性相当于一个会自动执行的方法,前提是触发这个事件的时候。

谨记:如果把上面的23行的事件绑定写成这样是错误的ele.onclick=fn();因为这样表示把fn方法运行后的返回值赋给了onclick事件,fn方法没有返回值,那这就是个错误的操作了。

下面是js中常见的事件

属性 当以下情况发生时,出现此事件
onabort 图像加载被中断
onblur 元素失去焦点
onchange 用户改变域的内容
onclick 鼠标点击某个对象
ondblclick 鼠标双击某个对象
onerror 当加载文档或图像时发生某个错误
onfocus 元素获得焦点
onkeydown 某个键盘的键被按下
onkeypress 某个键盘的键被按下或按住
onkeyup 某个键盘的键被松开
onload 某个页面或图像被完成加载
onmousedown 某个鼠标按键被按下
onmousemove 鼠标被移动
onmouseout 鼠标从某元素移开
onmouseover 鼠标被移到某元素之上
onmouseup 某个鼠标按键被松开
onreset 重置按钮被点击
onresize 窗口或框架被调整尺寸
onselect 文本被选定
onsubmit 提交按钮被点击
onunload 用户退出页面

DOM

DOM是什么

DOM 的全称为:Document Object Model 文档对象模型

每个网页其可以被认为是一个对象在浏览器窗口内部,当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model),文档对象表示将显示在该窗口的HTML文档。文档对象具有参考其他对象,允许访问文件的内容,以和修改各种性质。

HTML DOM 模型被构造为对象的树,如下图:

DOM 可以用来做什么

  • JavaScript 能改变页面中的所有 HTML 元素
  • JavaScript 能改变页面中的所有 HTML 属性
  • JavaScript 能改变页面中的所有 CSS 样式
  • JavaScript 能删除已有的 HTML 元素和属性
  • JavaScript 能添加新的 HTML 元素和属性
  • JavaScript 能对页面中所有已有的 HTML 事件作出反应
  • JavaScript 能在页面中创建新的 HTML 事件

DOM的常见操作

  1. 获取元素:
    • 通过 id 找到 HTML 元素
    • 通过标签名找到 HTML 元素
    • 通过类名找到 HTML 元素
getElementById  // document.getElementById("content")
getElementsByTagName // document.getElementsByTagName("table")[0]
getElementsByClassName // document.getElementsByClassName("null-input")[0]
querySelector // 推荐使用
querySelectorAll 
  1. 操作 CSS
    • 更改 color
    • 操作 border
    • 控制 margin
    • 注意问题:不能使用 border-color 的形式,而是换成驼峰形式 borderColor
tagDiv.onclick = function(){
  domDiv.style.width = "200px"
  domDiv.style.height = "200px"
  domDiv.innerHTML += "hello,world!"
}
  1. 事件(2种书写方式)
  • button.onclick = function() {} 注意这里不是驼峰形式
  • button.addEventListener("click", function() {}, useCapture)

BOM

BOM 是什么

BOM(Browser Object Model):浏览器对象模型。

在浏览器中的一些操作都可以使用 BOM 的方法进行编程处理。

比如:刷新浏览器、前进、后退、在地址栏输入 URL 等。

  • window

BOM 的顶级对象是:window , 我们常见的

window.alert();
window.prompt();
window.confirm(); // 两个按钮,分别返回 true 和 false。

通常,我们会省略 window ,写成 alert()

  • window.onload 页面加载对象

问题: 我们知道,如果将 script 标签放在 head 里面的话,页面加载的时候是先加载的 script 标签,之后才加载 body 里面的标签。如果 script 特别大的话,就很影响用户体验。

解决办法:

  • 将 script 标签放在 body 最后。
  • 使用 window.onload 事件。
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        window.onload = function () {
            document.getElementById("btn").onclick = function () {
                alert("haha");
            }
        }
    </script>
</head>
<body>
<input type="button" value="BUTTON" id="btn">
</body>

1、如果不写 window.onload 的话,执行到 document.getElementById("btn") 会报错,因为程序是从上至下执行。

2、window.onload 事件会在页面加载完毕(页面中所有内容、标签、属性以及外部引入的 js文件)时触发。

3、window.onload 可以省略 window。

  • 其他 BOM,不太常用,这里简单提一下:

    • window.open
    • window.location
    • window.history
    • window.navigator
    • window.screen
  • 定时器,有2个参数

    • setInterval(funtion() {}, time) 永久定时器
    • setTimeout(funtion() {}, time) 一次性定时器
    • window.clearInterval(id) 清除定时器
    • window.clearTimeout(id) 清除定时器

    具体例子 setInterval:

// setInterval

var intervalId = setInterval(function() {
  console.log(123)
}, 1000)


clearInterval(intervalId)

具体例子 setTimeout:

// setTimeout

var timeoutId = setTimeout(function() {
  console.log(123)
}, 1000)


clearTimeout(timeoutId)

使用 setTimeout 实现 setItnerval 的效果

function fn() {
    console.log('set')
}

while(true) setTimeout(fn, 1000)

JS中的类和对象

JavaScript中的类和对象是ES6之后才新增的,算是ES6的新特性,在ES6之前,都是通过构造函数和原型去模拟面向对象的类的一个实现机制,下面说一下类和对象的使用,和java中是大致相同 的。

创建对象

在JavaScript中,对象是一组有命名值(属性)集合的容器,常见的创建对象的方法是:

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
    <script>
       var object=new Object();
       object.age=13;
       object.lenth=22;
       object.height=33;
       console.log(object);
    </script>
</body>
</html>

最后可以看到相应的打印结果:

可以看到,对象只是一组无序的相关属性和方法的的容器,每个属性都有一个名称和一个值。所有的事务都是对象,例如字符串、数值、数组、函数等。

刚才声明的对象是只有静态信息的,为了使对象具有功能,可以在其中添加自己的函数方法,在JavaScript中,方法是包含Funcation()对象的属性,器目的是对函数内部的对象进行操作。

<script>
    var object=new Object();
    object.age=13;
    object.lenth=22;
    object.height=33;
    object.getAge=function(){
   	 	return this.age;
	}
	console.log(object.getAge());
</script>

可以看到getAge方法是object对象的一个属性,用于返回object的age属性值。在对象中,如果没有方法属性,那对象就只能用来存储静态信息,其实创建的object对象就是实例化了Object类,声明了一个对象,接下来看一下声明类的方法。

JavaScript中,有9个原生的对象构造函数,JavaScript使用这些对象来构建JavaScript语言,原生对象构造函数是多方面的,它可以生成对象,但也被用于促进语言的编程约定的额形成。例如,函数是Funcation()构造函数创建的对象,但是作为构造函数,使用new关键字调用之后,他们也可以创建爱你其他的对象。

JavaScript预包装了9个原生对象构造函数:

  • Number()
  • String()
  • Boolean()
  • Object()
  • Array()
  • Funcation()
  • Date()
  • RegExp()
  • Error()

JavaScript主要是由这九个对象(以及字符串、数字和布尔原始值)来创建的。

创建类

语法:

class name{
 	//class body
}

下来做一个demo来展示类的创建和使用,和java之中大多数是差不多的

<html>
<head>
<title>Document</title>
</head>
<body>
<h1>创建类</h1>
<p>创建人类</p>
    <script>
        // 创建类class 创建一个person类
        class Person{
            constructor(name,age){
                this.name=name;
                this.age=age;
            }
        }
        var lm=new Person("李明",23);
        var zs=new Person("张三",24);
        console.log(lm.name+"的年龄是"+lm.age);
        console.log(zs);
    </script>
</body>
</html>

在浏览器的控制台可以看到输出,输出成功,一个简单的类的创建与使用就完成了

其实在类的创建以及使用的时候,可以看出,基本上和java中类的创建与使用是差不多的,总结为以下几点

  1. 通过class关键字创建类,类名需要习惯性的大写
  2. 类里面有个construction函数,是可以接收传递过来的参数,同事返回实例对象
  3. construction函数是每次在new生成新的实例的时候,就会自动取调用的,如果不能主动声明这个方法的话,在新建实例的时候会默认使用一个无参数的构造方法
  4. 生成实例的时候,不能省略new
  5. 最后注意语法规范,创建类的时候,类名厚不加小括号,生成实例的时候类名后要加小括号,个构造函数不需要加function

在类中添加方法

方法也是一种属性,可以在类中添加方法,声明类的实例化对象之后,就可以通过对象去调用声明的方法。

	<script>
        // 创建类class 创建一个person类
        class Person{
            constructor(name,age){
                this.name=name;
                this.age=age;
            }
            say(message){
                console.log(message+this.name);
            }
        }
        var lm=new Person("李明",23);
        var zs=new Person("张三",24);
        lm.say("my name is");
        zs.say("my name is")
    </script>

写在类中的方法是不需要写funcation的。多个函数之间也不需要用逗号分隔。

类的继承

类的继承其实和java中也大相径庭,JavaScript中继承有六种方式

先创建一个父类

// 创建类class 创建一个父类
class Father{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    say(){
        return this.name + "爸爸的年龄是" + this.age;
    }
}

写一个子类继承

class Son extends Father{
    constructor(name,age){
        super(name, age);  //调用了父类中的构造函数,将参数传至父类中的say方法中
    }
}
var son=new Son('十三', 24);
alert(son.say());   //十三爸爸的年龄是24

可以看到,继承后,子类可以拥有父类的所有属性,就可以调用say方法了,并且可以通过super关键字讲参数传入say()方法中。

下面改写一下子类,也加一个自己的say()方法

class Son extends Father{
    constructor(name,age){
        super(name, age);  //调用了父类中的构造函数,将参数传至父类中的say方法中
        //constructor里面的this指向的是新创建的实例对象
        this.name=name;
        this,age=age;
    }
    say() {
        console.log(this.name + "的年龄是" + this.age);
        return this.name + "的年龄是" + this.age;
    }  
    fatherSay(age) {
        super.age= age;   //将父类的参数传入
        return super.say();//调用父类方法并返回
    }
}
var son=new Son('十三', 24);   
console.log(son.say());   //十三的年龄是24
//可以看到子类执行的时候执行了自己的say()方法,在子类执行自己的构造函数的时候,会默认执行参数的传参操作

继承中属性或者方法的的查找原则--就近原则

  1. 继承中,如果实例化子类输出一个放大,先看看子类中有没有这个方法,如果有就先执行子类的方法
  2. 继承中,如果子类没有,就会去查找父类有没有这个方法,如果有,就会执行父类这个方法

子类继承了父类之后,除了可以使用继承的属性和方法之外,还可以定义自己的属性与方法。这里不多赘述。

注意点:

  1. 在ES6中是没有变量提升的,所以必须先定义类,才能进行实例化
  2. 类中的公有的属性和方法一定要加this才能进行使用。
  3. 类里面的this指向,一般来说方法中的this都指向方法的调用者,比如说constructor里面的this指向的是新创建的实例对象

jQuery

jQuery 是什么

jQuery库可以通过一行简单的标记被添加到网页中去

什么是 js 库?

JavaScript 开发的过程中,处理浏览器的兼容很复杂而且很耗时,于是一些封装了这些操作的库应运而生。这些库还会把一些常用的代码进行封装。

把一些常用到的方法写到一个单独的 js 文件,使用的时候直接去引用这js文件就可以了,这个 js 文件就是 JavaScript 库。

什么是jQuery?

jQuery 就是一个 JavaScript 函数库,它可以通过一行简单的标记被添加到网页中去。没有什么特别的。里面封装了一大堆的方法方便我们的开发,因此我们学习jQuery,其实就是学习jQuery这个 js 文件中封装的一大堆方法。

jQuery包含的功能

jQuery就是一个js库,基本上就是为了更方便的完成js要实现的功能,极大地简化了JavaScript的编程,大致如下:

  • HTML元素选取
  • HTML元素操作
  • CSS操作
  • HTML事件函数
  • JavaScript特效和动画
  • HTML DOM遍历和修改
  • AJAX
  • Utilities(工具类)

如何引入jQuery

  1. jQuery 库位于一个 JavaScript 文件中,其中包含了所有的 jQuery 函数,可以从jquery.com下载jQuery库,然后引入页面

    <head>
    <script type="text/javascript" src="jquery.js"></script>
    </head>
    //请注意,<script> 标签应该位于页面的 <head> 部分。
    
  2. 从CDN中载入jQuery,谷歌、百度、微软等服务器中都有jQuery,直接引入就可以了

    使用 Google 的 CDN

    <head>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs
    /jquery/1.4.0/jquery.min.js"></script>
    </head>
    

    使用 Microsoft 的 CDN

    <head>
    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery
    /jquery-1.4.min.js"></script>
    </head>
    

    使用 百度 的 CDN

    <head>
    <script type="text/javascript" src="http://lib.baidu.com/jquery
    /jquery-1.4.min.js"></script>
    </head>
    

jQuery的语法

jQuery 语法是为 HTML 元素的选取编制的,可以对元素执行某些操作。

基础语法是:$(selector).action()

  • 美元符号定义 jQuery
  • 选择符(selector)“查询”和“查找” HTML 元素
  • jQuery 的 action() 执行对元素的操作

jQuery选择器

jQuery元素选择器

jQuery 使用 CSS 选择器来选取 HTML 元素的。

基础选择器

<div id="test" class="test">hello world</div>

// id 选择器
var id = $("#test")
console.log(id) // "hello world"

// 类选择器
var cls = $(".test")
console.log(cls) // "hello world"

// 标签选择器,选择所有符合条件的标签
var div = $("div")
console.log(div) // "hello world"

复合选择器

<div id="test">
  <p>hello,world</p>
  <span>hello,sss</span>
</div>

$("div,p,span") // 并集选择器,获取多个元素
$("div#test") // 交集选择器,获取 所有的id 为 test 的div元素
$("div p") // 后代选择器,获取 div 的后代元素 p
$("div:odd") // 获取第奇数个 div 标签
$("div:even") // 获取第偶数个 div 标签

jQuery 属性选择器

jQuery 使用 XPath 表达式来选择带有给定属性的元素。

$("[href]") 选取所有带有 href 属性的元素。

$("[href='#']") 选取所有带有 href 值等于 "#" 的元素。

$("[href!='#']") 选取所有带有 href 值不等于 "#" 的元素。

$("[href$='.jpg']") 选取所有 href 值以 ".jpg" 结尾的元素。

jQuery CSS 选择器

jQuery CSS 选择器可用于改变 HTML 元素的 CSS 属性。

有两种写法,链式写法和键值对写法

//链式写法
$("#father").css("border","1px solid black").css("color", "red")


//键值对写法
var divCss = {
  border: "1px solid black",
  color: "red"
}
$("#father").css(divCss)

jQuery事件

常用事件方法

//JS中事件有两种写法,可以和jQuery中做一下对比
// 对比 js 的事件1
button.onclick = function() {}
// 对比 js 的事件2 
button.addEventListener("click", function() {}, false)

// jQuery 常用的事件
$(document).ready(function)     //文档加载完成时候出发的事件
$("#btn").click(function)     //获取点击事件
$("#btn").dbclick(function)   //获取双击事件
$("span").mouseenter(function)    //鼠标指针进入(穿过)元素
$("span").mouseleave(function)   //鼠标离开元素
$("span").hover(function)      //鼠标悬停
$("span").focus(function) // 触发或将函数绑定到被选元素的获得焦点事件
$("span").blur(function) // 触发或将函数绑定到被选元素的失去焦点事件

事件的绑定与解除

bind() 方法为被选元素添加一个或多个事件处理程序,并规定事件发生时运行的函数。

unbind() 方法为被选元素解除一个或多个事件处理程序

在jquery1.7之后,官方是建议使用on和off来替代bind和unbind的。是都可以使用的,效果以及语法都一样

基本的语法是:

$(selector).bind(event,data,function)
$(selector).unbind(event,data,function)

event: 必需。规定添加到元素的一个或多个事件。由空格分隔多个事件。必须是有效的事件。

data: 可选。规定传递到函数的额外数据。

function:必需。规定当事件发生时运行的函数。

示例:

<html>
<head>
<script type="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
  $("button").bind("click",hide);  //将事件绑定到元素上
  $("button").unbind("click"); //将事件解除绑定,不加function参数的话会解除该元素上所有的click
});
function hide(e){
	$("p").slideToggle();
}
</script>
</head>
<body>
<p>这是一个测试类</p>
<button>请点击这里</button>
</body>
</html>

事件的目标

event

标准Event属性:

属性和方法 描述
bubbles 返回布尔值,指示事件是否是起泡事件类型。
cancelable 返回布尔值,指示事件是否可拥可取消的默认动作。
currentTarget 返回其事件监听器触发该事件的元素。
eventPhase 返回事件传播的当前阶段。
target 返回触发此事件的元素(事件的目标节点)。
timeStamp 返回事件生成的日期和时间。
type 返回当前 Event 对象表示的事件的名称。
initEvent() 初始化新创建的 Event 对象的属性。
preventDefault() 通知浏览器不要执行与事件关联的默认动作。
stopPropagation() 不再派发事件。

事件的冒泡

// 方法1  event.stopPropagation()   阻止父级的冒泡事件
// 方法2  event.stopImmediatePropagation()   阻止所有的冒泡事件
// 方法3  return false;    //相当于程序直接返回,事件被终止

自定义事件

jQuery.Event("MyEventName");

${"#btn"}.trrigger(e);

AJAX

Ajax

ES6

ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的新一代版本标准,2015.06 发版。

ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念,但是目前浏览器的 JavaScript 是 ES5 版本,大多数高版本的浏览器也支持 ES6,不过只实现了 ES6 的部分特性和功能。

ES6主要有以下一些特性

定义变量

let

let和const是ES6中新增加的两个关键字,用来声明变量,在此之前声明变量只有var,let和const都是块级作用域。

let 允许创建块级作用域,ES6 推荐在函数中使用 let 定义变量,而非 var:

{
  var a = 2;
  let b = 3;
  console.log(a); // 3
}
console.log(a); // 2 
console.log(b); // ReferenceError: b is not defined

const

同样在块级作用域有效的另一个变量声明方式是 const,它可以声明一个常量。ES6 中,const 声明的常量类似于指针,它指向某个引用,也就是说这个常量并非一成不变的,如:

{
  const arr = [5,6];
  arr.push(7);
  console.log(arr); // [5,6,7]
  arr = 10; // Assignment to constant variable.
}

有几个点需要注意:

  • let 关键词声明的变量不具备变量提升(hoisting)特性
  • let 和 const 声明只在最靠近的一个块中(花括号内)有效
  • 当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
  • const 在声明时必须被赋值

解构赋值

ES6中可以按照一定的模式从数组和对象中提取出来值,对变量进行赋值,这种就是解构

//数组解构
let [a,b,c] =[1,2,3];
a  //1
b  //2
c  //3

//数组嵌套赋值
let [a, [[b], c]] = [1, [[2], 3]];
a // 1
b // 2
c // 3

//上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。


//对象解构
let name='Tom';
let age='13';
let student={name,age};
student  //{name: "Tom", age: "13"}

//对象解构
let student={name: "Tom", age: "13"};
let{name,age}=student;
name   //Tom
age    //13
//数组解构和对象解构差不多,只要模式匹配都可以进行解构赋值

这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值.

还有就是如果等号两边模式不相等,还会有省略赋值和不定参数赋值

//省略赋值
let [ , , c] = [1, 2,3];
c // 3

let [a, , c] = [1, 2, 3];
a // 1
c // 3
//不赋值的位置可以不用变量接收,直接用空白代替就可以了

//不定参数赋值,使用...来表示不定参数,...是扩展运算符,可以将一个数组转成用逗号分隔的形式
let [a, ...b] = [1, 2, 3, 4];
a // 1
b // [2, 3, 4]

let [a,b, ...c] = ['a'];
a // "a"
b // undefined
c // []

如果解构不成功,变量的值就等于undefined

解构不成功说的是右边没有左边对应的值,比如说

let [a,b,c] = [1, 2];
a // 1
b // 2
c // undefined
//c就是解构不成功,因为右边的数组里没对应的值

还有一种是左边没有右边对应的值,这种是不完全解构,是可以解构成功的

let [a,b] = [1, 2,3];
a // 1
b // 2

函数问题

箭头函数(Arrow Functions)

ES6 中允许使用“ =>”来定义函数,使用括号包裹参数,跟随一个 =>,紧接着是函数体,不需要function关键字也可以省略return关键字:

var getPrice = a => a+1;
//等价于
var getPrice = function() {
  return a+1;
};

这个例子中的 getPrice 箭头函数采用了简洁函数体,它不需要 return 语句,下面这个例子使用的是正常函数体:

let arr = ['apple', 'banana', 'orange'];
 
let breakfast = arr.map(fruit => {
  return fruit + 's';
});
 
console.log(breakfast); // apples bananas oranges

当然,箭头函数不仅仅是让代码变得简洁,函数中 this 总是绑定总是指向函数定义时候所在的上下文对象,而不是函数执行之后调用它的上下文对象。具体可以看看下面几个例子:

function Person() {
  this.age = 0;
  setInterval(function growUp() {
    // 在非严格模式下,growUp() 函数的 this 指向 window 对象
    this.age++;
  }, 1000);  //每秒给age加一
}
var person = new Person(); 

我们经常需要使用一个变量来保存 this,然后在 growUp 函数中引用:

function Person() {
  var self = this;
  self.age = 0;
 
  setInterval(function growUp() {
    self.age++;
  }, 1000);
}

而使用箭头函数可以省却这个麻烦:

function Person(){
  this.age = 0;
 
  setInterval(() => {
    // |this| 指向 person 对象
    this.age++;
  }, 1000);
}
 
var person = new Person();

函数参数默认值

ES6 中允许你对函数参数设置默认值:

let getFinalPrice = (price, tax=0.7) => price + price * tax;
getFinalPrice(500); // 850

模板字符串

模板字符串是增强版的字符串,会用反引号(`)来标识字符串,除了可以当做普通的字符串之外,还可以用来定义多行的字符串,以及在字符串中嵌入变量。

const  str1= `正常的字符串`;
const  str2= `多行的
			  字符串`;
let name='十三';
const str3=`hello,${name}`;

set和map

Map 和 WeakMap

ES6 中两种新的数据结构集:Map 和 WeakMap。事实上每个对象都可以看作是一个 Map。

创建map的方法:

  1. 使用构造函数的方式创建一个实例
  2. 参数是个数组,数组的每一项都是一个数组,这个数组有两项,分别对应map的key和value,这个就和java中的map的概念一样了
  3. 在 Map 中,任何类型都可以作为对象的 key

如:

var map = new Map();
 
var keyString = "a string",
    keyObj = {},
    keyFunc = function () {};
 
// 设置值
map.set(keyString, "value 与 'a string' 关联");
map.set(keyObj, "value 与 keyObj 关联");
map.set(keyFunc, "value 与 keyFunc 关联");
 
map.size; // 3
 
// 获取值
map.get(keyString);    // "value 与 'a string' 关联"
map.get(keyObj);       // "value 与 keyObj 关联"
map.get(keyFunc);      // "value 与 keyFunc 关联"

//删除值
map.delete(keyString);  

//查看是否存在
map.has(keyString); //false

//清空map
map.clear();

//遍历map

map.forEach((key,val,map)=> {
    //val :内容
    //key :键值
    //map: 原Map实例
    
    //参数顺序不能乱,第一个代表内容,第二个是键值,第三个是实例
});


for(var key of map.keys()){
    //遍历键值
}
for(var val of map.values()){
    //遍历内容
}

for(var [key,val] of map.entries){
    //遍历键值和内容
}

WeakMap

WeakMap 就是一个 Map,只不过它的所有 key 都是弱引用,意思就是 WeakMap 中的东西垃圾回收时不考虑,使用它不用担心内存泄漏问题。

另一个需要注意的点是,WeakMap 的所有 key 必须是对象。它只有四个方法 delete(key),has(key),get(key) 和set(key, val):

let w = new WeakMap();
w.set('a', 'b'); 
// Uncaught TypeError: Invalid value used as weak map key
 
var o1 = {},
    o2 = function(){},
    o3 = window;
 
w.set(o1, 37);
w.set(o2, "azerty");
w.set(o3, undefined);
 
w.get(o3); // undefined, because that is the set value
 
w.has(o1); // true
w.delete(o1);
w.has(o1); // false

Set 和 WeakSet

Set 对象是一组不重复的值,重复的值将被忽略,值类型可以是原始类型和引用类型:

let mySet = new Set([1, 1, 2, 2, 3, 3]);
mySet.size; // 3
mySet.has(1); // true
mySet.add('strings');
mySet.add({ a: 1, b:2 });

可以通过 forEach 和 for...of 来遍历 Set 对象:

mySet.forEach((item) => {
  console.log(item);
    // 1
    // 2
    // 3
    // 'strings'
    // Object { a: 1, b: 2 }
});
 
for (let value of mySet) {
  console.log(value);
    // 1
    // 2
    // 3
    // 'strings'
    // Object { a: 1, b: 2 }
}

Set 同样有 delete() 和 clear() 方法。

WeakSet

类似于 WeakMap,WeakSet 对象可以让你在一个集合中保存对象的弱引用,在 WeakSet 中的对象只允许出现一次:

var ws = new WeakSet();
var obj = {};
var foo = {};
 
ws.add(window);
ws.add(obj);
 
ws.has(window); // true
ws.has(foo);    // false, foo 没有添加成功
 
ws.delete(window); // 从结合中删除 window 对象
ws.has(window);    // false, window 对象已经被删除

Promise

ES6 对 Promise 有了原生的支持,一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者rejected。

var p = new Promise(function(resolve, reject) {  
  if (/* condition */) {
    // fulfilled successfully
    resolve(/* value */);  
  } else {
    // error, rejected
    reject(/* reason */);  
  }
});

每一个 Promise 都有一个 .then 方法,这个方法接受两个参数,第一个是处理 resolved 状态的回调,一个是处理 rejected 状态的回调:

p.then((val) => console.log("Promise Resolved", val),
       (err) => console.log("Promise Rejected", err));

Class

JavaScript中的类和对象是ES6之后才新增的,算是ES6的新特性,在ES6之前,都是通过构造函数和原型去模拟面向对象的类的一个实现机制,下面说一下类和对象的使用,和java中是大致相同 的。

迭代器

迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素是,迭代器便会退出。它提供了 next() 函数来遍历一个序列,这个方法返回一个包含 done 和 value 属性的对象。

ES6 中可以通过 Symbol.iterator 给对象设置默认的遍历器,无论什么时候对象需要被遍历,执行它的 @@iterator 方法便可以返回一个用于获取值的迭代器。

数组默认就是一个迭代器:

var arr = [11,12,13];
var itr = arr[Symbol.iterator]();
 
itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }
 
itr.next(); // { value: undefined, done: true }

你可以通过 Symbol.iterator自定义一个对象的迭代器。

Symbol

Symbol 是一种新的数据类型,它的值是唯一的,不可变的。ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符:

var sym = Symbol( "some optional description" );
console.log(typeof sym); // symbol

注意,这里 Symbol 前面不能使用 new 操作符。

如果它被用作一个对象的属性,那么这个属性会是不可枚举的:

var o = {
    val: 10,
    [ Symbol("random") ]: "I'm a symbol",
};
 
console.log(Object.getOwnPropertyNames(o)); // val

如果要获取对象 symbol 属性,需要使用Object.getOwnPropertySymbols(o)。

posted @ 2020-05-06 00:07  张十三S  阅读(271)  评论(0编辑  收藏  举报