JavaScript学习(2)
ES6的类数组array-like对象
声明
- var 数组名称=[元素1,元素2,元素3...];
- var aList = new Array( 1,2,3 );
- var aList = [ ]
- 给数组添加元素的另一种方式:数组名[索引]=元素
特性
- 可以存储不同的数据类型的元素。
- 数组的长度可变。
- 数组的索引可以是数字,也可以是字符串。
- 可以多层嵌套
方法
Array.concat() #连接数组
Array.join() #将数组元素连接起来以构建一个字符串
Array.pop() #删除并返回数组的最后一个元素,对比delete
Array.push() #给数组添加元素,同[length]=obj
Array.reverse() #颠倒数组中元素的顺序
Array.shift() #将元素移出数组
Array.slice() #返回数组的一部分
Array.sort() #对数组元素进行排序
Array.splice() #插入、删除或替换数组的元素
Array.unshift() #在数组头部插入一个元
ES6中的逻辑判断语句
JavaScript 运算符
- 算数运算符: + - * % / ++ -
- 赋值运算符: = += -= *= /= %=
- 比较运算符: == === != !== > < >= <=
- 逻辑运算符: && || !
- 判断: fasle undefined null 0 NaN 空字符串
- 条件运算符: if...else (a === b)?x:y
循环语句
- break语句
- continue语句
- do...while语句: 一直重复,直到条件为假(false),至少执行一次
- while语句: 条件为真(true)就一直执行 可能一次不执行
- switch (val)
- for 语句
- for...in语句
- for ... of 语句
- 在可迭代对象上创建了一个循环
- 注意 for...in 和for ...of 的区别
- for...in循环读取键名,for...of循环读取键值
- 数组,set,map,对象,字符串
ES6中的函数与方法
声明
-
一般function:
name ([param[, param,[..., param]]]) -
匿名函数(立即执行):
(function(){}())这样写的好处是在内部定义的变量不会跟外部的变量有冲突,达到保护内部变量的作用
(function(name){
console.log(`Hi$(name)`);
})('riy')
运行(执行,调用)
- 立即执行函数表达式 IIFE (Immediately Invoked Function Expression)
- 赋给一个变量
var sayHi = function(name){
console.log(`Hi ${name}!`);
}
- 赋给对象属性
var obj= {}
obj.sayHi = function(name){
console.log(`Hi ${name}!`); //Hi Riy!
}
obj.sayHi('Riy')
// --------------------- //
obj.upperHi = function(){
return this.name.toUpperCase()
}
obj.name = 'Riy'
console.log(obj.upperHi()); //RIY
- 作为参数传递给另一个函数(高阶函数)
let arr = [1,2,3,4,5]
let newArr = arr.map(function(x){return x*2});
console.log(newArr); //[2,4,6,8,10]
let andArr = arr.reduce(function(x, y){return x*y})
console.log(andArr); //120
- 将函数作为返回值
function calcArea(w, h){
return w*h
}
function rectInfo(w, h){
console.log(`w=${w} h=${h}的面积为`);
return calcArea;
}
var w = 4;
var h = 5;
area = rectInfo(w,h)(w,h);
console.log(area); //20
函数的参数
- 形式参数
- 默认参数
function user(name, password='123456'){
if(password == '123456'){
return name+' OK'
}else{
return name+' error'
}
}
var res1 = user('riy')
console.log(res1); //riy OK
- 剩余(rest)参数
function sum(a, b){
console.log(arguments); //arguments是一个对应于传递给函数的参数的类数组对象。
return a+b
}
a = sum(4, 8)
console.log(a); //12
function newSum(...all){
console.log(all); //document.all实质就是文档中所有元素的集合。可以看做一个数组。
return all[0]+all[1]
}
b = newSum(4, 8)
console.log(b); //12
函数的属性和方法
- name
- length
- toString()
function sum(){};
var otherSum = sum;
otherSum(1,2,3,4)
console.log(otherSum.name); //sum
console.log(sum.length) //0
console.log(sum.toString()); //function sum()
ES6的变量解构赋值与作用域
解构赋值
作用域
-
全局变量:
在函数之外定义的变量,函数内部可以访问 -
局部变量:
在函数内部定义的变量,只能在函数内部访问,外部无法访问 -
全局作用域(Global Scope)
- 最外层函数和在最外层函数外面定义的变量拥有全局作用域
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
- 所有 window 对象的属性拥有全局作用域
- 局部作用域(Local Scope)-函数作用域
- 定义了一个函数的同时,就创建了一个函数作用域
- 内部定义的变量不能在函数外部访问
- 嵌套的作用域变量从当前作用域往上寻找声明,找不到则报错
- 函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域
- 全局和局部作用域的关系
- 在函数体内,局部变量的优先级高于同名的全局变量
- 定义在全局域中的函数可以访问所有定义在全局域中的变量
- 块级作用域
关于let:
- let声明的变量只在代码块有效
- let声明的变量不存在变量提升
- 不能重复声明
关于const:
- 创建块级作用域
- 新建一个同名变量,不能重复赋值,但可以在新的作用域使用
关于var:
- 函数内部var的变量提升,声明被提到函数最开头
- 可能导致结果出错,或者泄露变量
关于this关键字
- 直接被调用的函数,this为全局对象
- 被某个对象调用的函数,this为当前对象
关于闭包:
- 由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成 定义在一个函数内部的函数
- 闭包的用途:可以读取函数内部的变量(作用域链),让这些变量的值始终保持在内存中
- 注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。
ES6中的正则表达式
定义
- 直接量语法 /pattern/attributes
- 创建 RegExp 对象的语法: new RegExp(pattern, attributes);
- 参数 pattern 是一个字符串,指定了正则表达式的模式或其他正则表达式。
- 参数 attributes 是一个可选的字符串,包含属性 "g"、"i" 和 "m",分别用于指定全局匹配、区分大小写的匹配和多行匹配。ECMAScript 标准化之前,不支持 m 属性。如果 pattern 是正则表达 式,而不是字符串,则必须省略该参数
用途
- 验证表单:登录注册验证
- 字符串操作:过滤,查找
ES6中的prototype与class
1.传统的Javascript是动态语言,又可称之为Prototype-based Language,JavaScript继承方法是使用prototype,透过指定prototype属性,便可以指定要继承的目标。属性可以在运行时添加到或从对象中删除,引擎会为运行中的对象创建一个属性字典,新的属性都要透过字典查找属性在内存中的位置。
-
原型链的原理: [[Prototype]] 机制是一种存在于一个对象上的内部链接,它指向一个其他对象。
-
当一个属性/方法引用在一个对象上发生,而这样的属性/方法又不存在时,这个链接就会被使用。在这 种情况下,[[Prototype]] 链接告诉引擎去那个被链接的对象上寻找该属性/方法。接下来,如果那个对 象也不能满足查询,就沿着它的 [[Prototype]] 查询,如此继续。这种对象间的一系列链接构成了所谓 的“原形链”。
-
好比一栋楼,顶楼是最高的原型,每层楼的__proto__都指向上一楼,可以简称这就是继承。当你要查找 一个对象的属性attr时。先在第一楼找(obj.attr)。如果找不到,跑到二楼找(obj.proto.attr)。二楼 找不到,就跑到三楼找,(obj.proto.proto.attr)。直到找到顶楼为止。
- 可以想到,如果一个属性位于原型链的顶端,那么这个查找过程将会十分低效。所以如果重复查找原型 链顶端的属性,通过临时变量来缓存结果是个提高性能的不错的方法。
关于原型及原型链
- prototype 原型
- 我们创建的每个函数都有一个 prototype(原型)属性
- 使用原型的好处是可以让所有对象实例共享它所包含的属性和方法
- 换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型中
- 理解原型对象:
在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属 性包含一个指向 prototype 属性所在函数的指针 虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值 - 原型的动态性:
由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立 即从实例上反映出来,即使是先创建了实例后修改原型也照样如此 实例中的指针仅指向原型,而不指向构造函数
- proto
- 当调用构造函数创建一个新实例后,该实例的内部将包含一个指针 proto,指向构造函数的原型
- 简单来说,当我们访问一个对象的属性时,如果这个属性不存在,那么就会去 proto 里找,这个 proto 又会有自己的 proto,于是就这样一直找下去,直到找到为止
- 原型链
- JavaScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法
- 其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法
- 每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一
个指向原型对象的内部指针 - 假如我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针
- 假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条
- 这就是所谓原型链的基本概念
箭头函数
定义
- 箭头函数使用类似于=>这样的语法定义函数,
- 支持表达式模式和语句模式
数组的一些箭头函数
作用域
- 箭头函数:作用域最大特点在于和父作用域具有一样的this。绑定定义时所在的作用域
- 普通函数:this 既不指向函数自身也不指向函数的词法作用域,this 实际上是在函数被调用时发生 的绑定,它指向什么完全取决于函数在哪里被调用。
- 箭头函数根本没有自己的this,导致内部的this就是外层代码块的this
- setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式 5. setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。
- 箭头函数中,this的作用域在Timer内,由于闭包,保存了变量更新的值
- 普通函数的s2一直出于全局作用域,值没有被保存,每次值都为0
Ajax介绍
- AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
- AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
- AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
- AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
- AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
ES6的异步操作:认识promise和async
Promise
- 含义:
- Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和 更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise对象。
- 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步 操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
- 为异步编程提供了一种新的方式,Promise把未来将用到的值当做一等对象
- 给你一个诺言,要么成功(上天堂),要么失败(下地狱)
- 特点:
- 对象的状态不受外界影响。 Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。
- 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
- 只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
- 如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件 (Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
- 调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而 不应该直接写在resolve或reject的后面
- 作用:对延时和异步操作流程进行控制
关于async
- 定义
- Async函数声明async function foo() {}
- Async 函数表达式 const foo = async function () {};
- Async 定义对象的方法 let obj = { async foo()
- Async 箭头函数 const foo = async () => {};
2.返回promises
- 正常then,fulfilled
- 报错catch,rejected
- 使用await异步得到结果和错误
学习module体系
- 模块(module)体系,将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。
- ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变 量。
- ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
- 模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口 ,import命令用于输入其他模块提供的功能。
- 一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取 模块内部的某个变量,就必须使用export关键字输出该变量。