为什么要重新梳理js基础
vuejs建立在现在浏览器的特性之上,有专门的webpack打包工具,支持ECMA6语法,vue3同时又支持TypeScript,ESLint语法检查,vite快速预览改动等等
如果了解react.js,还需要了解 独有的 JSX 语法,在使用jsx时又需要了解为什么要添加标识(type=“text/babel” ),这就需要了解Browser.js ,Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,
所以,大家常说的大前端不是没有道理的,像我这个后端java开发的,本来只是想看看vuejs结合elementui,有哪些组件,以及通过vuejs怎么使用这些组件,现在首先vuejs这一关都不好搞,不敢想后面这么来使用,百步之下,始于足下,先把原生js以及EVMA6新特性来回顾一下,看看有哪些遗漏的。
JavaScript 与 TypeScript 的区别
以及 ECMAScript 6 与 ECMAScript 5的关系
TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。
TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
简单来说,所有的.js文件后缀名可以直接改成.ts,通过tsc命令编译成js.
ecma6是js的新版本,类似于jdk1.5与jdk8的区别,版本升级,支持新的特性
ECMAScript 6 目前基本成为业界标准,它的普及速度比 ES5 要快很多,主要原因是现代浏览器对 ES6 的支持相当迅速,尤其是 Chrome 和 Firefox 浏览器,已经支持 ES6 中绝大多数的特性。简单来说,可以之chrome的控制台直接使用ECMA6的语法
ECMAScript 6 ->简明教程
教程本身够简洁的,我这里挑选自己相对薄弱的地方,记录下来
知识点强化
1 let const block{} 变量以及作用域
var aa = 2;
{
let aa = 3;
console.log(aa); // 3
}
console.log(aa); // 2
{
const ARR = [5,6];
ARR.push(7);
console.log(ARR); // [5,6,7]
//ARR = 10; // TypeError
}
2 ()=>{} 箭头函数
var getPrice = function() {
return 4.55;
};
// Implementation with Arrow Function
var getPrice = () => 4.55;
console.log(getPrice())
let arr = ['apple', 'banana', 'orange'];
let breakfast = arr.map(fruit => {
return fruit + 's';
});
console.log(breakfast); // apples bananas oranges
var age=0;
person对象方法中使用箭头函数,this不是指向window对象,而是 指向 person 对象
function Person() {
this.age = 0;
setInterval(function growUp() {
// 在非严格模式下,growUp() 函数的 this 指向 window 对象
this.age++;
}, 1000);
}
var person = new Person();
function Person1() {
var self =this;
this.age = 0;
setInterval(function growUp() {
// 在非严格模式下,growUp() 函数的 this 指向 window 对象
self.age++;
}, 1000);
}
var person1 = new Person1();
function Person3(){
this.age = 0;
setInterval(() => {
// |this| 指向 person 对象
this.age++;
}, 1000);
}
var person3 = new Person3();
3 函数参数 默认值
let getFinalPrice = (price, tax=0.7) => price + price * tax;
var tax=getFinalPrice(500); // 850
console.log(tax)
4 对象词法扩展 简写 快速定义一个带有构造函数的类class
function getCar(make, model, value) {
return {
// 简写变量
make, // 等同于 make: make
model, // 等同于 model: model
value, // 等同于 value: value
// 属性可以使用表达式计算值
['make' + make]: true,
// 忽略 `function` 关键词简写对象函数
depreciate() {
this.value -= 2500;
}
};
}
let car = getCar('Barret', 'Lee', 40000);
5 对象和数组解构 解构可以避免在对象赋值时产生中间变量:
function foo() {
return [1,2,3];
}
let arr21 = foo(); // [1,2,3]
let [a, b, c] = foo();
console.log(a, b, c); // 1 2 3
function bar() {
return {
x: 4,
y: 5,
z: 6
};
}
let {x: x, y: y, z: z} = bar();
console.log(x, y, z); // 4 5 6
合并 展开 spread rest 数组与单个对象快速转换 …
function foo1(x,y,z) {
console.log(x,y,z);
}
let arr1 = [1,2,3];
foo1(...arr1); // 1 2 3
function foo2(...args) {
console.log(args);
}
foo2( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
6.对象超类 Object.setPrototypeOf(child, parent); 这里可以认识一下对象原型链
var parent = {
foo() {
console.log("Hello from the Parent");
}
}
var child = {
foo() {
super.foo();
console.log("Hello from the Child");
}
}
Object.setPrototypeOf(child, parent);
child.foo(); // Hello from the Parent
// Hello from the Child
7 模板语法和分隔符 Hi ${user}!
let user = 'Barret';
console.log(`Hi ${user}!`); // Hi Barret!
8 for…of VS for…in
for…of 用于遍历一个迭代器,如数组
let nicknames = ['di', 'boo', 'punkeye'];
//nicknames.size = 3;
for (let nickname of nicknames) {
console.log(nickname);
}
// 结果: di, boo, punkeye
for…in 用来遍历对象中的属性:
let nicknames2 = ['di', 'boo', 'punkeye'];
nicknames2.size = 3;
for (let nickname in nicknames2) {
console.log(nickname);
}
//Result: 0, 1, 2, size
function colors(){
return{
red:0,
blue:1,
green:2
}
}
let colors0=colors();
for(let color in colors0){
console.log(color);
}
9 Map
var myMap = new Map();
var keyString = "a string",
keyObj = {},
keyFunc = function () {};
// 设置值
myMap.set(keyString, "value 与 'a string' 关联");
myMap.set(keyObj, "value 与 keyObj 关联");
myMap.set(keyFunc, "value 与 keyFunc 关联");
//myMap.size; // 3
// 获取值
myMap.get(keyString); // "value 与 'a string' 关联"
myMap.get(keyObj); // "value 与 keyObj 关联"
myMap.get(keyFunc); // "value 与 keyFunc 关联"
10 Set
let mySet = new Set([1, 1, 2, 2, 3, 3]);
console.log(mySet.size); // 3
mySet.has(1); // true
//mySet.add('strings');
//mySet.add({ a: 1, b:2 });
11 类 class
ES6 中有 class 语法。值得注意是,这里的 class 不是新的对象继承模型,它只是原型链的语法糖表现形式。
class Task {
constructor() {
console.log("task instantiated!");
}
showId() {
console.log(23);
}
static loadAll() {
console.log("Loading all tasks..");
}
}
console.log(typeof Task); // function
let task = new Task(); // "task instantiated!"
task.showId(); // 23
Task.loadAll(); // "Loading all tasks…
12 类中的继承和超集: 在类中定义函数不需要使用 function 关键词
class Car {
constructor() {
console.log("Creating a new car");
}
}
class Porsche extends Car {
constructor() {
super();
console.log("Creating Porsche");
}
}
let car21 = new Porsche();
// Creating a new car
// Creating Porsche
isPrototypeOf 检测一个对象是否存在于另一个对象的原型链中
Porsche.prototype.isPrototypeOf(car21)
检测一个对象car21是否存在于另一个对象Porsche的原型链中
prototype 原型对象
下面代码为自定义类型函数定义两个原型成员。
var f = function () {} //定义函数
f.prototype = { //函数的原型对象
a : 1,
b : function () {
return 2;
}
}
console.log(f.prototype.a); //读取函数的原型对象的属性a,返回1
console.log(f.prototype.b()); //读取函数的原型对象的属性b,返回2
var o = new f(); //实例对象
console.log(o.a); //访问原型对象的属性
console.log(o.b()); //访问原型对象的属性
为了方便判定,Object 对象定义了 isPrototypeOf() 方法,该方法可以检测一个对象的原型对象。
通过下面示例,可以判断 f.prototype 就是对象 o 的原型对象,因为其返回值为 true。
prototype.isPrototypeOf(o)
hasOwnProperty() 这个方法会查找一个对象是否有某个属性,但是不会去查找它的原型链。
var obj = {
a: 1,
fn: function(){
},
c:{
d: 5
}
};
console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty('fn')); // true
console.log(obj.hasOwnProperty('c')); // true
console.log(obj.c.hasOwnProperty('d')); // true
console.log(obj.hasOwnProperty('d')); // false, obj对象没有d属性
var str = new String();
// split方法是String这个对象的方法,str对象本身是没有这个split这个属性的
console.log(str.hasOwnProperty('split')); // false
13 对象定义 属性 方法
var car = {name:"Fiat", model:500, color:"white"};
对象定义
var person = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"blue",
fullName:function (){
return this.firstName+this.lastName;
}
};
对象属性
person.lastName;
person["lastName"];
对象方法 对象的方法定义了一个函数,并作为对象的属性存储。
//对象方法通过添加 () 调用 (作为一个函数)。
name = person.fullName();
//如果你要访问 person 对象的 fullName 属性,它将作为一个定义函数的字符串返回:
name = person.fullName;
14 Symbol 生成一个唯一的标识符
var sym = Symbol( "some optional description" );
console.log(typeof sym); // symbol
var o = {
val: 10,
[ Symbol("random") ]: "I'm a symbol",
};
console.log(Object.getOwnPropertyNames(o)); // val
15 迭代器(Iterators) 可以通过 Symbol.iterator 自定义一个对象的迭代器。
//迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素时,迭代器便会退出。
// 它提供了 next() 函数来遍历一个序列,这个方法返回一个包含 done 和 value 属性的对象。
var arr31 = [11,12,13];
var itr = arr31[Symbol.iterator]();
itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }
itr.next(); // { value: undefined, done: true }
16 Generators ES6 的新特性,它允许一个函数返回的可遍历对象生成多个值。
function *infiniteNumbers() {
var n = 1;
while (true){
yield n++;
}
}
var numbers = infiniteNumbers(); // returns an iterable object
numbers.next(); // { value: 1, done: false }
numbers.next(); // { value: 2, done: false }
numbers.next(); // { value: 3, done: false }
17 Promise Promises ES6 对 Promise 有了原生的支持, 一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者rejected。
Promise 对象用于表示一个异步操作的最终完成(或失败),及其结果值。Promise 一旦被创建,会立即执行,共有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步结果可以决定当前是哪一种状态,状态一旦被确定就再也不会更改。也就是说, Promise 对象状态的更改只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。
参照-》Promise 执行机制
var p = new Promise(function(resolve, reject) {
if (2>1) {
// fulfilled successfully
resolve('2>1 yes');
} else {
// error, rejected
reject('something is wrong');
}
});
p.then((val) => console.log("Promise Resolved", val),
(err) => console.log("Promise Rejected", err));
“函数瀑布” 来实现的。可想而知,在一个复杂的程序当中,用 “函数瀑布” 实现的程序无论是维护还是异常处理都是一件特别繁琐的事情,而且会让缩进格式变得非常冗赘。
setTimeout(function () {
console.log("First");
setTimeout(function () {
console.log("Second");
setTimeout(function () {
console.log("Third");
}, 3000);
}, 4000);
}, 1000);
Promise 将嵌套格式的代码变成了顺序格式的代码
new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("First");
resolve();
}, 1000);
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("Second");
resolve();
}, 4000);
});
}).then(function () {
setTimeout(function () {
console.log("Third");
}, 3000);
});
当 Promise 被构造时,起始函数会被异步执行:
new Promise(function (resolve, reject) {
console.log("Run");
});
resolve 和 reject 都是函数,其中调用 resolve 代表一切正常,reject 是出现异常时所调用的:
//resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
//resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。
new Promise(function (resolve, reject) {
var a = 0;
var b = 1;
if (b == 0) reject("Divide zero");
else resolve(a / b);
}).then(function (value) {
console.log("a / b = " + value);
}).catch(function (err) {
console.log(err);
}).finally(function () {
console.log("End");
});
then() catch() finally()
//.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,
// .catch() 则是设定 Promise 的异常处理序列,
// .finally() 是在 Promise 执行的最后一定会执行的序列。
// .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:
new Promise(function (resolve, reject) {
console.log(1111);
resolve(2222);
}).then(function (value) {
console.log(value);
return 3333;
}).then(function (value) {
console.log(value);
throw "An error";
}).catch(function (err) {
console.log(err);
});
18 Promise 函数 异步函数(async function)是 ECMAScript 2017 (ECMA-262) 标准的规范,几乎被所有浏览器所支持,除了 Internet Explorer。
function print(delay, message) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(message);
resolve();
}, delay);
});
}
print(1000, "First").then(function () {
return print(4000, "Second");
}).then(function () {
print(3000, "Third");
});
//这岂不是将异步操作变得像同步操作一样容易了吗!
异步函数 async function 中可以使用 await 指令,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。
//异步函数实际上原理与 Promise 原生 API 的机制是一模一样的,只不过更便于程序员阅读。
//处理异常的机制将用 try-catch 块实现:
async function asyncFunc() {
await print(1000, "First");
await print(4000, "Second");
await print(3000, "Third");
}
asyncFunc();
async function asyncFunc1() {
try {
await new Promise(function (resolve, reject) {
console.log('asyncFunc1')
throw "Some error"; // 或者 reject("Some error")
});
} catch (err) {
console.log(err);
// 会输出 Some error
}
}
asyncFunc1();
//如果 Promise 有一个正常的返回值,await 语句也会返回它:
async function asyncFunc2() {
let value = await new Promise(
function (resolve, reject) {
resolve("Return value");
}
);
console.log(value);
}
asyncFunc2();
19 typeof() JavaScript 数据类型 对象类型
/*
JavaScript 数据类型
在 JavaScript 中有 6 种不同的数据类型:
string
number
boolean
object
function
symbol
3 种对象类型:
Object
Date
Array
2 个不包含任何值的数据类型:
null
undefined
20 对象constructor 属性
//constructor 属性
"John".constructor // 返回函数 String() { [native code] }
(3.14).constructor // 返回函数 Number() { [native code] }
false.constructor // 返回函数 Boolean() { [native code] }
[1,2,3,4].constructor // 返回函数 Array() { [native code] }
var li={name:'John', age:34}
li.constructor // 返回函数 Object() { [native code] }
new Date().constructor // 返回函数 Date() { [native code] }
function f1(){return 0 }
f1.constructor // 返回函数 Function(){ [native code] }
21 声明提升
x = 5; // 变量 x 设置为 5
elem = document.getElementById("demo"); // 查找元素
elem.innerHTML = x; // 在元素中显示 x
var x; // 声明 x
初始化不会提升
var x = 5; // 初始化 x
console.log( x + " " + y) // 显示 x 和 y 5 undefined
var y = 7; // 初始化 y
22 this
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
//在对象方法中, this 指向调用它所在方法的对象。 this 表示 person 对象。
return this.firstName + " " + this.lastName;
}
};
person.fullName()
//单独使用 this,则它指向全局(Global)对象。 在浏览器中,window 就是该全局对象为 [object Window]:
var x = this;
//函数中使用 this(默认)
function myFunction() {
return this;
}
//事件中的 this 在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素:
<button onClick="this.style.display='none'">
点我后我就消失了
</button>
22 显式函数绑定 apply 和 call 就是函数对象的方法
// 在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。
//在下面实例中,当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法:
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"John",
lastName: "Doe",
}
person1.fullName.call(person2); // 返回 "John Doe"
let 和 const详解
// let 和 const。
// let 声明的变量只在 let 命令所在的代码块内有效。
// const 声明一个只读的常量,一旦声明,常量的值就不能改变。
// 在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量。
//全局变量
var carName = "Volvo";
// 这里可以使用 carName 变量
function myFunction() {
// 这里也可以使用 carName 变量
}
//局部变量
// 这里不能使用 carName 变量
function myFunction() {
var carName = "Volvo";
// 这里可以使用 carName 变量
}
// 这里不能使用 carName 变量
//块级作用域(Block Scope)
{
var x = 2;
}
// 这里可以使用 x 变量
{
let x = 2;
}
// 这里不能使用 x 变量
//重新定义变量 使用 var 关键字重新声明变量可能会带来问题。 在块中重新声明变量也会重新声明块外的变量:
var x = 10;
// 这里输出 x 为 10
{
var x = 2;
// 这里输出 x 为 2
}
// 这里输出 x 为 2
//因为它只在 let 命令所在的代码块 {} 内有效。
var x = 10;
// 这里输出 x 为 10
{
let x = 2;
// 这里输出 x 为 2
}
// 这里输出 x 为 10
var i = 5;
for (var i = 0; i < 10; i++) {
// 一些代码...
}
// 这里输出 i 为 10
let i = 5;
for (let i = 0; i < 10; i++) {
// 一些代码...
}
// 这里输出 i 为 5
//HTML 代码中使用全局变量
var carName = "Volvo";
// 可以使用 window.carName 访问变量
let carName = "Volvo";
// 不能使用 window.carName 访问变量
23 object类是所以javascript类的基类,提供了一种创建自定义对象的简单方式,不需要程序员再定义构造函数。
var i=new Number(10);
//给原型对象添加方法
Number.prototype.add=function(a){
return this+a
}
window.alert(i.add(10).add(30));
var b=90;
window.alert(b.add(40));
//给javascript中的Array对象扩展一个find(val)方法,当一个Array对象调用该方法的时候,如果我们能找到val则返回其下标,否则返回负-1。
var arr1=new Array(3);
arr1[0]="George"
arr1[1]="John"
arr1[2]="Thomas"
//遍历数组
for(var i=0;i<arr1.length;i++){
console.log(arr1[i]+" ");
}
//使用Array提供的方法。颠倒数据
arr1.reverse();
//遍历该数组
for(var i=0;i<arr1.length;i++){
console.log(arr1[i]+" ");
}
//给Array对象添加一个find(val)方法
Array.prototype.find=function(val){
for(var i=0;i<this.length;i++){
if(val==this[i]){
return i;
}
}
return -1;
}
console.log("John 下标="+arr1.find("John"));
//hasOwnProperty 指示对象自身属性中是否具有指定的属性
var o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop'); // 返回 true
o.hasOwnProperty('toString'); // 返回 false
o.hasOwnProperty('hasOwnProperty'); // 返回 false
//isPrototypeOf 方法允许你检查一个对象是否存在于另一个对象的原型链上。
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
//传入baz对象 检查是否有Baz.prototype 存在 就返回 true.
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
24 自执行匿名函数 自执行函数,即定义和调用合为一体。
我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在执行完后很快就会被释放,关键是这种机制不会污染全局对象。
(function() { /* code */ })();
解释:包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数。
作用:可以用它创建命名空间,只要把自己所有的代码都写在这个特殊的函数包装内,那么外部就不能访问,除非你允许(变量前加上window,这样该函数或变量就成为全局)。
各JavaScript库的代码也基本是这种组织形式。
// 下面2个括弧()都会立即执行
(function () {
//我是匿名方式1----推荐使用这个----这种经常用来构建沙箱模式
} ())
(function () {
//我是匿名方式2
})()
// 如果你不在意返回值,或者不怕难以阅读
// 你甚至可以在function前面加一元操作符号
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
25 模块,导入导出
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量。
导出export
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
//上面代码是profile.js文件,保存了用户信息,
//ES6将其视为一个模块,里面用export命令对外部输出了三个变量。
//除了这种普通变量,输出的变量还可以是一个函数。
//另外,export语句输出的接口,与其对应的值是动态绑定关系,
//即通过该接口,可以取到模块内部实时的值。
//最后,export/import命令不能在块级作用域内,可以在全局作用域任何位置。
导入import
import语句只能在声明了type="module"的script的标签中使用。
动态导入:import(),它不需要依赖type="module"的script标签。
按照一定的条件或者按需加载模块的时候,动态import()是非常有用的。
而静态的import是初始化加载的最优选择。
// main.js
import {firstName, lastName, year} from './profile.js';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
//上面代码的import命令,用于加载profile.js文件,并从中输入变量。
//import命令接受一对大括号,里面指定要从其他模块导入的变量名。
//大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
注意:import语句会执行所加载的模块
import './lodash.js';
//执行lodash模块,但是不输入任何值
整体导入:
import * as myModule from './my-module.js';//不用加大括号{}
//将my-module里面输出的变量/函数,
//输入到myModule这个对象中作为属性/方法。
//通过myModule.属性名/myModule.方法()来调用。
默认导出/导入默认值:
告别使用import命令的时候,用户需要知道所要加载的变量名或函数名的现状
默认导出
//先用export default语法默认导出
//既然是默认输出,那么一个模板只能使用一次
export default function foo() {
console.log('foo');
}
导入默认值
//导入默认值
import customName from './default.js';//不用加大括号{}
customName(); // 'foo'
customName 是调用者任意指定的