ECMAScript 和 JavaScript的关系
ECMAScript是JavaScript的规格,JavaScript是ECMAScript的一种实现
Var
变量提升的工作原理:当 进 入 一 个 JavaScript 环 境 时,JavaScript 引 擎 并 不 是 立 刻 直 接 从 上 到 下 执 行 代 码 的, 而 是 先 扫 描 所 有 代 码, 将 var 声 明 的 变 量 集 合 在 一 起, 组 成 一 个 词 法 环 境
- 无块级作用域
- 存在变量提升
let
- 只在代码块之内有效
- 同一代码块中,不允许重复声名(可以重复赋值)
- 不存在变量提升
- 不会成为window的属性
const
- 只在代码块之内有效
- 同一代码块中,不允许重复声名(可以重复赋值)
- 不存在变量提升
- 不会成为window的属性
- 用于定义一个常量,常量不允许被重新赋值
- 如果这个变量是基本数据类型,声明后不允许修改该值
- 如果这个变量是引用数据类型,虽然我们不能修改该值,但是可以修改它属性的值
暂时性死区(开始于函数开头,终止于变量声名所在的那一行)
function fn = {
console.log(a);
let a = 2023;
}
字符串扩展
检索字符串:includes()、startsWith()、endsWith()(区分大小写)
A.includes(B,index)
A.startsWith(B,index)
A.endsWith(B,index)
//第1个参数表示“被包含的字符串”
//第2个参数可以省略,如果省略表示检索整个字符串
//includes() startsWith()第2个参数表示“从第index个字符串上进行检索”
//endsWith()第2个参数表示“对前index个字符串进行检索` ”
重复字符串:repeat()(n一般去正整数)
注意:repeat()并不会修改原来字符串的值,需要创建一个新的字符串进行接接收
const str = "lyyc";
const newStr = str.repeat(3);
console.log() //lyyclyyclyyc
长度补齐 pandStart() pandEnd()
pandStart(len,str);
pandEnd(len,str);
//注意:len是必选参数,用于指定字符串的长度
//str可选,表示用来补全的字符串,如果省略则用空格进行补齐
使用:补全日期 输出“2023-02-23”的形式
const d = new Date();
const year = d.getFullYear();
const month = (d.getMonth()).toString().pandStart(2,"0");
const day = (d.getDate()).toString().pandStart(2,"0");
const time = year + "-" + month + "-" + day;
console.log(time)
模板字符串(用``引起来的字符串)
-
多行字符串
- 使用``反引号来替代单引号或者双引号
-
字符串拼接
const user = "lyyc"; const boyFriend = "ziop"; const is = "是"; const res = "的男朋友"; const f = `${boyFriend}是${user}res`;
注意:在模板字符串中,单双引号不需要进行转义,可以直接保留单双引号 ,同时也会保留空格与换行
数组扩展
判断数组Array.isArray()
Array.isArray(值); 返回布尔值
创建数组Array.of()
转换数组Array.from()
类数组(伪数组)
特点:拥有length属性
可以使用下标的方式进行访问,但是不能使用数组的其他方法,例如push(),pop()
- 字符串
- 函数的arguments
- DOM的NodeList
在ES5中,将类数组转化为数组的方法:Array.prototype.slice.apply()接收类数组作为参数,返回一个真正的数组
- Array.from()也可以将Set与Map转化为真正的数组,而Array.prototype.slice.apply()只能将类数组转化为真正的数组
填充数组 fill()
语法:arr.fill(value,start,end (value表示用来填充的值,start表示的填充的开始位置,end表示填充的结束位置。
如果后两个省略,这表示填充全部)
注意:fill()方法会改变原来数组的值
打平数组flat() 将多维数组转化一维数组
语法:flat(正整数或者Infinity) 参数表示想打平的层数
注意:flat(Infinity)不管多少层都会转化为一维数组,使用比较多
使用ES5实现数组的扁平化
方法一:(通用)
function flatArr(arr) {
var resultArr = [];
arr.forEach(function (item) {
var str = Object.prototype.toString.call(item);
if (str.indexOf("Array") !== -1) {
resultArr = resultArr.concat(flatArr(item));
} else {
resultArr = resultArr.concat(item);
}
});
return resultArr;
}
var arr = [1, [2, [3]], 4, 5];
console.log(flatArr(arr));
var arr = [1, [2, [3]], 4, 5];
var temArr = arr.toString().split(",");
var resultArr2 = temArr.map(function (item) {
return parseInt(item);
})
console.log(resultArr2);
var arr = [1, [2, [3]], 4, 5];
var temArr = arr.join().split(",");
var resultArr2 = temArr.map(function (item) {
return parseInt(item);
})
console.log(resultArr2);
判断元素includes()
语法:arr.includes(value,index); value必选参数 表示要寻找的值 index表示开始寻找的位置,不写默认从0开始
对比includes()、indexOf()、find()方法
var arr = ["lyyc", "ziop", "frankZhang"];
console.log(arr.includes("ziop")); //true
console.log(arr.indexOf("ziop") !== -1); //true
const res = arr.find(value => {
return value === "ziop"
});
console.log(res === "ziop"); //true
总结:includes()方法与IndexOf()方法都是用来判断数组中是否存在某个值的,其中includes()方法用起来更加方便
而find()用于判断数组中是否存在符合条件的值
查找元素 find() findIndex() 只能返回第一个符合条件的元素
find()查找数组中符合条件的元素,返回第一个符合条件的元素
语法:find(function(value,index,array){})
find()方法接收一个回调函数作为参数。回调函数本身包括3个函数,value表示数组的值,index表示数组元素的索引 array表示数组本身 后两个数组可以省略
findIndex()查找数组中符合条件的元素下标,返回第一个符合条件的元素下标
语法:findIndex(function(value,index,array){})
findIndex()方法接收一个回调函数作为参数。回调函数本身包括3个函数,value表示数组的值,index表示数组元素的索引 array表示数组本身 后两个数组可以省略
对比:IndexOf()、lastIndex( )、find() findIndex()
IndexOf()、lastIndex( n)方法都是用来判断数组中是否存在某个值,
如果想要查找符合某个条件的元素或者元素下标使用find() findIndex()
判断数组中的元素是否满足某个条件 every() some()
every():用于判断数组中的元素是否都满足某一个条件。如果都满足,就返回true,如果有一个不满足就返回false 类似于&
some():用于判断数组中的元素是否满足某一个条件,如果有一个满足,就返回true,如果都不满足就返回false 类似于|
语法:arr.every(function(value,index,array){}) arr.some(function(value,index,array){})
every() some()方法接收一个回调函数作为参数。回调函数本身包括3个函数,value表示数组的值,index表示数组元素的索引 array表示数组本身 后两个数组可以省略
注意:如果对空数组进行判断 那么every()什么时候都会返回true,而some()什么时候后返回false
遍历数组的几个方法:keys() values() entries() 都会返回一个Iterator对象 实例方法
keys()遍历数组的键
语法:arr.keys()
const arr = ["ziop", "lyyc", "frankZhang"];
for (const item of arr.keys()) {
console.log(item);
}
// 0 1 2
values()遍历数组的键
语法:arr.values()
const arr = ["ziop", "lyyc", "frankZhang"];
for (const item of arr.values()) {
console.log(item);
}
// ziop lyyc frankZhang
entries()遍历数组的键
语法:arr.entries()
const arr = ["ziop", "lyyc", "frankZhang"];
for (const item of arr.entries()) {
console.log(item);
}
// [0,'ziop'] [1,'lyyc'] [2,'frankZhang']
数组和字符串都有的方法
-
indexOf()和lastIndexOf()
如果indexOf()方法能从字符串和数组中找到特定的值,就返回该值的下标,否则返回-1
-
includes()
如果includes()方法能从字符串和数组中找到特定的值,就返回true,否则返回false
-
slice()
slice(start,end)表示截取的范围为【start,end)。当end省略时,表示截取的范围为从start到结尾
-
concat()
合并两个数组,或者合并两个字符串
对象的扩展
简写语法
属性简写
//完整方式
const obj = {foo:foo,bar:bar};
//简写方式
const obj = {foo,bar};
方法简写
const obj = {
//完整写法
foo:function(){
console.log("foo");
}
//简写方式
foo(){
console.log("foo");
}
}
注意:简写的方式,只能用于定义对象的方法,不能用于声明函数
判断相等:Object.is()
语法:Object.is(a,b)
Object.is()接收两个值作为参数,当两个值类型相同且值相等时,返回true,否则返回false
合并对象:Object.assign()
语法:Object.assign(obj1,obj2……objn)
Object.assign()方法表示将后面所有的对象合并到第一个对象中
注意:Object.assign()方法会改变原来的对象,也就是将obj2、………objN合并到obj1中。
例子:
const obj1 = {a:1,b:2};
const obj1 = {c:3,d:4};
Object.assign(obj1,obj2);
console.log(obj1); //{a:1,b:2,c:3,d:4}
console.log(obj2); //{c:3,d:4}
Proxy
简介
在 ES6 中,我们可以使用 Proxy 来代理某一个对象。所谓代理一个对象,指的是当我们想要 访问一个对象时,并不直接访问这个对象,而是先访问它的 Proxy
访问机制
语法:
const 变量名 = new Proxy(target, handler);
说明:Proxy() 是一个构造函数,它可以接收两个参数,其中 target 表示原对象,handler表示配置 对象。
举个例子:
// 原对象
const person = {
name: "Jack",
age: 24
};
// 配置对象
const handler = {
get(obj, key, proxy) {
console.log(ˋ你访问了${key}属性ˋ);
return obj[key];
}
};
// Proxy对象
const p = new Proxy(person, handler);
console.log(p.name);
//输出结果
//你访问了name属性
//Jack
分析:
每当我们读取对象的属性时,就会自动触发这个 get() 方法。
const p=new Proxy(person, handler); 表示定义了一个代理对象 p,p 就是一个 Proxy 对 象。如果我们想要访问 person 对象,可以不直接访问,而是通过 p 来访问。也就是说,此时访问 person 对象有以下两种方式。 直接访问:通过 person 来访问,比如 person.name。 间接访问:通过 p 来访问,比如 p.name。
在这个例子中, console.log(p.name); 这句代码访问了属性,此时会触发 get() 方法。从输出 结果中可以看出,代理对象的 get() 方法先执行,属性访问后执行
方法
1.get(),可以使用 get() 方法来拦截对象的“读”操作
语法
get(obj, key, proxy) {
……
return obj[key];
}
说明:
get() 方法有 3 个参数,obj 是原对象,key 是属性名,proxy 是代理对象。需要注意的是, get() 方法要返回 obj[key],不然就无法访问原对象的属性值。
举个例子 (读取存在的数据)
// 原对象
const person = {
name: "Jack",
age: 24
};
// 配置对象
const handler = {
get(obj, key, proxy) {
console.log(obj);
console.log(key);
console.log(proxy);
return obj[key];
}
};
// Proxy对象
const p = new Proxy(person, handler);
const name = p.name;
//控制台上输出结果如下:
//{name: "Jack", age: 24}
//name
//Proxy {name: "Jack", age: 24}
举个例子 (读取不存在的数据)
// 原对象
const person = {
name: "Jack",
age: 24
};
// 配置对象
const handler = {
get(obj, key, proxy) {
if (obj.hasOwnProperty(key)) {
return obj[key];
} else {
throw new Error("属性不存在");
}
}
};
// Proxy对象
const p = new Proxy(person, handler);
const gender = p.gender;
//控制台上输出结果如下:
//(报错) Uncaught Error: 属性不存在
分析:一般情况下,读取对象一个不存在的属性,会返回 undefined,但是这个 undefined 之后和其 他值进行计算时可能会导致一些 bug。我们可以在 get() 方法中进行一些设置,使程序在读取不存 在的属性时抛出一个异常,而不是返回 undefined。