JavaScript 语言的每一个*值*,都属于某一种数据类型
js是单线程语言,不能同时干两件事
单线程是为了避免dom渲染的冲突,同一时间只能做一件事,通过事件轮循(event-loop)实现,会将进程分为同步进程和异步进程两个队列,同步执行完毕,在执行异步队列
同步、异步的理解 是否阻塞程序的执行,如果是就是同步,否则就是异步
典型的 alert() 就是同步执行,如果用户不点击确定按钮 就会一直等待
异步有:ajax请求、定时器、图片加载、点击事件
promise
Promise对象是一个构造函数,用来生成Promise实例。它有三个状态,进行中,已成功,已失败,最大的缺点一创建无法取消,接受两个回调函数
Promise构造函数接受一个函数作为参数,该函数的两个参数分别为resolve和reject,它们是两个函数
Promise.prototype.then()接受两个回调函数,Promise.prototype.catch()用来捕获异常
const promise = new Promise(function(resolve, reject) {
//some code ...
if(/* 异步操作成功 */) {
resolve(value);
}else {
reject(error);
}
});
promise.then(function(value) {
//状态为resolved时调用
}, function(error) {
//状态为rejected时调用
});
统一捕获异常、多个接口请求支持链式执行「promise.all所有的请求都完成再往下执行,参数是一个装有一个或多个promise对象的数组。、promise.race只要有一个完成就往下执行」
指定执行循序,通过.then;第一个执行完return 第二个promise对象
function loadImg(src) {
var promise = new Promise(function (resolve, reject) {
var img = document.createElement('img')
img.onload = function () {
resolve(img)
}
img.onerror = function () {
reject('图片加载失败')
}
img.src = src
})
return promise
}
var src1 = 'https://www.imooc.com/static/img/index/logo_new.png'
var result1 = loadImg(src1)
var src2 = 'https://img1.mukewang.com/545862fe00017c2602200220-100-100.jpg'
var result2 = loadImg(src2)
result1.then(function (img1) {
console.log('第一个图片加载完成', img1.width)
return result2 // 重要!!!
}).then(function (img2) {
console.log('第二个图片加载完成', img2.width)
}).catch(function (ex) {
console.log(ex)
})
async、await
现原理就是将Generator函数,ES6提供的一种异步编程解决方案,sync函数就是将Generator函数的星号(*)替换成async,将yield替换成await,然后内置了一个功能类似run的执行器。
是一个同步的写法,使用的时候注意 async加在函数的前面、await后面是一个promise的实例
一个函数如果加上 async ,那么该函数就会返回一个 Promise
async function test() {
return "1";
}
console.log(test()); // -> Promise {<resolved>: "1"}
可以把 async 看成将函数返回值使用 Promise.resolve() 包裹了下。
await 只能在 async 函数中使用
function sleep() {
return new Promise(resolve => {
setTimeout(() => {
console.log('finish')
resolve("sleep");
}, 2000);
});
}
async function test() {
let value = await sleep();
console.log("object");
}
test()
上面代码会先打印 finish 然后再打印 object 。因为 await 会等待 sleep 函数 resolve ,所以即使后面是同步代码,也不会先去执行同步代码再来执行异步代码。
为什么结果为13524?,由于单线程的机制,执行到setTimeout会被暂存起来不会立即执行
console.log(1)
setTimeout(function(){
console.log(2)
},0)
console.log(3)
setTimeout(function(){
console.log(4)
},1000)
console.log(5)
关于var、let、const
let和const是var的改良版,能用const就不用let, 能用let就不用var。
用var在函数内部声明,这个变量就属于当前的函数作用域,如果不用var关键字则声明的是一个全局变量。
var a = 1; //此处声明的变量a为全局变量
function foo(){
a = 2;//此处的变量a也是全局变量
console.log(a);//2
}
foo();
console.log(a);//2
let 和 const 声明的变量不存在变量提升。var 声明的变量存在提升
var a = 0;
console.log(window.a) // 0
let b = 1;
console.log(window.b) // undefined
let和const声明的变量时块级作用域,避免了无意中全局变量污染,更加的灵活安全。另一个好处就是在循环语句中,let关键字为每次循环绑定单独绑定一个变量。
for(var i = 0; i<10; i++){
console.log(i)
}
alert(i) 此时i已经变为10了
for(let i = 0; i<10; i++){
console.log(i)
}
alert(i) 此时i会输出0-9
let和const不可以重复定义变量,let和const定义的变量不属于不再是全局变量window的属性或方法
let声明的是变量,const声明的是常量,只读,修改值会报错,const保存的是内存地址,可以给对象或数组添加属性或元素,但是不能重新复写
const a = 1;
console.log(a);//1
a = 2;
console.log(a);//Uncaught TypeError: Assignment to constant variable.
const obj={
}
obj.a=1//正常
obj={
}//错误
const arr=[]
arr.push(0)//可以
arr=[2]//重新赋值报错
一、数据类型
初始化未经声明的变量,总是会创建一个全局变量。
数据类型分为:基本数据类型(undefined、null、string、number、boolean),引用数据类型(object、array、函数)基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象
undefined:表示“未定义”或不存在,null:表示空值,即此处的值为空
其中 JS 的数字类型是浮点类型的,没有整型。并且浮点类型基于 IEEE 754标准实现,在使用中会遇到某些 Bug。NaN 也属于 number 类型,并且 NaN 不等于自身。
对象(Object)是引用类型,在使用过程中会遇到浅拷贝和深拷贝的问题。
关于赋值
基本数据类型赋值 互不影响 而引用类型赋值后指向的是同一个引用地址 所以修改一个其他的都会变
js内置函数
object、array、bloolean、function、string、number
关于 NAN 即非数值,不是(not)一个(a)数字(number)。
NAN与任何值都不相等,包括它自己,进行关系比较结果都是false
alert(isNAN(NAN)) //是否 不是一个数字 true
alert(isNAN(10)) // false
alert(isNAN('ni')) // true
alert(isNAN(true)) // false 因为true 可以被转换为1
1.undefined 声明变量没有定义
2. null 空对象指针
3. bloolean
4. number 数值转换 Number()函数在转换字符串时比较复杂而且不够合理,推荐使用,parseInt()parseFloat()
5. string 字符串类型 toString() 有个缺点 对null 和 undefined 不起作用
6. string() 方法更全面
7. Boolean() 检测数据类型是否返回true、false ,对于0, '', null, undefined, NaN都返回false 注意其他默认类型值返回true
parseInt()、parseFloat()
parseInt方法用于将字符串转为整数。
如果字符串头部有空格,空格会被自动去除。
parseInt(' 81') // 81
如果parseInt的参数不是字符串,则会先转为字符串再转换。
parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1
字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15
如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。
如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN。
parseInt('abc') // NaN
parseInt('.3') // NaN
parseInt('') // NaN
parseInt('+') // NaN
parseInt('+1') // 1
parseFloat([]) // NaN
parseFloat('FF2') // NaN
parseFloat('') // NaN
parseFloat('123.45#') // 123.45
Number('123.45#') // NaN
string 字符串
由于 HTML 语言的属性值使用双引号,所以很多项目约定 JavaScript 语言的字符串只使用单引号
一、布尔,数字,字符串
截取给定位置的那个字符 charAt 只接受一个参数
var str = 'nihao';
alert(str.charAt(1)) //i
字符串的拼接 concat 或者 + 加号操作符
var str = 'nihao';
var newstr = str.concat('world', '!');
alert(newstr) // nihao world !
字符串的截取 slice()、substr()、substring()。接收两个参数,并且第二个参数都是可选参数
str.substring 遇到负数不计算,交换下标位置
substring()从提取的字符indexStart可达但不包括 indexEnd
如果indexStart 等于indexEnd,substring()返回一个空字符串。
如果indexEnd省略,则将substring()字符提取到字符串的末尾。
如果任一参数小于0或是NaN,它被视为为0。
如果任何一个参数都大于stringName.length,则被视为是stringName.length。
如果indexStart大于indexEnd,那么效果substring()就好像这两个论点被交换了一样; 例如,str.substring(1, 0) == str.substring(0, 1)
str.substr <不推荐使用,即将废弃>
substr()会从start获取长度为length字符(如果截取到字符串的末尾,则会停止截取)。
如果start是正的并且大于或等于字符串的长度,则substr()返回一个空字符串。
若start为负数,则将该值加上字符串长度后再进行计算(如果加上字符串的长度后还是负数,则从0开始截取)。
如果length为0或为负数,substr()返回一个空字符串。如果length省略,则将substr()字符提取到字符串的末尾。
str.slice 遇到负数会计算
若beginIndex为负数,则将该值加上字符串长度后再进行计算(如果加上字符串的长度后还是负数,则从0开始截取)。
如果beginIndex大于或等于字符串的长度,则slice()返回一个空字符串。
如果endIndex省略,则将slice()字符提取到字符串的末尾。如果为负,它被视为strLength + endIndex其中strLength是字符串的长度。
如何确定一个值到底是什么类型
JavaScript 有三种方法
- typeof运算符
- instanceof运算符
- Object.prototype.toString方法
Typeof
typeof 对于基本类型,除了 null 都可以显示正确的类型
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof b // b 没有声明,但是还会显示 undefined
function f() {
} typeof f // "function"
typeof 对于对象,除了函数都会显示 object
typeof [] // 'object'
typeof {
} // 'object'
typeof console.log // 'function'
对于 null 来说,虽然它是基本类型,但是会显示 object
typeof null // 'object'
null的类型是object,这是由于历史原因造成的。1995年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑null,只把它当作object的一种特殊值。后来null独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null返回object就没法改变了。
转换数字的时候会莫名其妙的变为NAN
如果第一个字符不是数字或者负号使用parseInt就会返回NAN
console.log(Number("")); //0
console.log(parseInt(""))//NAN
字符串的查找 indexOf match
var str = 'lele nihao,zheli shi di yi jia zhu';
var arr = [];
var op = str.indexOf('e');
while(op>-1){
arr.push(op);
op = str.indexOf('e', op+1);
}
//进入循环后每次给indexOf传递上一次的位置加1
alert(arr)
trim() 会创建一个字符串的副本,删除前置及后置的所有空格
match()方法只接受一个参数
var text = 'bat cat';
var parrent = /.at/gi;
var new = text.match(parrent)
统计一个字符串出现最多的字母 「考察数组去重、数据整合」
var data = "aaaaacccccssdsddddddddda";
var length = data.length;
var datas = [];
var num = [];
for (var i = 0; i < length; i++) {
if (datas.indexOf(data[i]) < 0) {
datas[i] = data[i];
num[data[i]] = 1;
}
else {
num[data[i]]++;
}
}
console.log(datas); //["a", empty × 4, "c", empty × 4, "s", empty, "d"]
console.log(num); //[a: 6, c: 5, s: 3, d: 10] 到这一步就已经统计出来了
var max = num[datas[0]]; //6
var datamax = datas[0]; //a
//下面的方法是为了取值
for (var i = 1; i < datas.length; i++) {
if (max < num[datas[i]]) {
console.log(num[datas[i]])
max = num[datas[i]];
datamax = datas[i];
}
}
console.log("出现最多的字母:" + datamax + " 出现次数:" + max);
字符串的替换 replace()
var text = 'bat cat';
var result = text.replace(/at/gi, 'oo')
字符串转数组的方法 split()
var text = 'arr,op,kj,hg,';
var result = text.split(',')
接受第二个参数,固定数组的length
二、URL编码方法
encodeURL() 是对整个URL进行编码,
encodeURLComponent()对附加在现有URL后面的使用
Math对象获取数组最大值最小值
三、 Math 对象
获取数组中最大值和最小值 避免过多的使用循环和在if语句中确定数值。
var val = [1,2,3,4,5,6,7,8,9];
var max = Math.max.apply(Math, val);
这个技巧的关键,把MAth作为apply的第一个参数,从而正确的设置了this、
Math.ceil() 向上取整 Math.floor() 向下取整 Math.round() 四舍五入取整
random()方法
值 = Math.floor ( Math.round() * 可能值的总数 + 第一个可能的值 )
var color = ['red', 'blue', 'green', 'yellow'];
function randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
}
var str = randomNum(0, color.length-1)
console.log(color[str])
运算
1、求模(取余数)
var result = 26 % 5
2、由于运算是从左往右的打印message第一个加法操作将一个字符串和一个数值拼接,
结果是一个字符串,这是加法运算的特殊之处。
var num1 = 5;
var num2 = 10;
var message = "this is a number = "+ num1 +num2;
var message2 = "this is a number = "+ (num1 +num2);
console.log(message) //this is a number = 510
console.log(message2) this is a number = 15
3、减法运算,来说就没那么特殊。
console.log('8'-1)
4、关于==、!=,这两个操作符。
console.log('55'==55); //true
console.log('55'===