JavaScript简介
JavaScript一种动态类型、弱类型、基于原型的客户端脚本语言,用来给HTML网页增加动态功能。
JavaScript由三部分组成:
ECMAScript(核心)+DOM(文档对象模型)+BOM(浏览器对象模型)
ECMAScript作为核心,规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象
DOM把整个页面映射为一个多层节点结果,开发人员可借助DOM提供的API,轻松地删除、添加、替换或修改任何节点。
BOM支持可以访问和操作浏览器窗口的浏览器对象模型,开发人员可以控制浏览器显示的页面以外的部分
一、声明变量
es6声明变量:
let x=1;//声明一个变量
const y=2;//声明一个只读常量,声明时必须赋值,之后值不可修改
es5声明变量:
var z=3;//声明一个变量
区别:
let不存在变量提升,而var存在
ps:变量提升:先解析代码,获取所有声明的变量,然后代码自上而下依次运行将变量提升到自身所在作用域的头部,这将导致脚本还未执行,而变量却存在,只不过变量的值为undefined。
var num=2;
function fun() {
console.log(num);//undefined
if(false){
var num=3;
console.log(num);//代码不执行
}
}
从上面代码可以看出,即使if语句不执行,但是num却依然声明了。
ES5只有全局作用域和函数作用域,没有块集作用域。而let则实际上为JavaScript新增了块级作用域。
用它所声明的变量,只在let命令所在的代码块内有效。
场景一:
let name = 'zach'
while (true) {
let name = 'obama'
console.log(name) //obama
break
}
console.log(name) //zach
var name = 'zach'
while (true) {
var name = 'obama'
console.log(name) //obama
break
}
console.log(name) //obama
场景二:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
上面代码中,变量i是var声明的,在全局范围内都有效。所以每一次循环,新的i值都会覆盖旧值,导致最后输出的是最后一轮的i的值。
而使用let则不会出现这个问题。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
场景三:
var clickBoxs = document.querySelectorAll('.clickBox')
for (var i = 0; i < clickBoxs.length; i++){
clickBoxs[i].onclick = function(){
console.log(i)
}
}//i为全局变量,每次点击输出最后一次的i值
运用闭包解决:
function iteratorFactory(i){
return function(){
console.log(i)
}
}
var clickBoxs = document.querySelectorAll('.clickBox');
for (var i = 0; i < clickBoxs.length; i++){
clickBoxs[i].onclick = iteratorFactory(i)
}
二、作用域
作用域:ps:变量能够起作用的范围
在es5中只有全局作用域和函数作用域,而es6中新增了一个块级作用域
var arr="love";//全局作用域下的全局变量
function foo() {
var arr="you";//函数作用域下的局部变量
}
foo();
块级作用域用 { } 包含
{
let num=.....;//块级作用域写法
........
}
*.在某个作用域中用let声明局部变量时,该作用域会形成封闭作用域,即在变量声明之前,该变量不可使用,并且不允许在相同的作用域下重复声明同一个变量.
var tmp="234";
{
tmp=345;//报错
let tmp="567";//在声明变量之前不可使用,区域已封闭
}
let garde=88;
let grade=79;//报错
let num=110;
{
let num=99;
console.log(num);//99
}
console.log(num);//110
从上面的代码可以看出用let声明的变量绑定了自己所在的作用域,互不影响.
三、箭头函数
箭头函数解决的问题
简化了写法。箭头函数适用于函数体只有一行的情况;当有多行时,可用普通函数增加可读性。 少打代码,结构清晰
明确了this。传统JS的this是在运行的时候确定的,而不是在定义的时候确定的;而箭头函数的this是在定义时就确定的,不能被改变,也不能被call,apply,bind这些方法修改。明确运行时候this指向谁,不用运行时判断this指向。
注:箭头函数没有自己的this,他的this就是外层的this,指向上一个不是箭头函数的函数的this。因为js的机制,所以指向的是一个非箭头函数的函数的作用域。
箭头函数与普通函数的区别
普通function的声明在变量提升中是最高的,箭头函数没有函数提升
箭头函数没有this,函数体内部的this对象就是定义的时候所在的对象而不是使用时所在的对象
箭头函数没有arguments对象,该对象在函数体内不存在,如果要用,可以使用rest参数
箭头函数不能作为构造函数,不能被new,没有property
call和apply方法只有参数,没有作用域
不可以使用yield命令,因此箭头函数不能做Generator函数
四、类继承
ES5通过原型链实现继承:
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
ES6引入了Class(类)这个概念,更像面向对象编程的语法。
class Animal {
constructor(){
this.type = 'animal'
}
says(say){
console.log(this.type + ' says ' + say)
}
}
let animal = new Animal()
animal.says('hello') //animal says hello
class Cat extends Animal {
constructor(){
super()
this.type = 'cat'
}
}
let cat = new Cat()
cat.says('hello') //cat says hello
上面代码首先用class定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。简单地说,constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实力对象可以共享的。
super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
五、设置默认函数参数
ES6中可以设置默认函数参数,如function A(x,y=9){};
六、promise
promise产生背景:解决回调地狱问题,处理异步请求
promise用法:链式调用,成功和失败的回调,三个状态,pending状态改变时触发。状态一旦改变就不会再变。
七、字符串模板 Template strings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
八、Iterators(迭代器)+ for…of
迭代器有个next方法,调用会返回:
(1).返回迭代对象的一个元素:{ done: false, value: elem }
(2).如果已到迭代对象的末端:{ done: true, value: retVal }
for (var n of ['a','b','c']) {
console.log(n);
}