定义变量
let
- 变量不能重复声明
- 有块级作用域(在一对大括号里面)
- var 的块级作用域只在函数里面
- 不存在变量提升,即只能在变量定义之后使用
不影响作用域链
{
let school = '学校';
function fn(){
console.log(school);
}
fn();
}
对比var ```javascript //获取div元素对象 let items = document.getElementsByClassName(‘item’);
//遍历并绑定事件 for(var i = 0;i<3;i++){ items[i].onclick = function(){ //修改当前元素的背景颜色 this.style.background = ‘pink’; } } for(let i = 0;i<3;i++){ items[i].onclick = function(){ //修改当前元素的背景颜色 items[i].style.background = ‘pink’; } } 若i用var定义,则i是window的属性,首次加载完成时被累加至3,则在点击修改颜色时,i为3 若i用let定义,则在块级作用域下,当点击修改颜色时,会查找该块中的i的值,且从内向外查找,所以i的值有效
<a name="YNEMI"></a>
## const
1. 定义时必须赋初始值,且之后不能进行修改
1. 对数组和对象,其元素的值可以修改,指针指向不变
```javascript
const NAKU = ['5t5','3u'];
NAKU.push('2250');
NAKU[0] = 'tokyo';
-
解构赋值
数组对应位置,对象对应名字
let list = ["悠一","杉木", "福山"];
let [you, sha, fu] = list;
对象的解构赋值,
let human = {
name: "naku",
age: 42,
tv: function(){
console.log("kongnigiwa");
}
}
let { tv, age } = human; // 只要名字一样就可以,不需要顺序
tv();
模板字符串
内容中可以出现换行符
let str = `<div></div>
<div></div>
<div></div>`;
变量拼接
let zou = `诹防顺`;
let en = `${zou}部一`;
console.log(en);
const LANGDU = {
en, // 利用前文相同名字为对象的属性赋值
chuyian(){ // 省略chuyan: function(){}
console.log("出演朗读剧")
}
}
箭头函数
函数的定义方式:
一般
const a = function() {
}
对象字面量中
const obj = {
b: function() {
},
c() {
}
}
箭头函数
let fn = (a, b) => {
return a+b;
}
箭头函数中
this
是静态的,this 始终指向函数声明时所在的最近作用域下的 this 的值,即使使用.call
方式 也不改变- 不能作为构造实例化对象,即箭头函数被new
- 不能使用
arguments
变量,arguments
是传递给函数的由其参数组成的数组,可以访问与修改。 简写
- 当形参有且只有一个时,省略小括号
- 当代码体只有一条语句的时候,省略花括号,且同时省略return关键字,此时执行结果就是函数的返回值
let double = a => a+a;
let box1 = document.getElementById("div1");
box1.addEventListener("click", function(){
let _this = this; // 保存this
setTimeout(function(){
// this.style.background = '#b7f79a'; 这个this指向的是window,因为最近的这个函数被调用时
_this.style.background = '#b7f79a';
}, 2000);
});
let box2 = document.getElementById("div2");
box2.addEventListener("click", function(){
setTimeout(()=>{ // 箭头函数的this为声明时所在位置的this
this.style.background = '#b7f79a';
}, 2000);
})
箭头函数适合与
this
无关的回调,定时器、数组的方法回调- 不适合与
this
有关的回调,事件回调、对象的方法 - js函数内部的this指向
函数参数默认值
形参初始值,一般位置靠后
function(a,b,c=10){
}
与解构赋值结合
function connect({host='127', username, password, port}){
console.log(host,username,password, port)
}
connect({
// host: 1,
username: 'root',
password: '123',
port: 3300
})
对象的字面量
定义对象时,直接使用const obj = { }
字面量的增强:
属性的增强写法:
const name = 'ldf';
const age = 23;
const height = 1.60;
const I = {
name,
age,
height
}
函数的增强写法:
const obj = {
// 普通写法
run: function () {
},
// 增强
eat(){
}
}
rest参数
代替arguments
function date(...args){
console.log(args); // 输出的是数组
}
date("悠一","杉田","樱井");
必须放在参数的最后
-
扩展运算符
函数调用时
...
,将数组转换为逗号分隔的参数序列function date(){
console.log(args); // 输出的是数组
}
const arr = ["悠一","杉田","樱井"];
date(...arr); // =>> date("悠一","杉田","樱井");
可用于数组的合并
let names=['jojo','dio'];
let shengyou = ["悠一","杉田","樱井"];
const zuhe = [...names, ...shengyou];
可用于数组的克隆
将伪数组转为真正的数组
const divs = document.querySelectorAll("div");
const divArr = [...divs];
Symbol
symbol 是一种基本数据类型 (primitive data type)。Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:”new Symbol()”。
- 创建
let s = Symbol("123");
let s = Symbol.for("123");
- Symbol 的值不能与其他数据进行运算
- Symbol 的值是唯一的,用来解决命名冲突
- Symbol定义的对象属性不能使用
for...in
循环遍历,但是可以使用Reflect.ownKeys
来获取对象的所有键名全部数据类型
USONB
u undefined
s string symbol
o object
n null number
b boolean
Symbol的应用
Symbol是独一无二的,为对象添加属性与方法
let game = {
name: "els",
up(){
console.log("hhh");
}
}
let methods = {
up: Symbol()
}
game[methods.up] = function(){ // 方式一
console.log("sss");
}
let youxi = {
name: 'zhuque',
[Symbol("zq")]: function(){ // 方式二
console.log("zhuque game");
}
}
迭代器
迭代器(iterator),是一种接口,为各种不同的数据结构提供统一的访问机制
原生具备迭代器的数据有:Array,Arguments,Set,Map,String,TypeArray,NodeList
- 可用 for of 遍历
let shengyou = ["悠一", "梶裕贵","润","樱井"];
for(let s of shengyou){
console.log(s);
}
// 使用 for in 输出的是下标
- 可用 for of 遍历
应用,自定义遍历数组,Symbol.iterator 为每一个对象定义了默认的迭代器。
const banji = {
name: "暗杀教室",
stuts: ["杀老师", "小蓝","小绿","sense"],
[Symbol.iterator](){
let index = 0; // 定义索引
let _this = this; // 保存this指向
return {
next: function(){
if(index < _this.stuts.length){
const result = {value: _this.stuts[index], done: false};
index++;
return result;
}else{
return {value: undefined, done: true};
}
}
}
}
};
for(let i of banji){
console.log(i);
}
生成器
- 生成器(Generator)是一个特殊的函数,应用于异步编程,可以解决一定的回调地域问题
- 定义时,需要在function和函数名之间加一个
*
field
语句将函数体分成多个块,定义对象的时候返回一个迭代器对象function * gen(){
console.log("块一");
yield 'y1';
console.log("块二");
yield 'y2';
console.log("块三");
yield 'y3';
}
let iter = gen(); // 返回一个迭代器对象
// 通过它的next方法执行生成器的内容
console.log(iter.next()); // 块一 {done: false,value: "y1"}.先执行第一个块的语句,再返回迭代器的next的返回值
console.log(iter.next()); // 块二 {done: false,value: "y2"}
for(let v of iter){
console.log(v); // 每一次返回结果为yield语句的内容 y1 y2 y3,<--这个搞不懂
}
可以在next方法中传参,其作为相应位置的前一个yield语句的返回结果
function * gen(){
console.log("块一");
let a = yield 'y1';
console.log(a); // aa
console.log("块二");
yield 'y2';
console.log("块三");
yield 'y3';
}
let iterator = gen(); // 返回一个迭代器对象
iterator.next();
iterator.next("aa"); // 传给第一个yield
生成器在计时器的示例
function one(){
setTimeout(() => {
console.log(111);
ite.next();
}, 1000);
}
function two(){
setTimeout(() => {
console.log(222);
ite.next();
}, 2000);
}
function three(){
setTimeout(() => {
console.log(333);
ite.next();
}, 3000);
}
function * gen(){
yield one();
yield two();
yield three();
}
let ite = gen();
ite.next();
Promise
- 用于异步编程,可以解决回调地狱问题,语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
- 一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。 ? resolved ?
- 已拒绝(rejected): 意味着操作失败。 ```javascript // 简单例子 const p = new Promise(function(resolve, reject){ // 模拟一个异步操作 setTimeout(() => { // let data = “数据库中的数据”; // resolve(data); // 执行这个则表示成功 let err = “获取数据失败”; reject(err); // 执行这个则表示失败 }, 1000); }); p.then(function(data){ // 第一个是返回成功的回调函数 console.log(data); }, function(reason){ // 第二个是返回失败的回调函数 console.error(reason); })
// 或者 p.then((data) => {成功时}).catch((err) => {失败时})
2. 定义`Promise`对象时需要使用一个函数作为参数,这个函数也拥有两个参数 都是函数 用来改变该Promise对象的状态(pending -> resolved 或 pending -> rejected)。如果改变已经发生了,你再对`Promise`对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
2. Promise对象拥有一个 `then` 方法,为Promise实例添加状态改变时的回调函数。`then`方法的返回结果也是一个Promise对象,这个对象状态由回调函数的执行结果决定
1. 若then的回调函数的返回结果是 非promise类型的属性,则状态为成功,且返回值为对象成功的值
1. 若then的回调函数的返回结果是 promise类型的属性,则这个返回的promise对象的状态决定了then方法返回的promise对象的状态
1. 若then的回调函数的返回结果为抛出错误,则状态为失败
4. 有了`Promise`对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,`Promise`对象提供统一的接口,使得控制异步操作更加容易。
4. `catch`方法,专门写返回失败的回调函数,就是相对于`then`不写第一个回调函数
当需要多层 Promise 对数据进行处理时,比如 第一层拿到数据,处理,返回数据处理结果1;第二层对结果1做处理,得到结果2;第三层对2进行处理,得到3。二三层的 Promise 并没有异步操作。则可以简写
```javascript
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa');
}, 1000)
}).then(res => {
...处理1
return new Promise(resolve => {
resolve(res+'111')
})
}).then(res => {
...处理2
return new Promise(resolve => {
resolve(res+'222')
})
}).then(res => {
...处理3
return new Promise(resolve => {
resolve(res+'333')
})
})
// 简写:
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa');
}, 1000)
}).then(res => {
...处理1
return Promise.resolve(res + '111') // return res + '111'
}).then(res => {
...处理2
return Promise.resolve(res + '222') // return res + '222'
}).then(res => {
...处理3
return Promise.resolve(res + '333') // return res + '333'
})
出错时 return Promise.reject('错误信息') // 或者 throw '错误信息'
最后 .catch(err => {
... 处理
})
all
当需要多个请求结果时,可以用 Promise 的 all 方法,对多个p的结果进行判断,同时判断他们是否都得到。
let p1 = new Promise( )
let p2 = new Promise( )
Promise.all([p1, p2]).then(results => {
results[0] 第一个 p 的结果
results[1] 第二个 p 的结果
})
Set
Set
集合,成员值唯一(自动去重),实现了iterator
接口,可以使用扩展运算符和for of
。- 集合的本质是对象
- 常用属性与方法:
- 元素个数:
s.size
- 添加新的元素:
s.add('newElement')
- 删除元素:
s.delete('元素3')
- 检测:
s.has('元素2')
返回true或false - 清空:
s.clear()
- 进一步使用: ```javascript
- 元素个数:
- 数组去重 let arr = [1,2,3,2,3,4,5,6,5,4]; let result = […new Set(arr)];
- 交集 let arr2 = [2,3,2,4,5] let result2 = […new Set(arr)].filter(item => { let s2 = new Set(arr2); if(s2.has(item)) return true; else return false; })
- 并集 let result3 = […new Set([…new Set(arr), …new Set(arr2)])];
- 差集,交集取反 let result4 = […new Set(arr)].filter(item => { let s2 = new Set(arr2); return !s2.has(item); }) ```
Map
- 键值对的集合,但是其
键
不限于字符串。也实现了iterator
接口。 - 常用属性与方法:
let m = new Map();
- 添加元素:
m.set(,)
- 大小:
m.size
- 删除:
m.delete(键)
- 获取:
m.get(键)
- 清空:
m.clear()
- 添加元素:
class类
- 比ES5更简洁
- 构造方法为
constructor(){}
,类的方法写法:名字(){}
静态属性方法
函数对象中
function Phone(){}
Phone.name = "nokia"; // 这个name属于函数对象,而不属于实例对象
Phone.propotype.size = '5.5inch'; // 原型对象
let nokia = new Phone();
nokia.name; // undefined
nokia.size; // 5.5inch 实例对象与原型对象想通
面向对象中
class Phone{
static name = "手机"; // 静态对象
}
let nokia = new Phone();
nokia.name; // undefined,此属性属于类,而不属于实例对象
继承
1. function
// 使用function实现继承
function Flower(name, color){
this.name = name;
this.color = color;
}
Flower.prototype.say = function(){
console.log("I am a flower");
}
function Lily(name, color, place, time){
Flower.call(this, name, color);
this.place = place;
this.time = time;
}
// 设置子级构造函数的原型
Lily.prototype = new Flower;
Lily.prototype.constructor = Lily;
// 声明子类的方法
Lily.prototype.boom = function(){
console.log("boom...");
}
Lily.prototype.fall = function(){
console.log("fall...");
}
const you = new Lily('百合花','白色','中国','春天');
console.log(you);
2. class,继承+重写父类方法
// class
class Phone{
constructor(brand, price){
this.brand = brand;
this.price = price;
}
call(){
console.log("call me by your name");
}
}
// 继承
class SmartPhone extends Phone{
constructor(brand, price, color, size){
super(brand, price);
this.color = color;
this.size = size;
}
phone(){
console.log("拍照?");
}
playGame(){
console.log("玩游戏?");
}
// 重写,完全重写
call(){
// 不能用 super() 调父类同名方法
console.log("call you");
}
}
let onePlus = new SmartPhone("1+", 1999,"白色","5.4inch");
console.log(onePlus);
get set
简单使用
class Game{
get price(){
console.log("get get get");
return "属性值"; // 返回的就是这个属性(price)的值
}
set price(newVal){ // 设置属性值,必须有一个参数
console.log("set set set");
}
}
let g = new Game();
console.log(g.price); // 使用该属性时,调用get方法,得到其返回值
g.price = 'free'; // 调用set方法
数值扩展
1. Number.EPSILON
- Number.EPSILON 的值接近一个极小值(2.22E-16),当两个浮点数的差值小于
// 当两个浮点数的差值小于这个值时,判断他俩相等
function equal(a, b){
return Math.abs(a-b) < Number.EPSILON;
}
2. 二、八、十、十六进制
- 二进制,以
0b
开头,如0b1010
- 八进制,以
0o
开头,如0o777
- 十进制
- 十六进制,以
0x
开头,如0xfff
3. 检测是否为某个数
Number.isNaN( 数 ) 是否为NaN
Number.isFinite(数) 是否为无限
Number.isInteger(数) 是否为整数
Math.sign(数) 判断数为 整数(返回1) 0 负数(返回-1)
4. Number.parseInt Number.parseFloat
截取字符串中的数值部分
5. Math.trunc
将数字的小数部分抹掉
对象方法的扩展
Object.is
判断两个值是否完全相等,与===
有点区别,比如在判断两个NaN是否相等
Object.assign
对象的合并,将前者同名属性覆盖,Object.assign(o1, o2)
Object.setPropotypeOf Object.getPropotypeOf
设置、获取原型对象
模块化
- 模块化是指将一个大的程序文件 拆成许多小的文件,然后将小文件组合起来。
- 优点:防止命名冲突,可以代码复用,有高维护性
export
和 import
- 除了默认导出外,都需要导入时的名字与导出时的名字一样
暴露的方法
分别暴露
export let school = "ESM";
export function learn(){
console.log("goooood!");
}
统一暴露
let school = "ESM";
function learn(){
console.log("goooood!");
}
export {school, learn};
默认暴露
export default {
name: 'nakamura',
job: function(){
console.log("声优");
}
}
引入的方法
通用的引入
import * as m1 from "./m1.js";
// 使用
m1.func()...
解构赋值形式
import {school, learn, default as mm} from './m1.js';
import aaan from './m.js'; // 默认导出的一个东西,不加 {}
引入的变量重名时,使用 as 建立别名。引入default时也使用别名
简便形式
- 只能引入默认暴露的内容
import m1 from './m1.js'; // m1.js里面只有默认暴露的东西
m1.job();
引入安装的包
- 比如引入
jquery
包
- 安装 npm i jquery
- 引入使用 import $ from ‘jquery’;
- 这种方式,如果直接在项目中使用(不打包),好像会出错‘Relative references must start with either “/“, “./“, or “../“.’。
项目打包
- 为了支持大多数浏览器的运行,需要用babel将源js文件转化为ES5格式,再打包
- 安装工具 babel-cli babel-preset-env browserify(webpack)
- 执行转化 npx babel js(原文件夹) -d dist/js(目标文件夹)
- 打包 npx browserify dist/js/app.js(输出文件) -o(输出) dist/bundle.js