Web前端开发—JavaScript学习笔记

很早之前跟这个这个视频学习的: https://www.bilibili.com/video/BV1nb411c7mG?p=1&vd_source=c096def4d5f55f1aab46258c0a27641b
可能有空会回顾这个视频,然后会重新沉淀,可能会对笔记有所修改
这是当时整理的笔记

JavaScript

01. Web发展史、JS入门

Web发展史

  • Mosaic:第一个普遍使用的能够显示图片的浏览器
  • JavaScript:1996年首次出现(命名为LiveScript)

浏览器的组成
① shell部分(外壳)
② 内核部分:渲染引擎、js引擎、其他引擎


js引擎
2001年,首次出现,对js引擎进行分离;
2008年,Chrome优化,V8;
FireFox推出。

主流浏览器

  • 在市场上有一定份额
  • 有独立研发的内核
主流浏览器内核
IE浏览器trident
FireFoxGecko
Google ChromeWebkit/blink
SafariWebkit
Operaprosto

JS入门

JavaScript特点(ECMAScript)

  • 解释性语言(翻译一行、执行一行)
  • 单线程
  • ECMA标注
编译性语言解释性语言
优点:快(例如:C、C++)优点:跨平台(例如:JavaScript、PHP、Python)
缺点:移植性不好(不能跨平台)缺点:稍微慢

JS的执行队列:轮转时间片

JS三大部分

  • ECMAScript
  • DOM
  • BOM

如何引入JS

页面级JS

<script type="text/javascript"> 
    //这里放JS代码
</script>

外部JS文件

<script type="text/javascript" src="xxxxx.js">//src属性放文件地址
</script>
//注:前端开发要结构(HTML)、行为(JavaScript)、样式(CSS)相分离
//因此提倡第二种方法

02. JS基础语法知识

变量

声明变量

var a;
var b = 10;
var c, 
    d,
    e;//在开发时,声明多个变量要回车隔开
//var来声明变量

变量的命名规则

  • 必须以英文字母、下划线、$开头
  • 可包含英文字母、下划线、$、数字
  • 不可以用系统关键字,保留字

数据类型

原始值

  • Number:数字
  • Boolean:逻辑值:0(假)和1(真)
  • String:字符串:引号(单引号或者双引号)
  • undefined:无定义的(值只有一个,就是本身)
  • null:空值,起占位作用

引用值

注:这两种类型的赋值方式不同,原始值(Stack)赋值是拷贝的关系,引用值(heap)赋值的是地址。

JS语句基本规则

  • 语句后面用分号结束;
  • JS语法错误会引发后续代码终止,但不会影响其他JS代码块

错误

  • 低级错误(语法解析错误)
  • 逻辑错误(标准错误,情有可原)

JS运算符

  1. “+”:数学运算、字符串连接

注:任何数据类型+字符串=字符串

var a = 1 + "a" + 1; //a = "1a1"
var b = 1 + 1 + "a" +1; //b = "2a1"
  1. “-”,“*”,“/”,“%”,“=”,“()”。

注:“=”最弱,“()”最高(先计算后赋值)

var num = 1 / 0;//Infinity(无穷)
var num = 0 / 0;//NaN(Not a Number非数)
var num = -1 / 0;//-Infinity(负无穷)
var a = 1 + "a" + (1 + 1); //a = "1a2"
  1. “++”,“–”,“+=”,“-=”,“*=”,“/=”,“%=”

注:赋值的顺序,自右向左;计算的顺序,自左向右。

var a = 1;
document.write(a ++);//打印a=1
document.write(a);//打印a=2
var b = 1;
document.write(++ b);//打印b=2
  1. 比较运算符:“>”,“<”,“==”,“>=”,“<=”,“!=”

注:字符串比较的是ASCII码,比较的结果为true或者false
注:NaN不等于NaN,Infinity等于Infinity

  1. 逻辑运算符:&&,||,!(运算结果为真实的值)
//&&
//先看第一个表达式转换成布尔值的结果,如果结果为真,那么他会看第二个表达式转换为
//布尔值的结果,如果只有两个表达式,只看得到第二个表达式,就可以返回该表达式的值
var a = 1 && 2;//返回2
var a = 0 && 2;//返回0
var a = 1 && 2 && 3;//返回3 
//undefined, null, NaN, "", 0, false ==>false;
//短路语句 data && fn(data) data有意义才执行后面语句
// ||
var a = 1 || 2;//返回1
var a = 0 || 2;//返回2 
// !(自身取反)
var a = !123;//返回false
var a = !"";//返回true
var a = !!"";//返回false

03. 条件语句、循环语句

条件语句:if语句

//第一种
if(条件){
    执行语句
}
//第二种
if(条件){
    执行语句
}else{
    执行语句
}
//第三种
if(条件){
    执行语句
}else if(条件){
    执行语句
}else{
    执行语句
}
//if 和 && 的相互转化
//if(条件){语句}    ==>    条件 && 语句

循环语句

for循环

for(var i = 0; i < 10; i++){//中间三块为执行顺序
    document.write('a');
}
//for(1;2;3)
//先执行一遍1 --> 判断2,执行语句 --> 执行3 --> 
//判断2,执行语句 --> 执行3......
//直到2的值为false
//执行顺序
//1、var i = 0;
//2、if(i < 10){document.write('a');}
//3、i++;   --> i = 1
//4、if(i < 10){document.write('a');}
//5、i++;
//6、if(i < 10){document.write('a');}
//......
//

while循环

while(条件){
    执行语句
}
//never-ending loop 死循环
//while(1){}

do while循环

do{
    执行语句
}while(条件)
//不管条件成立不成立,都先执行一遍

例题

//输入
var n = parseInt(window.prompt('input'));1
//JavaScript(动态语言)是天生浮点型,可直接进行小数运算
//1、计算2的n次幂,n可输入,n为自然数
var n = parseInt(window.prompt('input'));
var mul = 1;
for(var i = 0; i < n; i ++){
    mul *= 2;
}
document.write(mul);
//2、计算n的阶乘,n可输入
var n = parseInt(window.prompt('input'));
var mul = 1;
for(var i = 1; i <= n; i ++){
    mul *= i;
}
document.write(mul);
//3、著名的斐波那契额数列 1 1 2 3 5 8输出第n项
var n = parseInt(window.prompt('input'));
var first = 1,
    second = 1,
    third;
if(n > 2){
    for(var i = 0; i < n -2; i++){
        third = first + second;
        first = second;
        second = third;
    }
    document.write(third);
}else{
    document.write(1);
}
//4、编写一个程序,输入一个三位数的正整数,输出时反向输出
var n = parseInt(window.prompt('input'));
var a = n % 10;
var b = (n - a) % 100;
var c = (n - b - a) / 100;
var num = a * 100 + b + c;
document.write(num);
//5、输入a,b,c三四个数字,打印出最大的数字
var a = parseInt(window.prompt('input'));
var b = parseInt(window.prompt('input'));
var c = parseInt(window.prompt('input'));
if(a > b){
    if(a > c){
        document.write(a);
    }else{
        document.write(c);
    }
}else{
    if(b > c){
        document.write(b);
    }else{
        document.write(c);
    }
}
//6、打印出100以内的质数
var count = 0;
for(var i = 1; i < 100; i ++){
    for(var j = 1; j <= Math.sqrt(i); j ++){
        if(i % j == 0){
            count ++;
        }
    }
    if(count == 1){
        document.write(i + " ");
    }
    count = 0;
}

switch case语句

switch(条件){//当条件与情况相符合时,执行语句
    case 情况1:
        语句1;
         break;//跳出switch语句
    case 情况2:
        语句2;
        break;
    case 情况3:
        语句3;
        break;
}

break、continue语句

  • break:终止循环,必须放在循环里面,否则会报错
  • continue:终止本次循环来进行下一次循环

04. 初始引用值、typeof、类型转换

初始引用值

数组

var arr = [1, 2, 3, 4, 5, 7, "abc", undefined];
//1、读取arr[0]...
//2、写入arr[0]=2...
//3、数组的遍历:arr.length数组的长度 

对象object

var obj = {
    //key : value
    //属性名:属性值
    name : "name",//用逗号隔开
    age : 20,
}
//取值obj.name
//赋值obj.age=18;

编程形式的区别

  • 面向过程
  • 面向对象

typeof:分析数据类型,返回的是字符串类型的

//两种写法
typeof(num)
typeof num
  • number:123,234,…
  • string:“abc”,…
  • boolean:true,false
  • object:引用值返回,null返回
  • undefined:undefined
  • function

注:typeof中放没有定义的变量返回undefined

类型转换

显式类型转换

var num = Number('123');//把括号里的东西转换成数字
//null->0,true->1,false->0,undefined->NaN,不是数字的都转换成NaN
var num = parseInt(demo, radix);//转换成整型
//不是数字的全部为NaN,小数转换为整数
//ranix为基底,目标进制,以目标进制为基底转换为十进制,范围2-36
//从数字位往后看,看到非数字位截止
var num = parseFloat(demo);
//从数字位往后看,看到除了第一个点以外的非数字位截止
var num = String(demo);//转换为字符串
var num = Boolean(demo);//转换为布尔值
var num = demo.toString(radix);//转换成字符串,undefined和null不能用
//以十进制为基底转换为目标进制(radix)

隐式类型转换(内部调用的都是显示方法)

  • isNaN()
isNaN(demo)//true,false
//Number(demo) <--> NaN
  • ++/–,+/-(一元正负):内部调用Number()
  • +:内部调用String()
  • -,/,*,%:内部调用Number()
  • &&,||,!
  • <,>,<=,>=
  • ==,!=
undefined == null//true
NaN == NaN//false

不发生类型转换

  • ===:绝对等于
  • !==:绝对不等于
  • NaN === NaN : false

05. 函数、递归

函数

(1)定义

  • 函数声明
function 函数名(){
    语句块
}

注:函数名开发规范:小驼峰(例如:theFirstName…)

  • 函数表达式(忽略名字)
//1、命名函数表达式
var test = function test1(){
    函数体
}//定义结束之后依旧是匿名
//test.name  --> test1
//2、匿名函数表达式 ---函数表达式
var demo = function (){
    函数体
}//test.name --> demo

(2)组成形式

  • 函数名称
  • 参数(不限制位置,天生不定参数)
function sum(a, b){//形式参数(形参)
    //相当于隐式进行了以下两步
    //var a;
    //var b;
    var c = a + b;
    //arguments实参列表(出生的时候有几个就只有几个)
    //arguments -- [2, 3, 4]
    //实参的长度 arguments.length
    //形参的长度 sum.length
}
//映射关系(你变我也变)
sum(1, 2)//实际参数(实参)
sum(2, 3, 4)
  • 返回值
return;//终止函数
//返回值

(3)函数作用域
函数体里面可以访问全局变量,外面不可以访问局部变量。

var a = 123;//全局变量
function text(){
    var b = 234;//局部变量
}

递归

  • 找规律
  • 找出口

06.预编译

js运行三部曲

  1. 语法分析
  2. 预编译
  3. 解释执行

预编译前奏

(函数声明整体提升,变量的声明提升)
(1)imply global 暗示全局变量:任何变量,如果未经声明就赋值,此变量就为全局对象(window)所有

a = 10;//没有声明
//相当于
window.a = 10;
function test(){
    var a = b = 123;
    //a声明了,b没有声明
    //b归window所有
}

(2)一切声明的全局变量,全是window的属性
window就是全局的域

var a = 123;
//相当于window.a = 123
window {
    a : 123
}
//console.log(a) --> window.a

预编译过程

  1. 创建AO对象:Activation Object(执行期上下文) 全局生成GO对象,window == GO
  2. 找形参和变量声明,将变量和形参名作为AO对象的属性名,值为undefined
  3. 将实参和形参统一 全局没有这一步
  4. 找函数体里面的函数声明,值赋予函数体
function fn(a){
    console.log(a);
    var a = 123;
    console.log(a);
    function a(){}
    console.log(a);
    var b = function (){}
    console.log(b);
    function d(){}
}//预编译发生在函数执行的前一刻
fn(1);
  • 创建AO对象:Activation Object(执行期上下文)
AO{}
  • 找形参和变量声明,将变量和形参名作为AO对象的属性名,值为undefined
AO{
    a : undefined,
    b : undefined,
}
  • 将实参和形参统一
AO{
    a : 1,
    b : undefined,
}
  • 找函数体里面的函数声明,值赋予函数体
AO{
    a : function a(){},
    b : undefined,
    d : function d(){}
}
  • 结果
function fn(a){
    console.log(a);//function a(){}
    var a = 123;//var a;被提升 a = 123执行  --> 123
    console.log(a);//123
    function a(){}//提升
    console.log(a);//123
    var b = function (){}//var b;提升 执行b = function (){}
    console.log(b);//function (){}
    function d(){}
}
fn(1);
//结果
//function a(){}
//123
//123
//function (){}

07. 作用域精解、立即执行函数

[[scope]]

  • 每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但是有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
  • [[scope]]值得就是我们所说的作用域,其中存储了运行期上下文的集合。
  • 运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致常见多个执行期上下文,当函数执行完毕,它所产生的执行上下文被销毁。

作用域链

  • [[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
  • 查找变量:从作用域的顶端依次向下 查找。

立即执行函数

  • 此类函数没有函数声明,在一次执行过后即释放。
  • 针对初始化功能的函数
  • 执行完就被释放(和普通函数唯一的区别)
  • 有执行期上下文
  • 只有表达式才能被执行符号执行
  • 能被执行符号执行的表达式,这个函数的函数名就会被忽略
var num = (function (a, b, c){//形参
    语句块
    return n;//直接接受返回值给num
}(1, 2, 3))//实参
//方式
(function (){}());//W3C建议第一种
(function (){})();
//只有表达式才能被执行符号执行
var test = function(){
    语句块
}();//被执行符号执行
function test(){
    语句块
}()//不能被执行

08. 闭包

  • 当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露(过多占用内存资源

闭包的作用

  • 实现公有变量:函数累加器
function add(){
    var num = 0;
    function a(){
        console.log(++num);
    }
    return a;
}
var myAdd = add();
myAdd();   //  1
myAdd();  //  2
myAdd();  //  3
  • 可以做缓存(存储结构)
function test(){
    var food = "apple";
    var obj = {
        eatFood : function(){
            if(food != ""){
                console.log("I am eating " + food);
                food = "";
            }else{
                console.log("There is nothing!");
            }
        },
        pushFood : function(myFood){
            food = myFood;
        }
    }
    return obj;
}
var person = test();
person.eatFood();  //I am eating apple
person.eatFood();  //There is nothing!
person.pushFood("banana");  //
person.eatFood();  //I am eating banana
  • 可以实现封装,属性私有化
  • 模块化开发防止污染全局变量
function test(){
    var arr = [];
    for(var i = 0; i < 10; i++){
        arr[i] = function(){
            console.log(i);        
        }    
    }
    return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++){
    myArr[j]();
}//打印10个10

function test(){
    var arr = [];
    for(var i = 0; i < 10; i++){
        (function(j){
           arr[j] = function(){
            	console.log(j);//保存的是立即执行函数的劳动成果        
        	}               
        }(i))   
    }
    return arr;
}//打印0-9

09. 对象、包装类

对象的创建方法

//1.var obj = {}    plainObject    对象字面量/对象直接量
//2.构造函数
//      1) 系统自带的构造函数 new Object()
//      2) 自定义  大驼峰式命名规则
function Car(color){
    this.color = color;
    this.name = "BMW";
    this.height = "1400";
    this.run = function(){
            
    }
}
//通过参数使函数发生变化
//构造函数内部原理
//1.在函数体最前面隐式的加上this={}
//2.执行this.xxx = xxx;
//3.隐式的返回this

包装类

new String();
new Boolean();
new Number();
//原始值不能加属性
var num = 4;
num.len = 3;
//new Number(4).len = 3;
console.log(num.len);//undefined

10. 原型、继承模式、对象枚举、this

原型

  1. 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
  2. 利用原型特点和概念,可以提取共有属性。
  3. 对象如何查看原型——隐式属性__proto__
  4. 对象如何查看对象的构造函数——constructor
//Person.prototype  --原型
//Person.prototype = {} 是祖先

var obj = {};
//var obj1 = new Object();
//obj1.__proto__----->  Object.prototype

原型链

绝大多数对象的最终都会继承自 Object.prototype

//var obj = Object.create(原型)
var obj = {name:"sunny", age : 123};
var obj = Object.create(obj);

可正常计算的范围:小数点前16位,后16位

//call/apply
//作用,改变this指向
//区别,后面传的参数形式不同,传参列表不一样
//call 需要把实参按照形参的个数传进去
//apply 需要传一个arguments
function test(){
}
test() --> test.call();
function Person(name, age){
    this.name = name;
    this.age = age;
}
var person = new Person("zhangsan", 100);
var obj = {
}
Person.call(obj, "lisi", 300);//把所有的this变成obj
function Person(name, age, sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name, age, sex, tel, grade){
    //var this = {} 利用person的方法实现自己
    Person.call(this, name, age, sex);
    this.tel = tel;
    this.grade = grade;
}
var student = new Student('sunny', 123, 'male', 139, 2018);

继承模式

/**
 * 1.传统形式 -->  原型链
 *    过多的继承了没用的属性
 * 2.借用构造函数---call/apply
 *    不能继承借用构造函数的原型
 *    每次构造函数都要多走一个函数
 * 3.共享原型---先继承,后使用
 *    不能随便改动自己的原型
 * 4.圣杯模式
 */

//共享原型
Father.prototype.lastName = "Chen";
function Father(){
}
function Son(){
}
Son.prototype = Father.prototype;
var son = new Son();
var father = new Father();
//圣杯模式
//             Father.prototype
//
//                              functionF(){}
//                              F.prototype = Father.prototype
//
//                              Son.prototype = new F();
//
//     Father                            Son
//
//圣杯模式(继承最终写法)Target继承自Origin
//第一种写法
function inherit(Target, Origin){
    function F(){};
    F.prototype = Origin.prototype;
    Target.prototype = new F();
    Target.prototype.constuctor = Target;
    Target.prototype.uber = Origin.prototype;//真正继承自谁
}
//第二种写法(建议)
var inherit = (function (){
    var F = function(){};
    return function (Target, Origin){
            F.prototype = Origin.prototype;
    	Target.prototype = new F();
    	Target.prototype.constuctor = Target;
    	Target.prototype.uber = Origin.prototype;
    }
}());

Trips

//命名空间---管理变量,防止污染全局,适用于模块化开发
//想实现方法的连续调用,return this
//属性表示方法  obj.prop     obj["prop"]

对象的枚举

// for in
var obj = {
    name :"cyq",
    age : 21,
    sex : 'male',
    height : 150,
    weight : 47
}
for (var prop in obj){
    //console.log(obj.prop   --->  obj['prop'])
    //结果为undefined
    console.log(prop + " : " + obj[prop]);
}
// hasOwnProPerty
//判断属性是不是他自己的
var obj = {
    name :"cyq",
    age : 21,
    sex : 'male',
    height : 150,
    weight : 47,
    __proto__ :{
        lastName : "deng"
    }
}
for (var prop in obj){
    if(obj.hasOwnProperty(prop)){
        console.log(prop + " : " + obj[prop]);//打印结果没有deng
    }
}
// in 只能判断这个对象能不能访问到这个属性
// ** instanceof
// A对象 是不是 B构造函数构造出来的
// ** 看A对象的原型链上 有没有 B的原型
// A instanceof B  返回true/false

this

函数预编译过程 this --> window
全局作用域里 this --> window
call/apply 可以改变函数运行时this指向
obj.func(); func()

11. arguments、克隆、数组、类数组

arguments

//arguments.callee  --->   指向函数自身引用
//obj.caller

克隆

// 深度克隆
//遍历对象  for(var prop in obj)
//1.判断是不是原始值  typeof() object
//2.判断是数组还是对象  instanceof toString constructor
//3.建立相应的数据或对象
var obj = {
    name : "cyq",
    age : 18,
    card : ['123', 'abc'],
    wife : {
        name : 'bjw',
        son : {
            name : 'byz'
        }
    }
}
var obj1 = {
}
function deepClone(origin, target){
    var target = target || {},
        toStr = Object.prototype.toString,
        arrStr = "[object Array]";
    
    for(var prop in origin){
        if(origin.hasOwnProperty(prop)){
            if(origin[prop] !== "null" && typeof(origin[prop]) == 'object'){
                // if(toStr.call(origin[prop]) == arrStr){
                //     target[prop] = [];
                // }else{
                //     target[prop] ={};
                // }
                target[prop] = toStr.call(origin[prop]) == arrStr ? [] : {};
                deepClone(origin[prop], target[prop]);
            }else{
                target[prop] = origin[prop];//浅克隆
            }
        }
    }
    return target;
}
deepClone(obj, obj1);

数组

//数组的定义
//new Array(length/content);
//字面量 var arr = [1,2,,,3,4];
//数组的读和写
arr[num]//不可以溢出读 溢出读出undefined
arr[num] = xxx;//可以溢出写

//数组常用的方法 *es3.0  es5.0  es6.0
//改变原数组
//1.push
var arr = [];
arr.push(10);//添加数据,数组的最后一位,返回数组的长度
arr.push(1,2,3,4,5,6);
// Array.prototype.push = function(){
//     for(var i = 0; i < arguments.length; i ++){
//         this[this.length] = arguments[i];
//     }
//     return this.length;
// }
//2.pop
var num = arr.pop();//把数组最后一位剪切出去
//3.unshift在数组的前面增加数据
arr.unshift(1);
arr.unshift(1,2,3);
//4.shift
var num = arr.shift();//把数组的第一位剪切出去
//5.reverse
arr.reverse();//逆转数组,返回逆转后的数据
//6.splice (可用于往某一位中间添加数据)
//arr.splice(从第几位开始,截取多少的长度,在切口处添加新的数据);
arr.splice(1,2);//返回截取的数据
arr.splice(1,1,0,0,0,0);//在切口加数据,后面的参数为无穷个,返回截取的数组
arr.splice(-1,1);//-1为倒数第一位,负数就+length
//7.sort 排序
arr.sort();//升序 ASCII码排序
arr.sort().reverse();//降序
//必须写两个形参 看返回值
    	//①当返回值为负数时,那么前面的书放在前面
    	//②为正数 那么后面的数在前
    	//③为0 不动
arr.sort(function(a, b){
    if(a > b){//升序  降序(a < b)
        return 1;    
    }else{
        return -1;    
    }
});
arr.sort(function(a, b){
    return a - b;//升序  降序(b - a)
});
//乱序
arr.sort(function(a, b){
    return Math.random() - 0.5;
});
//对象排序
arr.sort(function(a, b){
    return a.age - b.age;
});

//不改变原数组
//1.concat
arr.concat(arr1);//把arr1拼在arr后面形成一个全新的数组
//2.slice
//slice(从该位开始截取,截取到该位)
var newArr = arr.slice(1,2);
arr.slice(1);//从第一位开始截取到最后
arr.slice();//截取全部
//3.join -- 不传参数按照,连接
arr.join("-");//返回字符串,把每一位连接起来,按照括号中的字符,例如"1-2-3-4"
//4.split--string拆分为数组
str.split('-');//"1-2-3-4" ---> ['1','2','3','4']

类数组

  • 可以利用属性名模拟数组的特性
  • 可以动态的增长length属性
  • 如果强行让类数组调用push方法,则会根据length属性值的位置进行属性的扩充
var obj = {
    "0" : 'a',
    "1" : 'b',
    "2" : 'c',
    "name" : 'cyq',
    "age" : 18,
    "length" : 3,
    "push" : Array.prototype.push,
    "splice" : Array.prototype.splice
}
//属性要为索引(数字)属性 必须有length属性 最好加上push
Array.prototype.push = function(target){
    obj[obj.length]  = target;
    obj.length ++;
}
//优点:把数组和对象的方法拼到一起

12. 封装type、数组去重

封装type

// typeof([]) -- Array
// typeof({}) -- Object
// typeof(function) -- Object
// typeof(new Number()) -- number Object
// typeof(123) -- number
function type(target){
    //1.分两类 原始值 引用值
    //2.区分引用值
    var ret = typeof(target);
    var template ={
        "[object Array]" :"array",
        "[object Object]" : "object",
        "[object Number]" : "number - object",
        "[object Boolean]" : "boolean - object",
        "[object String]" : "string - object"
    }
    if(target === null){
        return "null";
    }else if(ret == "object"){
        //数组
        //对象
        //包装类Object.prototype.toString
        var str = Object.prototype.toString.call(target);
        return template[str];
    }else{
        return ret;
    }
}

数据去重

//要求在原型链上编程
//数组去重,利用对象属性名不重复
Array.prototype.unique = function(){
    var temp = {},
        arr = [],
        len = this.length;
    for(var i = 0; i < len; i ++){
        if(!temp[this[i]]){
            //当前对象这个属性没有值,undefined
            temp[this[i]] = "abc";
            arr.push(this[i]);
        }
    }
    return arr;
}

13. try…catch、es5

try…catch

try{
   //在try里面发生错误,不会执行错误后的try里面的代码 
}catch(e){//error  error.message   error.name --> error
    console.log(e.message + " : " + e.name);
}
//Error.name
//1. EvalError:eval()的使用与定义不一致
//2. RangeError:数值越界
//3. ReferenceError:非法或不能识别的引用数值
//4. SyntaxError:发生语法解析错误
//5. TypeError:操作数类型错误
//6. URIError:URI处理函数使用不当

es5

//基于es3.0的 + es5.0的新增方法
//es3.0 和 es5.o产生冲突的部分
//es5.0严格模式 产生冲突的部分使用es5.0
//es5.0严格模式启动(第一行)
"use strict";

两种用法

  • 全局严格模式
  • 局部函数内严格模式(推荐)

规定

  • 不支持with,arguments.callee,func.caller
  • 变量赋值前必须声明
  • 局部的this必须被赋值(赋什么就是什么)
  • 拒绝重复属性和参数

14. DOM

什么是DOM

  • DOM:Document Object Model
  • DOM定义了表示和修改文档所需的方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作html和xml功能的一类对象的集合。也有人称DOM是对HTML以及XML的标准编程接口。

DOM基本操作

对节点的增删改查

//查看元素节点
//document代表整个文档
document.getElementById('')//元素id
.getElementsByTagName('div')[0]//标签名 类数组
.getElementsByName()//只有部分标签name可生效(表单,表单元素,img,iframe)
.getElementByClassName()//类名 -> ie8和ie8以下的ie版本中没有 可以多个class一起
//非实时
.querySelector()//(css选择器) 在ie7和ie7以下版本中没有
.querySelectorAll()//一组 在ie7和ie7以下版本中没有

//遍历节点树
// parentNode -> 父节点(最顶端的parentNode为#document);
// childNodes -> 子节点们
// firstChild -> 第一个子节点
// lastChild -> 最后一个子节点
// nextSibling -> 后一个兄弟节点
// previousSibling -> 前一个兄弟节点

// 基于元素节点树的遍历
// parentElement -> 返回当前元素的父元素节点(IE不兼容)
// children -> 只返回当前元素的元素子节点
// node.childElementCount === node.children.length当前元素节点的子元素的个数
// firstElementChild -> 返回的是第一个元素节点(IE不兼容) 9及以下
// lastElementChild -> 返回的是最后一个元素节点(IE不兼容)
// nextElementSibling/previousElementSibling -> 返回后一个/前一个兄弟元素节点

节点的类型

  • 元素节点 —— 1
  • 属性节点 —— 2
  • 文本节点 —— 3
  • 注释节点 —— 8
  • document —— 9
  • DocumentFragment —— 11

获取节点类型 nodeType
节点的四个属性

  • nodeName:元素的标签名,以大写形式表示,只读
  • nodeValue:Text节点或Comment节点的文本内容,可读写
  • nodeType:该节点的类型,只读
  • attributes:Element节点的属性集合

节点的一个方法 Node.hasChildNodes(); / true / false

DOM基本操作

  • getElementById方法定义在Document.prototype上,即Element节点上不能使用
  • getElementByName方法定义在HTMLDocument.prototype上,即非html中的document不能使用(xml,document,Element)
  • getElementByTagName方法定义在Document.prototypeElement.prototype
  • HTMLDocument.prototype定义了一些常用的属性,body,head分别指代HTML文档中的<body><head>标签
  • Document.prototype上定义了documentElement属性,指代文档的根元素,在HTML文档中,他总指代<html>元素
  • getElementByClassNamequerySelectorAllquerySelectorDocument.prototypeElement.prototype类中均有定义

增加一个元素节点

document.createElement();//创建元素节点***
document.createTextNode();//创建文本节点
document.createComment();//创建注释节点
document.createDocumentFragment();//创建文档碎片节点

插入操作

// PARENTNODE.appendChild();
// PARENTNODE.insertBefore(a,b); 在b之前插入a

删除操作

// parent.removeChild(); 剪切
// child.remove(); 销毁

替换

// parent.replaceChild(new, origin); 拿新的替换老的 剪切

Element节点的一些属性

  • innerHTML获取HTML内容,改变HTML里面的内容(覆盖原内容)
  • innerText取文本、写文本(覆盖结构)(火狐不兼容)/ textContent(老版本IE不好使)

Element节点的一些方法

  • ele.setAttribute()
  • ele.getAttribute()

DOM基本操作

//查看滚动条的滚动距离
window.pageXOffset//横向
window.pageYOffset//纵向
//IE8和IE8一下的浏览器 兼容性混乱
document.body.scrollLeft
document.body.scrollTop
document.documentElement.scrollTop
document.documentElement.scrollLeft
document.body.scrollLeft + document.documentElement.scrollLeft//取值同时相加

//查看可视区窗口的尺寸
window.innerWidth//宽度
window.innerHeight//高度
//IE8及以下  
//标准模式下
document.documentElement.clientWidth
document.documentElement.clientHeight
//怪异模式下
document.body.clientHeight
document.body.clientWidth

//查看元素几何尺寸
getBoundingClientRect();
//兼容性很好
//返回一个对象 对象里有left top right bottom
//IE里没有height width
//非实时的

//查看元素的尺寸
dom.offsetWidth
dom.offsetHeight
//查看元素的位置
//对于无定位父级的元素,返回相对文档的坐标;对于有定位的父级,返回相对于最近的有定位的父级的坐标
dom.offsetLeft
dom.offsetTop
//返回最近的有定位的父级
dom.offsetParent

//让滚动条滚动
//window上有三个方法 将x,y传入
scroll();//让滚动条滚动到当前位置
scrollTo();
scrollBy();//累加滚动距离

DOM树结构

DOM树

15. date对象、定时器

日期对象:Date() 是系统提供好的

var date = new Date();//非实时
date.getDate();//一个月中的某一天 (1 ~ 31)
date.getDay();//一周中的第几天 (周日为0) (0 ~ 6)
date.getMonth();//返回月份(0 ~ 11)
date.getFullYear();//返回年份四位数
date.getHours();//小时
date.getMinutes();//分钟
date.getSeconds();//秒钟
date.getMilliseconds();//毫秒
date.getTime();//***返回 1970 年 1 月 1 日至今的毫秒数

定时器

// 定时器
//1.
var timer1 = setInterval(function (){
    //时间不准
}, 1000);//每隔1000毫秒执行一次函数
clearInterval(timer1);//唯一标识
//2.
var timer2 = setTimeout(function(){
}, 1000);//在1000毫秒之后执行函数,只执行一次
clearTimeout(timer2);
//全局对象Window上的方法,内部函数this执行window
//setInterval("func()", 1000);

16. 脚本化CSS

读写css

dom.style.prop
//可读写行间样式 没有兼容性问题 碰到float的保留字属性 在前面加上css
dom.style.cssFloat
//复合属性必须拆解,组合单词变成小驼峰式写法

查询计算样式

window.getComputedStyle(ele, null);//获取ele元素显示出来的css属性,包括默认值
//对象
//计算样式只读
//返回的计算样式的值都是绝对值 没有相对单位
// IE8及IE8以下不兼容
ele.currentStyle
//IE 

17. 事件

如何绑定事件处理函数

  1. ele.onxxx = function(event){}
  • 兼容性很好,但是一个元素的同一个事件上只能绑定一个处理程序
  • 基本等同于写在HTML行间上
  1. obj.addEventListener(type, fn, false);
  • IE9以下不兼容,可以为一个时间绑定多个处理程序
  1. obj.attachEvent('on' + type, fn);
  • IE独有,一个事件同样可以绑定多个处理程序

事件处理程序的运行环境

  1. ele.onxxx = function(event){}
  • 程序this指向是dom元素本身
  1. obj.addEventListener(type, fn, false);
  • 程序this指向是dom元素本身
  1. obj.attachEvent('on' + type, fn);
  • 程序this指向window

解除事件处理程序

  • ele.onclick = false/''/null;
  • ele.removeEventListener(type, fn, false);
  • ele.detachEvent('on' + type, fn);
  • 注:若绑定匿名函数,则无法解除

事件处理模型

  1. 事件冒泡
    结构上(非视觉上)嵌套关系的元素,会存在事件冒泡的功能,同一事件,自子元素冒泡向父元素。(自底向上)
  2. 事件捕获
  • 结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,同一事件,自父元素捕获至子元素(事件源元素)。(自顶向下)
  • IE没有捕获事件
  • 触发顺序,先捕获,后冒泡
  • focusblurchangesubmitresetselect等事件不冒泡

取消冒泡和阻止默认事件

  1. 取消冒泡
  • W3C标准event.stopPropagation(); 但不支持IE9以下版本
  • IE独有event.cancelBubble = true;
  • 封装取消冒泡的函数 stopBubble(event)
  1. 阻止默认事件
  • 默认事件 — 表单提交,a标签跳转,右键菜单等
  • return false; 以对象属性的方式注册的时间才生效
  • event.preventDefault(); W3C标准,IE9以下不兼容
  • event.returnValue = false; 兼容IE
javascript:void()//相当于返回括号里的内容
javascript:void(0);// return 0

事件对象

//  event || window.event 用于IE
//事件源对象 这俩chrome都有
event.target  //火狐只有这个
event.srcElement   //IE只有这个
event.target || event.srcElement

事件委托

利用事件冒泡,和事件源对象进行处理
优点:

  • 性能 不需要循环所有的元素一个个绑定事件
  • 灵活 当有新的子元素时不需要重新绑定事件

鼠标事件

onclick   点击
onmousedown  鼠标按下
onmouseup   鼠标弹起
contextmenu 右键产生菜单
mousemove  鼠标移动
mouseover  鼠标闯进区域
mouseout   鼠标离开区域
mouseenter  鼠标移入某元素
mouseleave  鼠标移出某元素
用button属性来区分鼠标的按键, 0左键/1/2右键 (mouseup mousedown)
click事件只能监听左键

键盘事件

keydown > keypress > keyup
keydown可以响应任意键字符 keypress只能响应字符类键盘按键
keypress返回ASCII码,可以转换成相应字符

文本操作事件

  • input
  • change 鼠标聚焦和失去焦点是否发生改变
  • focus 聚焦
  • blur 失去焦点

窗体操作类

  • scroll 滚动条滚动
  • load

18. json、异步加载、时间线

json

JSON.parse(); //string --> json
JSON.stringify(); //json --> string

异步加载

js加载的缺点:加载工具方法没必要阻塞文档,过得js加载会影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作。有些工具方法需要按需加载,用到再加载,不用不加载。
JavaScript异步加载的三种方案

  • defer异步加载,但要等到dom文档全部解析玩才会被执行,只有IE能用,也可以将代码写到内部;(执行时不阻塞页面)
  • async异步加载,加载完就执行,async只能加载外部脚本,不能把js写在script标签里;(执行时不阻塞页面)
  • 创建script,插入到DOM中,加载完毕后callBack(按需加载)

js加载时间线

  1. 创建Document对象,开始解析Web页面,解析HTML元素和他们的文本内容后添加Element对象和Text节点到文档中。这个阶段document.readyState = 'loading'
  2. 遇到link外部css,创建线程加载,并继续解析文档。
  3. 遇到script外部js,并且没有一个设置asyncdefer,浏览器加载,并阻塞,等待js加载完成并执行该脚本, 然后继续解析文档。
  4. 遇到script外部js,并且设置有asyncdefer,浏览器创建线程加载,并继续解析文档。对于async属性的脚本,脚本加载完成后立即执行。(异步禁止使用document.write()
  5. 遇到img等,先正常解析dom结构,然后浏览器异步加载src,并继续解析文档。
  6. 当文档解析完成后,document.readyState = 'interactive'
  7. 文档解析完成后,所有设置有defer的脚本会按照顺序执行。(注意与async的不同,但同样禁止使用document.write()
  8. document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段。
  9. 当所有async的脚本加载完成并执行后、img等加载完成后,document.readyState = 'complete',window对象触发load事件。
  10. 从此,以异步响应方式处理用户输入、网络事件等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

30ring

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

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

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

打赏作者

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

抵扣说明:

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

余额充值