一、声明
作用域分为全局作用域、函数作用域和块作用域 。
/* 全局作用域 */
var array = ['a', 'b', 'c'] //全局变量
/* 函数作用域 */
function foo () {
var string = 'string' //局部变量
/* 块作用域 */
if(string) {
console.log(`foo:${string}`) //foot:string
}
}
foo()
/* 函数外无法直接访问局部变量 */
console.log(`string:${string}`) //Uncaught ReferenceError: string is not defined
var、let 和 const 的主要区别有以下三点:
- var 声明的变量属于函数作用域,let 和 const 声明的变量属于块级作用域;
- var 存在变量提升现象,而 let 和 const 没有此类现象;
- var 变量可以重复声明,而在同一个块级作用域,let 变量不能重新声明,const 变量不能修改。
var
如果使用关键字 var 声明一个变量,那么这个变量就属于当前的函数作用域,如果声明是发生在任何函数外的顶层声明,那么这个变量就属于全局作用域。
var a = 1 //此处声明的变量a为全局变量
function test(){
var a = 2 //此处声明的变量a为函数foo的局部变量
console.log(a) //2
}
test()
console.log(a) //1
如果在声明变量时,省略 var 的话,该变量就会变成全局变量,如全局作用域中存在该变量,就会更新其值。
var a = 1 //此处声明的变量a为全局变量
function test(){
a = 2 //此处的变量a也是全局变量
console.log(a) //2
}
test();
console.log(a) //2
console.log(a) //undefined
var a = 1
var a
console.log(a) //undefined
a = 1
console.log(b) //假设b未声明过,Uncaught ReferenceError: b is not defined
let
let 声明的变量,具有如下几个特点:
- let 声明的变量具有块作用域的特征;
- 在同一个块级作用域,不能重复声明变量;
- let 声明的变量不存在变量提升。
let a = 1
console.log(a) //1
console.log(b) //Uncaught ReferenceError: b is not defined
let b = 2
function test(){
let a = 1
let a = 2 //Uncaught SyntaxError: Identifier 'a' has already been declared
}
以下是一个经典的关于 var 和 let 的一个例子:
for (var i = 1; i <= 5; i++) {
setTimeout(function(){
console.log(i)
}, 100)
};
//依次打印:6 6 6 6 6 (var)
for (let i = 1; i <= 5; i++) {
setTimeout(function(){
console.log(i)
}, 100)
};
//依次打印:1 2 3 4 5 (用let声明)
for (var i = 1; i <= 5; i++) {
function foo(j) {
setTimeout(function(){
console.log(j)
}, 100)
}
foo(i)
};
//依次打印:1 2 3 4 5(用一个闭包把i的作用域包起来)
const
const 声明方式,除了具有 let 的上述特点外,其还具备一个特点,即 const 定义的变量,一旦定义后,就不能修改,即 const 声明的为常量。
const a = 1
console.log(a) //1
a = 2
console.log(a) //Uncaught TypeError: Assignment to constant variable.
但并不是说 const 声明的变量其内部内容不可变 。
const obj = {a: 1, b: 2}
console.log(obj.a) //1
obj.a = 3
console.log(obj.a) //3
二、数据类型
Array类型
splice(索引, 删除个数, [newObject]),[newObject] 可选参数。
arr.splice(0, 1)
arr.splice(0, 1, 'a')
sort() 数组排序
var arr = ['a', 'd', 'c', 'b']
arr.sort()
indexOf(item) 索引,-1为不存在。
var object = arr.indexOf('1')
slice(索引, 取出个数)
var arr1 = arr.slice(0, 3);
concat(arr) 合并数组
var arr2 = arr.concat(arr1)
array 转 string,中间 ‘,’ 隔开,等同于 toString()。
let str = arr.join(',')
let str1 = arr.toString()
push(object, ..., object) 添加一个或多个对象
var arr = ['a']
arr.push('b')
arr.push('c', 'd')
从数组头添加对象
var arr = []
arr.unshift('a')
arr.unshift('b', 'c')
typeof arr1 === 'object',数组的 type 为 object。
var arr = arr1.concat(arr2) //生成新的内存
arr1.push.apply(arr1, arr2)
Array.prototype.push.apply(arr1, arr2) //合并到arr1中
String类型
数字/字符串相互转换。
var integer = parseInt('666') /* 转换函数 */
var integer1 = Number('888') /* 强制类型转换 */
var str = integer.toString() /* 转换函数 */
var str1 = String(integer1) /* 强制类型转换 */
replace("current", "new") 替换字符
str.replace("current", "new")
split(" ") 根据空格生成 array
str.split(" ")
substr(索引, 个数) 个数:可选参数,不填则表示索引处全取。
str.substr(0, 2)
toLowerCase() toUpperCase() 大小写
str.toLowerCase()
str.toUpperCase()
slice(start, end) 取出start~end的字符,end:可选参数。
str.slice(2, 5)
concat(str) 拼接字符串,等同于 ‘+’。
str.concat('a', 'b', 'c')
str += 'a' + 'b' + 'c'
indexOf('subStr') 索引,-1为不存在。
str.indexOf('abc')
Object类型
Object.assign(object1, object2) 合并对象(object2合并到object1)
键值对第一层为深拷贝,第二层和以上为浅拷贝。
Object.assign(object1, object2) //object1内存地址不变
var newObject = Object.assign({}, {key: 'value'}, {key2: 'value2'}) //生成新的对象
delete newObject.key //删除key-value
delete newObject['key2'] //删除key2-value2
var keys = Object.keys(object1) //获取object1的keys
var values = Object.values(object1) //获取object1的values
var keys2 = Object.getOwnPropertyNames(object2) //获取object2的keys
变量类型-typeof
console.log(typeof firstObject) //'undefined'
console.log(typeof(false)) //'boolean'
console.log(typeof 'helloworld') //'string'
console.log(typeof 27) //'number'
console.log(typeof NaN) //'number'
console.log(typeof null) //'object'
var str = new String()
console.log(typeof(str)) //'object'
var fn = function(){}
console.log(typeof(fn)) //'function'
console.log(typeof(class c{})) //'function'
变量为空判断
/* 等同于 if(variable) console.log('variable为空') */
if (variable === null || variable === undefined || variable === '' || variable === 0) {
console.log('variable为空')
}
/* 等同于 variable === undefined */
typeof (variable) === 'undefined'
var str = ''
str.length === 0
var arr = []
arr.length === 0
var data = {}
var keys = Object.keys(data)
keys.lenght === 0
JSON转换
var myJson = JSON.stringify(object) //object转jsonString
var object = JSON.parse(myJson) //jsonString转object
/* 两方法一起用可以实现深拷贝 */
Date类型
new Date('2019/04/23').getTime() => Date.parse('2019/04/23')
Date.now() => new Date().getTime() 时间戳
/* dateString 转 时间戳 通用格式'xxxx/xx/xx xx:xx:xx' */
var dateStr = '2019-05-19'
dateStr = dateStr.replace(/-/g, '/')
var date = new Date(dateStr)
let time = date.getTime()
/* 时间戳 转 dateString 'xxxx-xx-xx xx:xx:xx' */
function formatDate(date) {
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
}
var date = new Date(1230999938);
var dateString = formatDate(date);
三、定时器
setTimeout
var timeout = setTimeout(() => {
//延时调用
}, 1000);
//取消延时器
clearTimeout(timeout);
setInterval
var interval = setInterval(() => {
//循环调用
}, 1000);
//取消定时器
clearInterval(interval);
四、Dom方法
document.documentElement.scrollTop = 270 //跳至到270的位置
document.getElementById('el').scrollIntoView() //跳至指定元素位置
var element = document.getElementById('el')
element.style.color = '#50d6c2' //元素属性赋值
属性初始化
/* response没有声明,报undefined */
this.response.error = (err) => {}
/* 修正后的代码示例 */
this.response = {}
this.response.error = (err) => {}
五、函数、闭包
var infoFunc = deviceInfo => { } /*类似 function(deviceInfo) { } */
var func = () => { } /*类似 function() { } */
var verfunc = (verA, verB) => { } /*类似 function(verA, verB) { } */
let _this = this /* 多层嵌套可以引用'_this',单个闭包'=>{}'直接用'this'就行 */
/* 用法跟ios的block相似,可作为传参并接受回调,也可以只作为一个闭包(方法),实现方法的调用 */
六、HTTP-AXIOS
axios 是通过 promise 实现对 ajax 技术的一种封装。
/* axios的两种调用方式 */
axios({
method: 'post',
url: '/user/login',
data: { username: '123456', password: 'ABC23456' }
}).then(function (res) {
console.log(res);
}).catch(function (err) {
console.log(err);
});
axios.get('user/userinfo').then(res => {
console.log(res);
}).catch(err => {
console.log(err);
});
七、公共库的引用
/* stream.js */
var Stream = {
gateWayAjax: function(options) {
console.log('gateWayAjax')
}
}
export default Stream
/* util.js */
export let compareVersion = (verA, verB)=> { }
/*等同 export function compareVersion(verA, verB) { }*/
export const debug = true
/* vue引用 */
import UtilStream from 'Utils/stream' // UtilStream == export default Stream
improt { debug, compareVersion } from 'Utils/util' // const命名必须一致
export defealt {
created() {
UtilStream.gateWayAjax({ })
compareVersion(appVersion, '2.0.2')
console.log('It is debug:' + debug)
}
}
/* Api.js */
var Api = {
interface: {
$reqData: this.$reqData
}
$reqData() {
Axios.post()
}
}
export const api = Object.assign(Api.interface)
/* Sql.js sql与api结构相似{key:value} */
$queryData() {
console.log('queryData')
}
$insertData() {
console.log('insertData')
}
export const sql = { $queryData, $insertData }
/* vue引用 */
import { api } from 'utils/Api'
import { sql } from 'utils/Sql'
export default {
methods: {
...api,
...sql,
reqData() {
this.$reqData()
/* methods引入...api后,可以直接this.调用api中的方法 */
},
queryData() {
this.$insertData()
this.$queryData()
/* methods引入...sql后,可以直接this.调用sql中的方法 */
}
}
}
八、构造函数/原型对象
在 JavaScript 中,用 new
关键字来调用的函数,称为构造函数。
function construct() {
var data = {}
function method(params) {
// do something
}
}
var constructObj = new construct()
用 prototype 可以实现构造函数的扩展和继承
/* 通过prototype实现扩展 */
function Construct() {
var data = {}
function method(params) {
// do something
}
}
// 方法扩展
Construct.prototye.setvalue = (value) => {
// do something
}
var constructObj = new Construct()
constructObj.setValue('赋值')
/* 通过prototype实现继承 */
function Construct() {
var data = {}
function method(params) {
// do something
}
}
function SuperClass() {
var params = {}
function setValue(value) {
// do something
}
}
// 继承
Construct.prototye = new SuperClass()
var constructObj = new Construct()
constructObj.method('参数')
constructObj.setValue('赋值')
构造函数和原型对象的关关联如下图:
- 实例的 constructor 指向构造函数;
- 函数对象才有 prototype 属性;
- 原型对象是构造函数的一个实例。
九、线程
JavaScript引擎
JavaScript 引擎是基于事件驱动单线程执行的,JavaScript 引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个 JavaScript 线程在运行 JavaScript 程序。
GUI渲染线程
GUI 渲染线程负责渲染浏览器界面,当界面需要重绘或由于某种操作引发回流时,该线程就会执行,但需要注意,GUI 渲染线程与 JavaScript 引擎是互斥的,当 JavaScript 引擎执行时 GUI 线程会被挂起,GUI 更新会被保存在一个队列中等到 JavaScript 引擎空闲时立即被执行。
事件触发线程
当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待 JavaScript引擎的处理;这些事件可来自JavaScript引擎当前执行的代码块,如 setTimeout,也可来自浏览器内核的其他线层,如鼠标点击、Ajax异步请求等,但由于 JavaScript 的单线程关系,所有这些事件都得排队等待 JavaScript 引擎处理。
同步/异步
JavaScript 是单线程执行机制,但也可以实现同异步操作,同步任务直接在当前线程执行,异步任务则先进入任务队列,当事件触发线程检测到 JavaScript 引擎空闲时,会读取任务队列,并执行对应的任务(当线程中没有执行任何同步代码的情况下才会执行异步代码)。
十、异步回调
Promise
Promise 简单来说就是一个容器,从它可以获取异步操作的消息。
/* 正常执行后的回调 */
let p = new Promise((resolve, reject) => {
resolve('resolve')
});
p.then(result => {
console.log(result);
});
Promise 同时执行 resolve() 和 reject() 时,只能触发其中一个监听,也就是最终只会回调 ‘正常状态’ 或者 ‘异常状态’
/* 正常及异常的监听回调实现 */
let p = new Promise((resolve,reject) => {
let result = (response.ret === 0)
if(result) {
resolve(response)
} else {
reject('error')
}
/* reject调用无效
* resolve(response)
* reject('error')
*/
});
/* 两种书写方式 */
p.then(res => {
console.log('response',res)
}, err => {
console.log('error',err)
})
p.then(res => {
console.log('response',res)
}).catch(err => {
console.log('error',err)
})
async/await
async 用于申明一个 function 是异步的,而 await 可以认为是 async wait 的简写,等待一个异步方法执行完成。
async function asyncMethod() {
return HTTPReq()
}
/* async函数返回的是Promise对象 */
let p = asyncMethod()
p.then(res => { })
使用await必须在该函数中添加 async 声明,async await 把异步转成同步,直接返回结果。
/* 直接返回结果 */
async function asyncMethod() {
let response = await HTTPReq()
return response
}
asyncMethod().then(res => {
this.console.log(res)
})