《JavaScript 高级程序设计(第3版)》 源码分析

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已经变为10for(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 有三种方法

  1. typeof运算符
  2. instanceof运算符
  3. 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'===55) //false
1、对于string,number等基础类型,
  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值