事件视界
事件视界
发布于 2022-04-17 / 9 阅读
0

JS笔记

1. JS基础

1.1 JS基本语法

JavaScript每个语句后的;不是必须但是推荐添加

1.1.1 数据类型

1.1.1.1 Number

js不区分浮点数和整数,统一用Number表示

1.1.1.2 字符串

以单引号或者双引号括起来的文本,可以使用转义字符"\"在字符串内表示字符串内的单双引号

可以使用下标来获取字符串内的某个字符,如s[1]

但需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果:

var s = 'Test';
s[0] = 'X';
alert(s); // s仍然为'Test'

字符串常用的方法

方法作用
toUpperCase()把一个字符串全部变为大写
toLowerCase()把一个字符串全部变为小写
indexOf()搜索指定字符串出现的位置,如果没有则返回-1
substring()返回指定索引区间的字串,第一个属性为起始点,第二个为结束点,结束点非必须
1.1.1.3 布尔值

true或false

1.1.2 值得注意的运算符

运算符效果
==它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果
===它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较

因此,大部分情况下不要使用==,而应该使用===

1.1.3 特殊值

注释
NaNNaN这个特殊number和其他所有值不相等,包括自己,唯一能判断NaN的方法是通过isNaN()函数
null表示一个“空”的值,它和0以及空字符串''不同,0是一个数值,''表示长度为0的字符串,而null表示“空”
undefined未定义

1.1.4 数组

创建数组的方法:

var arr = [1,2,3];

new Array(1, 2, 3);

arr.length可以获取数组长度,给它赋值也能改变数组的长度

请注意,如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化:

var arr = [1, 2, 3];
arr[5] = 'x';
arr; // arr变为[1, 2, 3, undefined, undefined, 'x']

常用数组的方法:

方法作用
indexOf搜索一个指定的元素的位置
slice()它截取Array的部分元素,然后返回一个新的Array
push和poppush()Array的末尾添加若干元素,pop()则把Array的最后一个元素删除掉
unshift和shift如果要往Array的头部添加若干元素,使用unshift()方法,shift()方法则把Array的第一个元素删掉,返回array的新长度
sort()数组排序,直接调用会按照默认顺序排序
reverse()反转数组
splice()修改Array的“万能方法”
concat()方法把当前的Array和另一个Array连接起来,并返回一个新的Array,注意不是修改而是创建新的
join()它把当前Array的每个元素都用指定的字符串连接起来,然后返回连接后的字符串

1.1.5 对象

即一组键值对形成的对象

当属性名包含特殊字符时,如middle-school,需要用'括起来,访问这个属性也不能再用.,而是要用obj['middle-school']

检测某个对象是否存在某个属性时,可以用in,如:

'name' in xiaoming;

要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()方法:

xiaoming.hasOwnProperty('name');

1.1.6 变量

使用var申明变量,js的变量为动态的,可以从一种数据类型变化为另一种数据类型

如果不使用var定义的变量则会变成全局变量,在strict模式下将强制使用var定义变量,不使用就报错

ES6之后可以用const定义常量,constlet都具有块级作用域

启用strict模式的方法是在JavaScript代码的第一行写上:

'use strict';

1.1.7 条件判断

注意:JavaScript把nullundefined0NaN和空字符串''视为false,其他值一概视为true

1.1.8 循环

//FOR循环
var x = 0;
var i;
for (i=1; i<=10000; i++) {
    x = x + i;
}
//for循环的一种变体:for...in...
var o = {
    name: 'Jack',
    age: 20,
    city: 'Beijing'
};
for (var key in o) {
    console.log(key); // 'name', 'age', 'city'
}
//for ... in对Array的循环得到的是String而不是Number
//while循环,先判断后执行
var x = 0;
var n = 99;
while (n > 0) {
    x = x + n;
    n = n - 2;
}
x; // 2500
//do while循环,先执行后判断
var n = 0;
do {
    n = n + 1;
} while (n < 100);
n; // 100

1.1.9 Map和Set

由于对象的键只能是字符串,ES6推出了支持其他数据类型的Map

var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined

Set则为仅储存键不储存值,可以理解成不能重复没有索引的数组

var s = new Set([1, 2, 3, 3, '3']);//重复元素在`Set`中自动被过滤:
s; // Set {1, 2, 3, "3"}
s.add(4);
s; // Set {1, 2, 3, "3", 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, "3", 4}
s.delete(3);
s; // Set {1, 2, "3", 4}

1.1.1.10 iterable类型

ArrayMapSet都属于iterable类型。

使用for…of来遍历

var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array,Array实际上是以索引为键的对象,当给其添加了额外的属性后就不能用for...in了(又是历史遗留问题)
    console.log(x);
}
for (var x of s) { // 遍历Set
    console.log(x);
}
for (var x of m) { // 遍历Map
    console.log(x[0] + '=' + x[1]);
}

forEach方法可以遍历整个iterable类型,此方法为ES5.1引入

a.forEach(function (element, index, array) {
    // element: 指向当前元素的值
    // index: 指向当前索引
    // array: 指向Array对象本身
    console.log(element + ', index = ' + index);
});
//Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身
//Map的回调函数参数依次为value、key和map本身:

1.2 函数

1.2.1 函数基础

定义函数的方式如下:

//方式一、直接定义abs()函数对象
function abs(x) {
}
//方式二、定义匿名函数并赋值给abs变量
var abs = function (x) {
};
//两种方法完全等价

注意:js允许传入比函数需要多或者少的变量,不影响函数的调用

关键字arguments:仅起作用于函数内部,指向调用者传入的所有参数,类似array但不是array

ES6标准引入了rest参数,可以查找出定义的参数以外的所有参数(以数组形式):

function foo(a, b, ...rest) {
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}
foo(1, 2, 3, 4, 5);
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

TIPS:

  • js中的作用域仅用于拘束函数,不能拘束for和if这类
  • js会会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部,所以可以先引用后申明
  • 不在任何函数内定义的变量就具有全局作用域
  • 解构赋值可以快速进行赋值(需支持ES6)

在一个对象中绑定方法,称为这个对象的方法

对象.方法()时,this指向对象

直接使用方法()时,strict模式下为undefined,非strict模式下为windows

apply()call()可以用于指定函数调用的this,唯一区别是:

  • apply()把参数打包成Array再传入;
  • call()把参数按顺序传入。

1.2.2 高阶函数

以函数为参数的函数成为高阶函数,一个最简单的高阶函数:

function add(x, y, f) {
    return f(x) + f(y);
}
高级函数作用
map()map()对整个数组执行某个函数
reduce()reduce()将数组中的前两个值传入函数,得到结果后将结果与下一个元素继续传入函数
filter()filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
sort()对数组进行排序,默认排序时是将数字也转换成字符串之后按字符串的ASCII顺序排序的,也可以调用自定义函数来排序,当返回值为1时调换传入的两个函数的位置。sort是修改数组而不是返回新数组
every()判断数组的所有元素是否满足测试条件
find()查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回undefined
findIndex()findIndex()find()类似,也是查找符合条件的第一个元素,不同之处在于findIndex()会返回这个元素的索引,如果没有找到,返回-1
forEach()forEach()map()类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。forEach()常用于遍历数组,因此,传入的函数不需要返回值

1.2.3 闭包

将返回值设置为一个函数,返回的函数不会立即执行,而是会在调用时候才执行,因此,当函数内包含循环变量(或者会发生变化的变量)的计算的时候,这个计算会在调用时才发生。

返回函数不要引用任何循环变量,或者后续会发生变化的变量。

或者让其立即执行

function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i));
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

f1(); // 1
f2(); // 4
f3(); // 9

闭包的意义:返回一个函数的同时可以携带一个外部无法访问的局部变量,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来

1.2.3 箭头函数

ES6新增的写法

x => x * x

上面的箭头函数相当于创建一个匿名函数:

function (x) {
    return x * x;
}

其他写法

// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

// 可变参数:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i ({ foo: x })

不过与直接定义匿名函数比,箭头函数的this就始终指向外层调用者了。

1.2.4 生成器generator

写法:

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}

调用一个generator会返回一个generator对象

可以通过next()方法获取下一个返回的值以及是否返回完:

{value: 3, done: false}
{value: undefined, done: true}

也可以通过for…of循环generator来获取每一个返回值

for (var x of fib(10)) {
    console.log(x); // 依次输出11,12,13
}

2. 标准对象

2.1 对象的类型

  • number
  • string
  • boolean
  • function
  • undefined
  • object【其中null、Array的类型也都是object】

2.2 包装对象

typeof new Number(123); // 'object'
new Number(123) === 123; // false

通过new来创建包装对象,其类型成为了对象

不写new时为转换函数,转换结果不是对象

  • 不要使用new Number()new Boolean()new String()创建包装对象;
  • parseInt()parseFloat()来转换任意类型到number
  • String()来转换任意类型到string,或者直接调用某个对象的toString()方法;【nullundefined没有toString()方法】
  • 通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...}
  • typeof操作符可以判断出numberbooleanstringfunctionundefined
  • 判断Array要使用Array.isArray(arr)
  • 判断null请使用myVar === null
  • 判断某个全局变量是否存在用typeof window.myVar === 'undefined'
  • 函数内部判断某个变量是否存在用typeof myVar === 'undefined'

2.3 常用对象

2.3.1 Date 时间对象

要获取系统当前时间,用:

var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳

也可以自己定义时间

var d = new Date(2015, 5, 19, 20, 15, 30, 123);
d; // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)
//其中,月份里0指1月,1指2月以此类推
var d = Date.parse('2015-06-24T19:49:22.875+08:00');
d; // 1435146562875
d.getMonth(); // 5——表示6月
d.toLocaleString(); // '2015/6/24 下午7:49:22',本地时间(北京时区+8:00),显示的字符串与操作系统设定的格式有关
d.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC时间,与本地时间相差8小时

2.3.2 RegExp正则表达式

指定字符类型

  • \d可以匹配一个数字
  • \w可以匹配一个字母或数字
  • \s可以匹配一个空格(也包括Tab等空白符)
  • 要做更精确地匹配,可以用[]表示范围
  • ()表示的就是要提取的分组(Group)。比如: ^(\d{3})-(\d{3,8})$分别定义了两个组

指定数目【由其前面指定类型】

  • .可以匹配任意字符
  • *表示任意个字符(包括0个)
  • +表示至少一个字符
  • ?表示0个或1个字符
  • {n}表示n个字符
  • {n,m}表示n-m个字符

指定行结构

  • ^表示行的开头,^\d表示必须以数字开头。
  • $表示行的结束,\d$表示必须以数字结束。

创建一个正则表达式的方式

var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');

split()可以用正则表达式拆分字符串

'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']

exec()方法可以匹配符合条件的字符串,有则返回数组,无则返回null

正则表达式为贪婪匹配,会尽可能匹配多的字符,加个?可以让其不采用贪婪匹配

全局匹配加g,可以多次执行exec()来搜索最匹配的项:

var r1 = /test/g;
// 等价于:
var r2 = new RegExp('test', 'g');

每次运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引

2.3.3 JavaScript Object Notation

JSON字符串必须用双引号"",Object的键也必须用双引号""

2.3.3.1 JSON序列化
JSON.stringify(对象,筛选键值或者传入函数对键值进行处理,指定缩进用的空白字符)

也可以定义一个toJSON()方法返回JSON应该序列化的数据

var xiaoming = {
    name: '小明',
    age: 14,
    gender: true,
    height: 1.65,
    grade: null,
    'middle-school': '\"W3C\" Middle School',
    skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
    toJSON: function () {
        return { // 只输出name和age,并且改变了key:
            'Name': this.name,
            'Age': this.age
        };
    }
};

JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'
2.3.3.2 JSON反序列化

可以用JSON.parse()把JSON格式的字符串变成一个JavaScript对象

2.4 面向对象编程

2.4.1原型

// 原型对象:
var Student = {
    name: 'Robot',
    height: 1.2,
    run: function () {
        console.log(this.name + ' is running...');
    }
};

function createStudent(name) {
    // 基于Student原型创建一个新对象:
    var s = Object.create(Student);
    // 初始化新对象:
    s.name = name;
    return s;
}

var xiaoming = createStudent('小明');
xiaoming.run(); // 小明 is running...
xiaoming.__proto__ === Student; // true

2.4.2 构造函数

function Student(name) {
    this.name = name;
    this.hello = function () {
        alert('Hello, ' + this.name + '!');
    }
}

通过new来构造一个对象

var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!

不用new的话就是一个普通的函数

2.4.3 原型继承

function inherits(Child, Parent) {
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}
function Student(props) {
    this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

function PrimaryStudent(props) {
    Student.call(this, props);
    this.grade = props.grade || 1;
}

// 实现原型继承链:
inherits(PrimaryStudent, Student);

// 绑定其他方法到PrimaryStudent原型:
PrimaryStudent.prototype.getGrade = function () {
    return this.grade;
};

JavaScript的原型继承实现方式就是:

  1. 定义新的构造函数,并在内部用call()调用希望“继承”的构造函数,并绑定this
  2. 借助中间函数F实现原型链继承,最好通过封装的inherits函数完成;
  3. 继续在新的构造函数的原型上定义新方法。

2.4.4 CLASS

这语言在ES6把以上说的继承方法封装成和java的class一样的继承方法了,不过由于ES6的支持度不广,说是不推荐用就是了。

3 浏览器

3.1 浏览器对象

对象名意义常用属性兼容性
window不但充当全局作用域,而且表示浏览器窗口innerWidthinnerHeight属性,可以获取浏览器窗口的内部宽度和高度;
对应的,还有一个outerWidthouterHeight属性,可以获取浏览器窗口的整个宽高
IE<=8不支持
navigator浏览器的信息appName:浏览器名称;
appVersion:浏览器版本;
language:浏览器设置的语言;
platform:操作系统类型;
userAgent:浏览器设定的User-Agent字符串
screen屏幕的信息screen.width:屏幕宽度,以像素为单位;
screen.height:屏幕高度,以像素为单位;
screen.colorDepth:返回颜色位数,如8、16、24。
location当前页面的URL信息href:URL地址
protocal:协议,如http
host:主机,一般是域名或者IP
port:端口
pathname:地址,如index.html
search:提交的表单,如?a=1
hash:类似于#h1之类的标记
assign():加载新页面的方法
reload():重新加载当前页面
document表示当前页面,document对象就是整个DOM树的根节点title:标题
cookie:当前页面的cookie
cookie可以用httpOnly来设定禁止被js读取,这个项自IE6 SP1开始支持
history保存了浏览器的历史记录back():后退
forward ():前进
历史遗留,由于ajax的使用不推荐这么返回

3.2 DOM

DocumentObjectModel(文档对象模型)

常用的获取DOM节点的方法

document.getElementById()
//ID选择器
document.getElementsByTagName()
//标签选择器
document.getElementsByClassName()
//类选择器
document.querySelector('#q1')
var ps = q1.querySelectorAll('div.highlighted > p');
//selector语法,截止IE8都有限支持

3.2.1 更新DOM

innerHTML:修改节点内整个html内容

innerTexttextContent:会对字符串进行HTML编码,不会被解释为HTML标签,IE<9不支持textContent

p.style.color:类似这样修改样式

3.2.2 插入DOM

appendChild:插入父节点最后,如果节点已经存在于当前的文档树,这个节点首先会从原先的位置删除,再插入到新的位置

从头创建一个节点的话:

var
    list = document.getElementById('list'),
    haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);

insertBefore:插入到指定位置

insertBefore(newElement, referenceElement);//两个参数都得是dom对象

3.2.3 删除DOM

// 拿到待删除节点:
var self = document.getElementById('to-be-removed');
// 拿到父节点:
var parent = self.parentElement;
// 删除:
var removed = parent.removeChild(self);
removed === self; // true

remove后的节点还在内存里面,随时可以调用

3.3 提交表单的方式



3.3 操作文件

在HTML表单中,可以上传文件的唯一控件就是

当一个表单包含时,表单的enctype必须指定为multipart/form-datamethod必须指定为post,浏览器才能正确编码并以multipart/form-data格式发送表单的数据

FILE API

html5新增的api,允许js读取文件内容

HTML5的File API提供了FileFileReader两个主要对象,可以获得文件信息并读取文件。

一个file api用例

3.4 AJAX 异步请求

var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象
//——————————————————————————//
//低版本IE用以下对象
var request = new ActiveXObject('Microsoft.XMLHTTP'); // 新建Microsoft.XMLHTTP对象
//——————————————————————————//
request.onreadystatechange = function () { // 状态发生变化时,函数被回调
    if (request.readyState === 4) { // 成功完成
        // 判断响应结果:
        if (request.status === 200) {
            // 成功,通过responseText拿到响应的文本:
            return success(request.responseText);
        } else {
            // 失败,根据响应码判断失败原因:
            return fail(request.status);
        }
    } else {
        // HTTP请求还在继续...
    }
}

XMLHttpRequest对象的open()方法有3个参数,第一个参数指定是GET还是POST,第二个参数指定URL地址,第三个参数指定是否使用异步,默认是true,所以不用写。

3.4.1 安全限制

JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致

解决方法:

  1. 通过Flash插件发送HTTP请求
  2. 通过在同源域名下架设一个代理服务器来转发
  3. JSONP

3.4.2 CORS

CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源。

取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin

3.5 PROMISE 异步执行

作用是异步执行任务

调用resolve方法时,Promise的状态就变成fulfilled,即操作成功状态。后续走then

调用reject方法时,Promise的状态就变成rejected,即操作失败状态,后续走catch

then():然后执行【括号内需要是promise对象】

catch():错误时执行

all():同时执行多个promise,后面加then()时,多个promise执行成功后再走then

race():同时执行多个promise,后面加then()时,多个promise第一个执行成功后就走then

3.6 Canvas 绘图

H5新组件

getContext('2d'):绘制2d图形

getContext("webgl"):绘制3d图形

4 jQuery

1.x版本——支持IE6-8

2.x版本——不支持IE6-8

\$被占用怎么办——jQuery.noConflict()可以还原\$这个变量【jq在占用\$前事先储存了它】

4.1 选择器

var div = $('#abc');//按ID来查
var ps = $('p');//按TAG来查
var a = $('.red'); //按class来查
var a = $('.red.green'); //按多个class来查 注意没有空格!
var email = $('[name=email]'); //按属性来查
var icons = $('[name^=icon]'); // 找出所有name属性值以icon开头的DOM
// 例如: name="icon-1", name="icon-2"
var names = $('[name$=with]'); // 找出所有name属性值以with结尾的DOM
// 例如: name="startswith", name="endswith"
$('p,div'); // 查多项,把

都选出来 $('ul.lang li');//层级选择 $('parent>child') //子选择器,两者必须为直属父子关系 $('ul.lang li:first-child'); //过滤器Filter

4.2 表单相关

针对表单元素,jQuery还有一组特殊的选择器:

  • :input:可以选择