Javascript是 netscape(网景)公司提供了ECMA(欧洲计算机厂商联盟组织)
ECMAScript和 JavaScript的关系是,前者是后者的规格,后者是前者的一种实现
为什么有ES6的let
定义变量
因为ES5的时候我们使用var的时候会出现变量提升,所以出现了let,let没有变量提升
var 不是块级作用域; let是块级作用域
ES6声明变量的使用建议使用let声明变量
定义常量 const
//数据解构
let arr = [10,20,30];
let [a,b,c] = arr;
这样就可以获取到其中的元素
//对象解构
let obj = {
name:"tom",
age:23,
sex:"男"
};
let {name,age,sex} = obj;
这样就可以获取其中的元素
function fn() {
console.log("hello);
}
如果代码多并且无参时
const fn = () =>{
console.log("hello);
}
如果代码少
const fn = () =>console.log("hello);
ES5写法
function fn() {
return a+b;
}
console.log(fn(5,6));
ES6写法
const fn = (a,b) =>a+b;
console.log(fn(5,6));
普通函数中的this指的是全局的window对象
var num = 10;
function fn(){
}
fn()
这个找到的是obj
var obj = {
name: "tom",
say: function() {
console.log(this);//obj对象
}
};
obj.say();
箭头函数中的this指的是函数定义所在位置的上下文
var obj = {
name: "tom",
say: () => {
console.log(this);//window对象
}
};
obj.say();
这是自定义的参数,本身就有
function fn() {
var sum = 0;
// arguments是位数组,是函数中所有参数的形成的数组
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log(sum);
}
fn(10, 20); //30
fn(10, 20, 30); //60
剩余参数...args
const sun=(...args)=>{
let sum = 0;
args.foreach(item=>{
sum += item;
})
console.log(sum);
}
sum(10,20,30);
数组展开自动使用逗号做分隔符
使用扩展预算符连接数组
let arr1 = ["a", "b", "c"];
let arr2 = ["d", "e", "f"];
let arr3 = [...arr1, ...arr2]; //['a','b','c','d','e','f']
console.log(arr3);
需要了解的ES6
let arr = [
{
id: "1",
name: "tom"
},
{
id: "2",
name: "jim"
}
];
const obj = arr.find(item => item.id == 2);
console.log(obj);
这个案例是查询对象的id是2的,返回结果是满足条件的那个对象
let arr = [
{
id: "1",
name: "tom"
},
{
id: "2",
name: "jim"
}
];
const index = arr.findIndex(item => item.id == 3);
console.log(index);
let arr = [10, 20, 30];
const res = arr.includes(10);
console.log(res);
如果有就返回true,没有就返回false
类似数组,新的数据结构
let year = 2021;
let month = 11;
let day = 16;
let str = `今年是${year}年${month}月${day}号`; //今年是2021年11月16号
let str2 = `${year}
${month}`;
document.write(str2);
const fn = () => {
return "hello";
};
const str = `${fn()}`;
console.log(str);
startsWith是判断字符串以什么开头 endsWith是判断字符串以什么结束(判断的结果以布尔值来显示)
let str = "hello";
let res1 = str.startsWith("h");//这是以什么字母开头
let res2 = str.endsWith("o");//这是以什么字母结尾
console.log(res1, res2);
let str = "hello".repeat(2);
console.log(str);
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
});
}
执行的结果:
https://www.cnblogs.com/Trista-l/p/7380830.html 这是大佬理解的这个问题的原因
那这个问题让我理解就是:
那有的同学就要问了,怎么才能正确的执行我想的0-4呢,这就要说到这个立即执行函数
立即执行函数就是不能让javascript认为function是一个语句,要让他认为function是一个表达式
立即执行函数模式是一种语法,可以让你的函数在定义后立即被执行,比如:
(function () {
alert('watch out!');
}());
这种模式本质上就是函数表达式(命名的或者匿名的),在创建后立即执行;
立即执行函数(immediate function)术语不是在ECMAScript标准中定义的,但它很短有助于描述和讨论模式;
立即执行函数的写法有两种:
//立即执行函数的两种写法
//第一种:用括号把整个函数定义和调用包裹起来
(function(){
function body
}())
//第二种:用括号把函数定义包裹起来,后面再加括号
(function (){
function body
})()
立即执行函数其他作用
(function foo(){console.log("Hello World!")}())//用括号把整个表达式包起来,正常执行
(function foo(){console.log("Hello World!")})()//用括号把函数包起来,正常执行
!function foo(){console.log("Hello World!")}()//使用!,求反,这里只想通过语法检查。
+function foo(){console.log("Hello World!")}()//使用+,正常执行
-function foo(){console.log("Hello World!")}()//使用-,正常执行
~function foo(){console.log("Hello World!")}()//使用~,正常执行
void function foo(){console.log("Hello World!")}()//使用void,正常执行
new function foo(){console.log("Hello World!")}()//使用new,正常执行
不必为函数命名,避免了污染全局变量
立即执行函数内部形成了一个独立的作用域,可以封装一些外部无法读取的私有变量,这个作用域里面的变量,外面访问不到,这样就可以
避免变量污染
封装变量
闭包和私有数据
【一句话总结】立即执行函数会形成一个单独的作用域,我们可以封装一些临时变量或者局部变量,避免污染全局变量。
<script type="text/javascript">
for (var i = 0; i < 5; i++) {
(function(e){
setTimeout(function(){console.log(e);},0)
})(i)
}
</script>
输出的结果是:
这样就输出了从0-4的数子,是不就很nice呢
面向过程就是不太好用
类的使用:
js原生的table选项卡
面向对象的table选项卡
// 父类
class Father{
}
// 子类继承父类
class Son extends Father {
}
class Father {
constructor(name) {
this.name= name;
}
say() {
console.log('你的姓是' + this.name);
}
}
class Son extends Father{
// 这样子类就继承了父类的属性和方法
}
var obj= new Son('张');
obj.say(); //结果为 你的姓是张
//定义了父类
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
//子元素继承父类
class Son extends Father {
constructor(x, y) {
super(x, y); //使用super调用了父类中的构造函数
}
}
var son = new Son(10, 20);
son.sum(); //结果为30
// 父类有加法方法
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extends Father {
constructor(x, y) {
// 利用super 调用父类的构造函数 super 必须在子类this之前调用,放到this之后会报错
super(x, y);
this.x = x;
this.y = y;
}
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(5, 3);
son.subtract(); //2 调用子类自己的减法方法
son.sum();//8 调用了继承的父类的加法方法
}
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(5, 3);
son.subtract(); //2 调用子类自己的减法方法
son.sum();//8 调用了继承的父类的加法方法
#### (2)面向对象
1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
3. 如果子类想要继承父类的方法,同时在自己内部扩展自己的方法,利用super 调用父类的构造函数,super 必须在子类this之前调用
4. constructor中的this指向的是new出来的实例对象
5. 自定义的方法,一般也指向的new出来的实例对象
6. 绑定事件之后this指向的就是触发事件的事件源