小饶学编程之JAVA SE第二部分——Web 前端基础:10JavaScript

1. JavaScript概述

1.1 历史

JavaScript是世界上最流行的脚本语言。1994年,网景公司(Netscape)发布了Navigator浏览器0.9版。这是历史上第一个比较成熟的网络浏览器,轰动一时。但是,这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。网景公司的整个管理层,都是Java语言的信徒,Sun公司完全介入网页脚本语言的决策。因此,Javascript后来就是网景和Sun两家公司一起携手推向市场的,这种语言被命名为"Java+script"并不是偶然的。

此时,34岁的系统程序员Brendan Eich登场了。仅仅一个月之后,1995年5月,网景公司做出决策,未来的网页脚本语言必须"看上去与Java足够相似",但是比Java简单,使得非专业的网页作者也能很快上手。Brendan Eich被指定为这种"简化版Java语言"的设计师。但是,他对Java一点兴趣也没有。为了应付公司安排的任务,他只用10天时间就把Javascript设计出来了

在这里插入图片描述

ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaScript,所以它可以理解为是JavaScript的一个标准,但实际上后两者是ECMA-262标准的实现和扩展。目前主流版本为ES6。

1.2 JavaScript组成
  • 核心语法(ECMAscript)
  • 文档对象模型 (DOM Docuemtn Object Model) ,JS与HTML文档交互。
  • 浏览器对象模型(BOM Browser Object Model),JS与游览器交互。
1.3 JavaScript特征

JavaScript是一种解释型脚本语言,或者动态语言。是一种弱类型语言,意味着里面的类型可以变化。

  • 编译型语言,需要经历编写-编译-链接-运行。比如java、c++等。

  • 解释型语言,解释型语言没有编译结果

2. JavaScript基础语法

2.1 JS的引入

HTML中有3种方式写入JS代码。

  • 写在标签属性

    <a href="#" onclick="alert('hello world')">点击我</a>
    
  • 写在script标签中

    <script type="text/javascript">			
        alert("hello world...");			
    </script>
    
  • 写在外部的JS文件中

    js/hello.js

     alert("hello world...");	
    

    index.html

    <!-- 注意:即使标签中没有内容也不能写成自闭合的 -->
    <script src="js/hello.js" type="text/javascript"></script>
    
2.2 注释

JS中的注释同Java。

  • // 单行注释
  • /* */ 多行注释
  • /** */ 多行注释
2.3 变量

变量是用来存储数据的,操作变量来间接操作内存中空间的数据。由于JS是弱类型语言,变量类型是动态的,故定义的时候不需要定义变量类型,使用var即可。

  • 变量命名规范:

    • 不允许使用js关键字和保留关键字
    • 可以包含字母、数字、下划线_以及$
    • 变量名不能以数字开头
    • 可以用中文,但是不推荐使用
    • 见名知意(驼峰)
  • 变量的声明提前

    所有变量的声明,会自动提升到代码(当前作用域)的最顶部。声明提前破坏了程序的执行顺序,所以大家知道原理即可,切勿在实际开发过程中使用,不仅会降低代码可读性,还容易造成程序错误。

    1 console.log(a);               //undefined
    2 var a; // 这行代码相当于插入到最开始
    3 a=10;
    4 console.log(a
    
2.4 调试
  • alert将数据弹出
  • document.write();在文档内输出
  • console.log在游览器的控制中输出
  • 在游览器的开发控制台的Sources面板中断点调试
2.5 流程控制

条件分支跟循环参考Java,此处省略。

2.6 关键字跟保留字

JS中我们在命名规范中不能使用系统的关键字跟保留字。

  • 关键字
    在这里插入图片描述

  • 保留字

在这里插入图片描述

3. 数据类型

变量没有类型,但是值有类型,可以通过typeof运算符检查值类型。

var i = 1 ;
console.log(typeof i );
  • 原始类型(基本类型):按值访问,可以操作保存在变量中实际的值。原始类型汇总中null和undefined比较特殊,5种。

  • 引用类型:引用类型的值是保存在内存中的对象。

在这里插入图片描述

3.1 基本数据类型
3.1.1 number

数字类型,既可以表示整数,也可以表示小数。

123 //整数
123.1 //小数
1.1e3 // 科学计数法
-9 // 负数
NaN // not a number 
Infinity // 无穷大
-Infinity // 负无穷大
0x11a // 16进制
0755 // 8进制
0b10101 // 2进制
  • NaN不等于任何值,包括它自身。所以只能通过全局函数isNaN()来判断。
  • Infinity比任何数字都要大。
  • -Infinity比任何数字都要小。
3.1.2 string
  • 字符串表示一段文本符号数据。由字符、数字、符号、特殊字符等组成。JS中的字符串可以用单引号也可以使用双引号。

    "hello"
    'hello \n world'
    
  • 字符串模板:模板字符串是ES6增加的用于定于字符串的新特性,支持字符串直接换行而不需要转义,且支持插值 ${}

    var name = "seven";
    		   
    var msg = ` 你好,
    	${name} `;
    
3.1.3 boolean
  • 布尔类型,只有truefalse2个值,表示结果是真还是假。
  • boolean也可以进行算术运算,true当做1,false当做0。
3.1.4 undefined

表示未定义。

3.1.5 null

表示空,不存在。从逻辑角度上看,null是一个空的对象指针。而这也正是使用typeof操作符检测null值,会返回“object”的原因。

3.2 引用数据类型

也就是对象类型Object type,比如:Object 、Array 、Function 、Data等,以及自定义的。

object

对象,是一组数据和功能(函数)的集合。可以用new操作符后跟要创建的对象类型的名称来创建。也可以用字面量表示法创建。

var person = {name:'zhangsan'} // 方式1: 字面量的方式
var obj1= new Object();        // 方式2: 构造方法

4. 运算符

算术运算符

+ - * / % ++ --``**

  • +用在字符串上表示字符串的拼接。

  • 可以通过()改变运算的优先级。

  • 浮点数也有小尾巴的问题(0.1 + 0.2 ),尽量避免。可以使用number的toFixedf方法来四舍五入。

  • ++ -- 只能作用在变量上,不能作用在值上面。

  • /除数为0,结果是无穷

    console.log(-1/0); // -Infinity
    console.log(1/0);  // Infinity
    console.log(0/0)   //  NaN
    console.log(isNaN(0/0))  // true
    
  • **表示计算幂,优先级比较高

    console.log(3**4); // 81
    console.log(-3**3); // 报错
    console.log((-3)**3); // -27
    console.log(-(3**3)); // -27
    
比较运算符

比较运算符的结果是一个boolean类型。

> < >= <= 用法同JAVA

  • ==

    等于,js中==只判断2个值是否相等,不考虑类型。

    "1" == 1  // true
    1 == true   // true
    0 == false   // true
    null == undefined // true
    NaN == NaN // false
    
  • ===

    绝对等于,js中用来判断值跟类型都必须相同。

    "1" === 1  // false
    "1" === "1"  // true
    NaN === NaN // false
    
逻辑运算符

逻辑运算符同java中逻辑运算符,也具有短路功能。结果是一个boolean类型。

&&  2个都为真则为真
||  有一个为真则为真
!  真即假,假即真

5. 函数

JS中通过函数来把一段逻辑封装用来重复使用。函数式通过关键字function来定义的。

  • JS中的函数不需要定义返回类型,直接返回结果即可
  • JS中的函数参数列表不需要定义类型以及var,只需定义变量名
  • 函数需要调用才会执行,不调用是不会执行的
  • 函数没有重载,只要方法名相同就会去执行,不管参数列表匹配与否
  • 如果定义了多个方法名相同,后面覆盖前面的
5.1 函数的定义

定义方式一

/* 语法
function 函数名(参数列表){ 
    函数体;
}*/

function study(){
    console.log("好好学习,天天向上。");
}

定义方式二

/* 语法
var  函数名 = function(参数列表){ 
    函数体;
}*/

var study = function(){
    console.log("好好学习,天天向上。");
}

定义方式三(不推荐)

/*
	语法:参数跟函数体都必须在字符串内,Function的F必须大写
new Function(arg1, arg2, ..., argN, function_body);
*/

var study = new Function("name", "time","console.log(name+'每天学习'+time+'分钟');console.log('继续保持')");
5.2 函数的调用

函数的调用(方式一)

/* 
语法: 函数名(参数值)
*/
study("seven",180);

函数的调用(方式二)

/*
语法: 函数名.call(调用对象,参数值)
*/
study.call(this,"seven",180 );

函数的调用(方式三)

/*  
参数需要封装到数组中
语法: 函数名.apply(调用对象,参数值数组)
*/
study.apply(this,['seven',120]  );

函数的调用(方式四)

/*
bind会返回新的函数,需要调用才会执行,所以后面需要(),其它跟call用法一样。
语法: 函数名.bind(调用对象,参数值)()
*/
study.bind(this,"seven",180 )();
5.3 函数参数

JS中的参数都会封装到arguments中,在函数体中可以通过这个参数拿到定义参数以外的参数值。

var study = function(name , time){
    // 传统方式只能拿到定义的参数
    console.log(name);
    console.log(time);
    // 通过arguments可以定义参数以外的参数
    console.log(arguments.length);
    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(arguments[2]);
    console.log(arguments[3]);
    
    console.log(name+'每天学习'+time+'分钟');
}

study("zhangsan",180,1,"a");

ES6也支持类似Java中的可变长度参数

var study = function(name , time ,  ... args){
    console.log(args);
}

6. 数组

用来装元素的集合。

  • JS中的数组中的类型可以不一样。
  • JS中数组下标越界不会异常,访问会返回 undefined
数组的定义
// 方式1 
var arr1 = [1,2,3,true,2.1,'hello',null ];
// 方式2 
var arr2 = new Array(1,2,3,true,2.1,'hello',null);

console.log(arr1[100]);// undefined

7. 对象

JS中的对象分为3类:

  • 内置对象(ArrayBooleanDateFunctionGlobalMathNumberObjectRegExpErrorString
  • 宿主对象(BOM/DOM
  • 自定义对象
内置对象
  • String
    var s = "hello js world ...";
    
    console.log(s.length);// length属性表示字符串长度
    console.log(s[1]);// 可以通过具体的下标访问数组中的字符
    s.toUpperCase();// 转换成大写
    s.toLowerCase();// 转换成小写
    s.indexOf('e')// 获取字符e出现的位置
    s.substring(3,5)// 获取子字符串
    
    
  • Array
    var arr = [1,2,3,4,5];
    
    console.log(arr.length);// length属性表示数组元素个数
    arr.length = 2 ; // 设置长度减小,表示只保留前面的2个元素,剩余的丢掉
    arr.length = 10 ;// 会增加5个元素,增加的都是undefined值
    arr.indexOf(3)//返回元素3的索引,如果没有返回-1
    arr.slice(3,6)// 截取子数组,类似String的subString
    arr.push("a","b","c") // 往数组尾部添加元素
    arr.pop(); // 把数组的尾部最后一个元素弹出,也就是删除
    arr.unshift("f"); // 往数组头部添加元素
    arr.shift(); // 把数组的头部第一个元素弹出,也就是删除
    arr.sort();  // 把数组进行排序
    arr.reverse();  // 把数组元素进行反转
    arr.concat(['a','b','c']); // 把新的数组拼接在元素后,会返回新的数组,并没改变原数组
    arr.join("-")// 把数组中的所有元素拼接在一起,使用设置的分隔符。
    
    // 数组的遍历
    arr.forEach(function(value){
        console.log(value);
    });
    
    // 数组的遍历,这里的index是数组中的索引
    for(var index in arr){
        console.log( arr[index]);
    }
    
    // 数组的遍历,这里的e是数组中的元素
    for(var e of arr){
        console.log( e);
    }
    
  • Date
    var d = new Date();// 定义日期类型
    console.log(d);// 打印当前日期
    console.log(d.getFullYear());// 获取年份
    console.log(d.getMonth());// 获取月份
    console.log(d.getDate());// 获取日
    console.log(d.getDay());// 获取星期几
    console.log(d.getHours());// 获取小时
    console.log(d.getMinutes());// 获取分
    console.log(d.getSeconds());// 获取秒
    console.log(d.getTime());// 获取时间戳
    console.log(d.toLocaleString());// 获取本地日期 
    console.log(d.toLocaleDateString());// 获取本地日期,只有年月日
    
  • JSON

    JSON(JavaScript Object Notation)(http://www.json.org/) 是一种轻量级的数据交换格式。 JSON中支持2种数据格式:对象跟数组2种数据。具体支持的值类型有数字、字符串、boolean、null

    • 对象用花括号表示{}

    • 数组用中括号表示[]

    • 数据表现为键值对用:隔开

    • 同级数据用,号隔开

      // json对象
         { "name":"seven","age":"18"}
      // json数组,数组里面的元素是对象
         [
          {“name”:"张三","age":"21"},
          {“name”:"李四","age":"22"} 
         ]
      

    JSON跟JS对象的区别

区别JSONJavascript
含义仅仅是一种数据格式表示类的实例
传输可以跨平台数据传输,速度快不能传输
表现1.简直对方式,键必须加双引号 2.值不能是方法函数,不能是undefined/NaN1.键值对方式,键不加引号 2.值可以是函数、对象、字符串、数字、boolean 等
  • JS对象转JSON

    var user = {
        name:"zhangsan",
        age:18,
        sex:"男"
    };
    
    // js对象转JSON对象(JSON.stringify)
    var json = JSON.stringify(user);
    console.log(json); //{"name":"zhangsan","age":18,"sex":"男"}
    
  • JSON转JS对象

    var user = JSON.parse('{"name":"zhangsan","age":18,"sex":"男"}');
    console.log(user);
    
自定义对象
对象的定义
  • 方式1(字面量)

    // 大括号{}表示一个对象
    var user = {
    		name:"zhangsan",
    		age:17,
    		sleep:function(){
    			console.log("sleeping ... ");
    		}
    	};
    
    
  • 方式2(Object)

    var user = new Object();
    user.name = "zhangsan";
    user.age = 17 ;
    user.sleep = function(){
        console.log("sleeping ... ");
    }
    
    
  • 方式3(工厂模式)

    function createUser(name,age){
        var user = new Object();
        user.name = name ;
        user.age = age ;
        user.sleep = function(){
            console.log("sleeping ... ");
        };
        return user;
    };
    
    
  • 方式4(构造方法)

    // 构造方法名首字母大写,用以区分其他普通函数
    function User(name,age){
        this.name = name;
        this.age = age ;
        this.sleep = function(){
            console.log("sleeping ... ");
        };
    }
    
    var u1 = new User("zhang",111);
    
  • 方式5(Object.create)

    // 类似java中的clone
    var user1 = {name:"zhangsan",age:18};
    var user2 = Object.create(user1);
    
    
对象的使用
var person = {
    name:"zhangsan",
    age:19,
    sex:"男",
    sleep:function(){
        console.log("早睡早起身体好。");
    }    
    
  • 属性的访问跟赋值

    person.name 
    person["name"]
    person.name = "seven";
    person["name"] = "seven";
    
    person.height // 使用对象的一个不存在的属性不会报错,undefined
    
  • 动态的删除属性

    delete person.name ;// 动态的删除person对象的name属性
    
  • 动态的添加属性

    person.hello = "hello";// 直接给新的属性赋值即可
    person.eat =function(){console.log("吃");} // 函数也一样。
    
  • 判断属性是否在这个对象中

    'name' in person  // 判断name属性是否存在person对象或者父类对象中。
    'sleep' in person // 判断sleep函数是否存在person对象或者父类对象中。
    person.hasOwnProperty("name");// 判断name属性是否存在person对象中,不包括父类的
    person.hasOwnProperty("sleep");// 判断sleep函数是否存在person对象中,不包括父类的
    

8. 原型与原型链

​ 我们先通过构造函数创建一个对象

function Person() {

}
//Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person
var person = new Person();

person.name = 'seven';
console.log(person.name) // seven

JS在创建对象的时候都会创建对应类型的原型。

在这里插入图片描述

  • 当我们给Person添加属性跟方法的时候,可以添加在对象中,也可以添加在原型中。区别是对象中的属性是独立的,原型中的属性是所有对象共享的。

  • 当访问对象的属性跟方法时,先去对象中找,找不到再去原型中找。

    function Person() {
    
    }
    // 虽然写在注释里,但是你要注意:
    // prototype是函数才会有的属性
    Person.prototype.name = 'seven';
    var person1 = new Person();
    var person2 = new Person();
    console.log(person1.name) // seven
    console.log(person2.name) // seven
    
  • 每一个JS对象都有一个属性__proto__,这个属性会指向该对象的原型.

在这里插入图片描述

function Person() {

}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true
  • 每个对象跟原型都有一个 constructor 属性指向关联的构造函数实例原型指向构造函数。

在这里插入图片描述

function Person() {

}
console.log(Person === Person.prototype.constructor); // true
  • 原型也是一个特殊的对象,也有__proto__属性,默认指向Object.prototype

在这里插入图片描述

  • 我们访问对象的属性跟方法先去对象中找,找不到就去对应的原型上找,原型找不到再去父原型上面找,直到顶级原型Object.prototype。JS中是通过原型链来达到继承的效果。

    function Person() {
    
    }
    
    var person = new Person();
    
    Object.prototype.name = "seven";
    
    console.log(person.name) // seven
    

9. BOM

​ 浏览器对象模型 (Browser Object Model) 使 JavaScript 有能力与浏览器"对话"。

9.1 window

window 对象是BOM中所有对象的核心,除了是BOM中所有对象的父对象外,还包含一些窗口控制函数。

所有浏览器都支持 window 对象。它表示浏览器窗口。其它的BOM对象都是window对象的子对象。

全局变量是 window 对象的属性。

全局函数是 window 对象的方法。

// 定义的全局变量都默认是window属性
var a = "hello";
// 定义的全局函数都默认是window函数
function study(){
    console.log("好好学习,天天向上。");
}

// window可省略
console.log(a); // hello 
console.log(window.a);// hello 
window.study(); 
  • 窗口尺寸
    • innerHeight:浏览器窗口的内部高度。

    • innerWidth:浏览器窗口的内部宽度。

    • outerHeight:浏览器窗口外部高度。

    • outerWidth:浏览器窗口外部宽度。

      console.log(window.innerHeight); 
      console.log(window.innerWidth); 
      
      console.log(window.outerHeight); 
      console.log(window.outerWidth); 
      
  • 系统对话框
    • alert()确定提示框,只有一个确定按钮。

    • confirm():选择提示框,有确认跟取消按钮

    • prompt():输入提示框,可以输入值,有确认跟取消按钮。

      // 只有一个确定按钮
      alert("我很帅");
      
      // 有确认跟取消按钮
      var result = confirm("我是不是很帅");
      console.log(result); //  true/false
      
      // 可以输入值,有确认跟取消按钮
      var time = prompt("你今天学习了几个小时?",3);// 输入值默认初始值设置为3
      console.log(time); //  输入的值,点击取消结果为null
      
  • 定时器

    window 对象包含 4 个定时器专用方法,说明如下表所示,使用它们可以实现代码定时执行,或者延迟执行,使用定时器可以设计演示动画。

    方法说明
    setInterval()按照执行的周期(单位为毫秒)调用函数或计算表达式
    setTimeout()在指定的毫秒数后调用函数或计算表达式
    clearInterval()取消由 setInterval() 方法生成的定时器
    clearTimeout()取消由 setTimeout() 方法生成的定时器
    var i = 0 ;
    function printNowTime(){
        i++;
        console.log(new Date().toLocaleString());
    
        if(i>=3){
            // 清除这个定时器
            clearInterval(timer);
        }
    
    }
    
    // 每1000毫秒执行一次,一直执行
    var timer = setInterval(printNowTime,1000);
    
    var i = 0 ;
    function printNowTime(){
        i++;
        console.log(new Date().toLocaleString());
    
    
        // 递归,让一次性定时器一直执行.
        var timer = setTimeout(printNowTime,1000);
    
        if(i>=3){
            // 清除这个定时器
            clearTimeout(timer);
        }			
    			
    }
    
    printNowTime();
    
  • 窗口移动
    • moveBy():可相对窗口的当前坐标把它移动指定的像素。
    • moveTo():把窗口的左上角移动到一个指定的坐标。

    由于安全性的考虑,Chrome等游览器把这个功能屏蔽了。

    // 下面案例仅IE有效
    
    // 每秒运行一次
    window.onload = function () {
        timer = window.setInterval("jump()", 1000);
    }
    
    function jump () {
        // 把窗口大小改为200*200像素
        window.resizeTo (200, 200);
        // 随机一个X轴跟Y轴坐标
        x = Math.ceil (Math.random() * 1024);
        y = Math.ceil (Math.random() * 760);
        // 移动到这个位置
        window.moveTo(x, y);
    }
    
  • 打开窗口

    使用 window 对象的 open() 方法可以打开一个新窗口。

    window.open (URL, name, features, replace)

    参数列表如下:

    • URL:可选字符串,声明在新窗口中显示网页文档的 URL。如果省略,或者为空,则新窗口就不会显示任何文档。
    • name:可选字符串,声明新窗口的名称。
    • features:可选字符串,声明了新窗口要显示的标准浏览器的特征,具体说明如下表所示。如果省略该参数,新窗口将具有所有标准特征。
    • replace:可选的布尔值。规定了装载到窗口的 URL 是在窗口的浏览历史中创建一个新条目,还是替换浏览历史中的当前条目。
    var features = "height=500, width=800, top=100, left=100, toolbar=no, menubar=no,    scrollbars=no,resizable=no, location=no, status=no";  //设置新窗口的特性
    var win = window.open("http://www.bailiban.com", "windowName", featrues);
    setTimeout (function () {  //定时器
        if (win.closed) {
            console.log("创建的窗口已经关闭。");
        } else {
            win.close();
        }
    }, 5000);  //半秒钟之后关闭该窗口
    
    //打开一个新的窗口
    var win = window.open("http://www.bailiban.com");
    
    setTimeout (function () {  //定时器
        win.close();
    }, 5000);  //半秒钟之后关闭该窗口
    
9.2 document

每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。

  • 对象属性

    //document.cookie = "name='zhangsan'";
    
    //设置或返回与当前文档有关的所有 cookie。
    console.log(document.cookie);
    //返回当前文档的域名。
    console.log(document.domain);
    //返回文档被最后修改的日期和时间。
    console.log(document.lastModified);
    //返回载入当前文档的文档的 URL。
    console.log(document.referrer);
    //返回当前文档的标题。
    console.log(document.title);
    //返回当前文档的 URL。
    console.log(document.URL);
    
  • 文档写入

    • open()打开一个流,以收集来自任何 document.write() 或 document.writeln() 方法的输出。
    • write()向文档写 HTML 表达式 或 JavaScript 代码。
    • writeln()等同于 write() 方法,不同的是在每个表达式之后写一个换行符。
    <html>
    <head>
    	<script>
    		function docWrite(){
                // 重写打开一个一个新的流
    			var newDoc=document.open();
    			var txt="Learning about the DOM is FUN!";
                // 往新的流中写入内容
    			newDoc.writeln(txt);
                // 往新的流中写入内容
    			newDoc.write(txt);
                // 关闭流
    			newDoc.close(); 
    		}		
    	</script>	 
    </head>
    <body>
    
    <input type="button" value="Write to a new document"
    onclick="docWrite()">
    
    </body>
    </html>
    
  • 文档操作见DOM

9.3 location

window.location 对象用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。

这种方法既可以用于具有onclick事件的标签,也可以用于满足某些条件进行跳转,特点是方便且灵活。

  • 对象属性

    //    http://127.0.0.1:8848/aaaa/b.html?name=zhangsan
    
    //设置或返回主机名和当前 URL 的端口号。
    console.log(location.host);  // 127.0.0.1:8848
    //设置或返回当前 URL 的协议。
    console.log(location.protocol);//http:
    //设置或返回当前 URL 的主机名。
    console.log(location.hostname);//127.0.0.1
    //设置或返回当前 URL 的端口号。
    console.log(location.port);//8848
    
    //设置或返回完整的 URL。
    console.log(location.href);//http://127.0.0.1:8848/aaaa/b.html?name=zhangsan
    //设置或返回当前 URL 的路径部分。
    console.log(location.pathname);///aaaa/b.html
    
    //设置或返回从问号 (?) 开始的 URL(查询部分)。
    console.log(location.search);//?name=zhangsan
    
    //可以通过location.href来设置页面的跳转
    location.href = "http://www.bailiban.com";
    
    
  • 地址操作

    • location.assign("http://www.bailiban.com")打开新的页面,会在History 对象中生成一个新的记录。
    • location.replace("http://www.bailiban.com")打开新的页面,不会在 History 对象中生成一个新的记录。
    • location.reload()刷新当前页面内容

10. DOM

​ 浏览器对象模型 (Document Object Model) 使 JavaScript 有能力与当前文档对话。
在这里插入图片描述

​ 任意的文档都可以绘制成树状结构,在DOM树上,每个元素都可与看做一个对象,每个对象都叫做一个节点(node)。docunment就是一个对象,这个对象指代的是这个文档。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。

​ 节点类型主要分为4类(不考虑注释):

  • document
  • element
  • attribute
  • text
10.1 document节点
  • 属性

    • nodeName

      document的nodeName属性为#document。

    • nodeType

      document的nodeName属性为9。

    • nodeValue

      document的nodeValue属性为null。

  • 方法

    • getElementById

      返回带有指定 ID 的元素,结果为dom对象。

      // 获取ID值为my_h1的元素,结果为dom对象
      var h1 = document.getElementById("my_h1");
      
    • getElementsByTagName

      返回带有指定标签名的所有元素。结果为dom对象数组。

      // 返回所有标签名为tagname的元素结合。
      document.getElementsByTagName("tagname");
      
    • getElementsByClassName

      返回带有相同类名的所有元素。结果为dom对象数组。

      // 返回所有class属性值为intro的元素结合。
      document.getElementsByClassName("intro");
      
    • getElementsByName

      可返回带有指定名称的对象的集合。结果为dom对象数组。

      // 返回所有name属性为my_input的元素集合。
      document.getElementsByName("my_input");
      
    • querySelector

      可返回文档中匹配指定 CSS 选择器的一个元素。结果为第一个匹配的dom对象。

      var h1 = document.querySelector("#my_h1");
      
    • querySelectorAll

      可返回文档中匹配指定 CSS 选择器的所有元素的集合。

      var li = document.querySelectorAll("li");
      
    • createElement

      创建一个元素节点 。

    • createAttribute

      创建一个属性节点。

    • createTextNode

      创建一个文本节点。

      // 通过document创建一个h1元素节点
      var newH1 = document.createElement("h1");
      // 通过document创建一个h1元素节点
      var att1 =  document.createAttribute("class");
      att1.value = "my_class" ;
      // 通过document创建一个h1元素节点
      var text2 = document.createTextNode("我们正在学习JS的DOM.");
      // 把属性节点设置到对应的元素节点上
      newH1.setAttributeNode(att1);
      // 把文本节点设置到对应的元素节点上
      newH1.appendChild(text2);
      
      // 将创建的h1加入到body中
      document.body.appendChild(newH1);
      
10.2 element节点
  • 方法

    • getElementsByTagName

      返回带有指定标签名的所有元素。结果为dom对象数组。

      var span = document.getElementById("span");
      //通过元素标签span获取内部元素标签
      var h1 = span.getElementsByTagName("h1");
      console.log(h1[0].innerText);
      
    • appendChild

      向元素添加新的子节点,作为最后一个子节点。

      var newH1 = document.createElement("h1"); 
      
      // 将创建的h1加入到body中
      document.body.appendChild(newH1);
      
    • removeChild

      从元素中移除子节点。

      var span = document.getElementById("span");
      var h1 = span.getElementsByTagName("h1")[0];
      // 把第一个h1标签从span父容器中删除			 
      span.removeChild(h1);
      
    • remove

      直接把当前元素删除。

      var h1 = document.getElementsByTagName("h1")[0];
      // 把当前的h1元素直接删除			 
      h1.remove();
      
    • replaceChild

      用新节点替换某个子节点。

      var span = document.getElementById("span");
      var h1 = document.getElementsByTagName("h1")[0];
      // 创建新的节点
      var newNode = document.createTextNode("a");
      newNode.innerText = "bailiban" ;
      // 用新的节点替换旧的节点
      span.replaceChild(newNode,h1);
      
    • setAttribute / getAttribute

      设置/获取元素的属性值。

      var input = document.getElementById("userPassword");
      // 设置输入框的type属性值为text
      input.setAttribute("type","text");
      
    • setAttributeNode / getAttributeNode

      设置/返回指定的属性节点。

      var span = document.getElementById("span");
      // 通过document创建一个class属性节点
      var att1 =  document.createAttribute("class");
      // 设置此属性节点的值为my_class
      att1.value = "my_class" ;
      // 将此属性节点设置到对应的元素上
      span.setAttributeNode(att1);
      // 获取span的class属性节点,打印此属性值
      console.log(span.getAttributeNode("class").value);
      
    • insertBefore

      在指定的已有子节点之前插入新的子节点。新节点参数在前,已存在节点参数在后。

      // 创建新的节点h2
      var newNode = document.createElement("h2"); 
      newNode.innerText = "bailiban";
      // 获取已存在的id值为my_p的节点
      var exsitNode = document.getElementById("my_p");
      // 在body元素中,将新的节点插入到已存在的p之前。
      document.body.insertBefore(newNode,exsitNode);
      
    • cloneNode

      创建节点的拷贝,并返回该副本。参数为boolean类型,默认false,表示只克隆节点跟属性。true表示复制节点跟属性以及后代。

      var exsitNode = document.getElementsByTagName("h1")[0];
      //将已存在的h1标签进行克隆,后代也一起克隆过来
      var newNode = exsitNode.cloneNode(true);
      // 将克隆的新的节点插入到body中。			
      document.body.insertBefore(newNode,exsitNode);
      
  • 属性

    • nodeName

      element的nodeName属性为标签名。

    • nodeType

      element的nodeName属性为1。

    • nodeValue

      element的nodeValue属性为null。

    • innerText

      设置或返回元素的内部文本。

      var h1 = document.getElementsByTagName("h1")[0];
      // 设置h1标签的内部文本
      h1.innerText = "bailiban";
      // 获取h1标签的内部文本
      console.log(h1.innerText);
      
    • innerHTML

      设置或返回元素的内部HTML。

      var h1 = document.getElementsByTagName("h1")[0];
      // 设置h1标签的内部html,html标签可以得到正确解析
      h1.innerHTML = "<em>bailiban</em>";
      // 获取h1标签的内部html
      console.log(h1.innerHTML);
      
    • outerHTML

      设置或返回元素的外部HTML。

      var h1 = document.getElementsByTagName("h1")[0];
      // 获取h1标签的外部html
      console.log(h1.innerHTML);
      // 设置h1标签的外部html,html标签可以得到正确解析
      h1.outerHTML = "<em>bailiban</em>";
      
    • id / className / tagName

      设置或返回元素的 id / class / 标签名。

      var h1 = document.getElementsByTagName("h1")[0];
      // 设置元素的id值
      h1.id = "h1_id";
      // 设置元素的class值
      h1.className = "h1_class";
      // 获取元素的id值
      console.log(h1.id);
      // 获取元素的class值
      console.log(h1.className);
      // 获取元素的标签值
      console.log(h1.tagName);
      
    • offsetHeight / offsetWidth

      返回元素的高度/宽度。

      var h1 = document.getElementsByTagName("h1")[0];
      console.log(h1.offsetHeight);
      console.log(h1.offsetWidth);
      
    • offsetLeft / offsetTop

      返回元素的水平/垂直偏移位置。

      var h1 = document.getElementsByTagName("h1")[0];
      console.log(h1.offsetLeft );
      console.log(h1.offsetTop);
      
    <h1>bailiban</h1>
    		 
    <ul id="ul">
        <li>苹果</li>
        <li>香蕉</li>
        <li>菠萝</li>
        <li>西瓜</li>
    </ul>
    
    <p>我们正在学习DOM。</p>
    
    • childNodes / children

      返回节点的子节点集合,childNodes会把折叠的空白也算做一个子节点,而children不会。

      var ul = document.getElementById("ul");
      console.log(ul.childNodes[1].innerText);//苹果,因为前面的空白算第一个孩子
      console.log(ul.children[1].innerText);// 香蕉,不考虑空白
      
    • firstChild / firstElementChild

      返回元素的第一个子元素。firstChild计算空白,而firstElementChild不会。

      var ul = document.getElementById("ul");
      console.log(ul.firstChild.innerText);//undefined,第一个孩子是空白,没有innerText
      console.log(ul.firstElementChild.innerText);//苹果,不考虑空白
      
    • lastChild / lastElementChild

      返回元素的最后一个子元素。lastChild 计算空白,而lastElementChild不会。

      var ul = document.getElementById("ul");
      console.log(ul.lastChild.innerText);//undefined,最后一个孩子是空白,没有innerText
      console.log(ul.lastElementChild.innerText);//西瓜,不考虑空白
      
    • nextSibling / nextElementSibling

      返回位于相同节点树层级的下一个节点。nextSibling计算空白,而nextElementSibling不会。

      var ul = document.getElementById("ul");
      console.log(ul.nextSibling.innerText);//undefined,下个节点是空白,没有innerText
      console.log(ul.nextElementSibling.innerText);//我们正在学习DOM。
      
    • previousSibling / previousElementSibling

      返回位于相同节点树层级的上一个节点。previousSibling 计算空白,而previousElementSibling不会。

      var ul = document.getElementById("ul");
      //undefined,空白没有innerText
      console.log(ul.previousSibling.innerText);
      //bailiban
      console.log(ul.previousElementSibling.innerText);
      
    • parentNode

      返回元素的父节点。

      var ul = document.getElementById("ul");
      console.log(ul.parentNode.tagName);// body
      
10.3 CSS
  • 内联样式

    我们可以通过元素.style.属性或者==元素.style[“属性”]==来获取或者设置元素的内联样式。如果属性是多个单词需要使用驼峰命名。

    var p = document.getElementById("my_p");
    // 获取元素P的内联样式的宽度
    console.log(p.style['width']);
    // 获取元素p的内联样式的字体大小,fontSize采用驼峰命名
    console.log(p.style.fontSize);
    // 设置元素p的宽度
    p.style.width = "200px" ;
    
    • 我们获取样式的时候是字符串类型,并且带有px字样。如果想转成只有数字的number类型可以使用parseInt方法。
  • 生效样式

    很多样式我们是定义在内部或者外部,只查看内联样式没意义,我们可以查看元素的生效样式而不用管是定义在哪里。

    • IE游览器: 元素. currentStyle.属性

      var p = document.getElementById("my_p");
      console.log(p.currentStyle.width);
      console.log(p.currentStyle.fontSize);
      
    • 非IE游览器:getComputedStyle

      var p = document.getElementById("my_p");
      
      console.log(   getComputedStyle(p)["width"]   );
      console.log(   getComputedStyle(p)["fontSize"]  );
      
  • 兼容样式

    由于IE跟非IE游览器的样式访问不太一样,我们可以自定义一个方法,来兼容所有游览器。

    /*
    ele:要查看样式的元素。
    styleName:要查看的样式名,字符串形式。
    */
    function getStyleValue(ele,styleName){
        return ele.currentStyle ? ele.currentStyle[styleName] : 		getComputedStyle(ele,null)[styleName];
    }
    					
    var p = document.getElementById("my_p");
    console.log(getStyleValue(p,"width"));
    console.log(getStyleValue(p,"fontSize"));
    

11. 事件

​ 有时候我们需要在达到某些条件的时候去执行 一段固定的JS代码。我们称之为事件。事件有3要素:事件源、绑定事件、事件执行程序。比如页面有一个提交按钮,当点击这个按钮后可以打开一个新的页面。这个按钮叫事件源,打开新的页面叫做事件执行程序,按钮需要跟事件执行程序绑定后,才能在点击的时候触发执行逻辑。

11.1常用事件句柄

在这里插入图片描述

11.2 事件的绑定

方式一,直接在HTML中定义元素事件的相关属性

<button onclick="alert('hello')">按钮</button>
		
<button onclick="helloClk()">按钮</button>

<script>
    function helloClk(){
        alert('hello');
    }
</script>

缺点:html中写JS代码,强耦合,违反了“内容与行为相分离”的原则,少用。

方式二,直接在JS中定义元素事件的相关属性

//<button id="btn_id1">按钮</button>

// 获取按钮元素
var btn = document.getElementById("btn_id1");
// 给按钮元素绑定事件句柄函数
btn.onclick = helloClk;
// 定义事件驱动函数
function helloClk(){
    alert('hello');
}

解决了强耦合性,但只能给一个事件对象绑定一个事件类型。 绑定多个同一类型的事件的话后面覆盖前面的。

方式三,高级事件处理方式 (addEventListener)

// 获取按钮元素
var btn = document.getElementById("btn_id1");

// 给按钮元素绑定事件句柄函数,可以绑定多个
btn.addEventListener("click",btnClick1);
// false表示事件冒泡阶段执行,true表示事件捕获阶段执行,默认false
btn.addEventListener("click",btnClick2 ,false);

function btnClick1(){
    alert('hello1');
}

function btnClick2(){
    alert('hello2');
}

// 把btn上的click事件的btnClick1解除绑定
btn.removeEventListener("click",btnClick1);

  • 可以为一个元素绑定多个监听函数,都会得到执行。
  • 匿名事件无法解绑。
  • IE使用的是detachEvent / attachEvent
11.3 表单的校验

​ 对于JAVA工程师来说,前端与后台的数据交互是及其重要的,而表单的提交就是前端与后台的重要的数据交互。为了提交表单时数据更加合理,减轻后台的压力,在提交表单时进行校验是非常有必要的。

​ 需求:一个具有用户名跟密码的表单,用户名跟密码长度不低于6位则提交,否则不提交并给出提示。

Step 1

​ 在表单中绑定onsubmit事件,调用校验的函数,通过boolean结果来控制是否需要提交。

<form id="my_form" action="#" method="post" onsubmit="return check()"   >
    用户名: <input id="user_name" name="userName"  /> <br/>
    密 码: <input id="user_pwd" type="password" name="userPwd" /> <br/>
    <input type="submit"  />
</form>

<script>
    function check(){
        var name = document.getElementById("user_name").value;
        var pwd = document.getElementById("user_pwd").value;
        if(name.length < 6){
            alert("用户名长度必须不低于6位");
            return false ;
        }
        if(pwd.length < 6){
            alert("密码长度必须不低于6位");
            return false ;
        }
        return true;
    }
</script>

Step 2

​ 这种方式可以进行表单校验,但是密码具有私密性,这种方式密码可以直接看到,我们可以进一步优化,在提交数据之前对密码进行MD5加密。

​ md5在线CDN:

https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.js

https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.min.js

<!-- 引入md5的cdn --> 
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.min.js"></script>
function check(){
    var name = document.getElementById("user_name").value;
    var pwdInput = document.getElementById("user_pwd") ;
    var pwd = pwdInput.value;

    if(name.length < 6){
        alert("用户名长度必须不低于6位");
        return false ;
    }

    if(pwd.length < 6){
        alert("密码长度必须不低于6位");
        return false ;
    }
// 当合法时通过md5方法对密码进行加密后,更新到密码框,这样提交的时候就是加密后的结果。
    pwdInput.value = md5(pwd); 
    return true;
}

Step 3

​ 虽然这样可以对密码进行加密,但是提交的时候密码框的长度会变长,给用户的体验并不好,我们还可以进一步优化,使用隐藏域来提交密码。

​ 终极方案:

<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.min.js"></script>

<form id="my_form" action="#" method="post" onsubmit="return check()"   >
    用户名: <input id="user_name" name="userName"  /> <br/>
    密 码: <input id="user_input_pwd" type="password"  /> <br/>
    <!-- 隐藏域,值用来保存密码md5加密后的结果,提交到后台 -->
    <input id="user_hidden_pwd" type="hidden" name="userPwd" />
    <input type="submit"  />
</form>
function check(){
    var name = document.getElementById("user_name").value;
    var pwdInput = document.getElementById("user_input_pwd") ;
    var pwd = pwdInput.value;

    var pwdHidden = document.getElementById("user_hidden_pwd") ;


    if(name.length < 6){
        alert("用户名长度必须不低于6位");
        return false ;
    }

    if(pwd.length < 6){
        alert("密码长度必须不低于6位");
        return false ;
    }

    pwdHidden.value = md5(pwd); 
    return true;
}
11.4 事件冒泡
  • 事件的传播

    JS中的事件创建后,会按照如下过程在HTML元素间进行传播。IE的事件模型是没有捕获阶段的。

    • 第一阶段:事件捕获,事件对对象沿DOM树向下传播
    • 第二阶段:目标出发,运行事件监听函数
    • 第三阶段:事件冒泡,事件沿DOM树向上传播
      在这里插入图片描述
<div id="my_div">
    <button id="btn_id1">按钮</button>
</div>
		
<script>
    // 获取按钮元素
    var btn = document.getElementById("btn_id1");
    var div = document.getElementById("my_div");

    // 给按钮元素绑定btnClick1,在冒泡阶段 
    btn.addEventListener("click",btnClick1,false);
    // 给按钮元素绑定btnClick1,在冒泡阶段 
    div.addEventListener("click",btnClick2,false);
    // 给按钮元素绑定btnClick1,在捕获阶段 
    document.body.addEventListener("click",btnClick3,true);

    function btnClick1(){
        alert('btn click1');
    }

    function btnClick2(){
        alert('div click2');
    }

    function btnClick3(){
        alert('body click3');
    } 

</script>

结果

body click3
div  click2
btn  click1
11.5 event对象

​ 事件处理函数中有一个绑定事件的对象,有时候我们需要用到里面的一些重要属性。

  • target

    返回触发此事件的元素(事件的目标节点)。

    event.target.id;// 返回触发事件的元素的ID
    event.target.nodeName;// 返回触发事件的元素的标签名
    
  • type

    返回事件的类型。

    event.type; // click
    
  • clintX / clintY

    返回当事件被触发时,鼠标指针的水平 / 垂直坐标。

  • offsetX / offsetY

    返回当事件被触发时,鼠标指针相对于事件源的水平 / 垂直坐标。

  • keyCode

    对于按键事件,返回按键的代码。

  • preventDefault

    取消事件的默认动作(如果存在这样的动作)。比如超链接、表单。

    <a id="my_a" href="https://www.bailiban.com">bailiban</a>
    <script>			
        var a = document.getElementById("my_a");
        a.onclick = function(e){
            e.preventDefault();
        }
    </script>
    
  • stopPropagation()

    阻止事件的继续传播。

    <div id="my_div">
        <button id="btn_id1">按钮</button>
    </div>
    		
    <script>
        // 获取按钮元素
        var btn = document.getElementById("btn_id1");
        var div = document.getElementById("my_div");
    
        // 给按钮元素绑定btnClick1,在冒泡阶段 
        btn.addEventListener("click",btnClick1,false);
        // 给按钮元素绑定btnClick1,在冒泡阶段 
        div.addEventListener("click",btnClick2,false);
        // 给按钮元素绑定btnClick1,在捕获阶段 
        document.body.addEventListener("click",btnClick3,true);
    
        function btnClick1(e){
            alert('btn click1');
        }
    
        function btnClick2(e){
            alert('div click2');
        }
    
        function btnClick3(e){
            alert('body click3');
            // 阻止事件的进一步传播,不会传播到div跟btn
            e.stopPropagation();
        } 
    
    </script>
    
  • cancelable

    指示事件是否可拥可取消的默认动作。设置成true表示阻止事件的传播,等同stopPropagation()

11.6 事件的委托/代理

​ 事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

需求:给ul下的每一个li绑定事件。

<ul id="ul1">
    <li>苹果</li>
    <li>香蕉</li>
    <li>菠萝</li>
    <li>哈密瓜</li>
</ul>

传统方式

循环给li元素绑定事件。

for(var item of li){
    item.onclick = function(){
        alert(this.innerText);
    }
}

这种方式需要绑定很多事件,进行比较多次数的dom交互,影响性能。

事件委托

利用事件的传播机制,直接绑定在ul元素上。

ul.onclick = function(event){
    if(event.target.nodeName.toLowerCase() == 'li'){
        alert(event.target.innerText);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱喝皮蛋瘦肉粥的小饶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值