Yapei Li

专注于前端领域

0%

变量提升(预解析):

当前作用域 中 js代码自上而下执行之前,浏览器首先会把带 ‘var’或者 ‘function’ 关键字的进行提前的‘声明或定义’

声明(declare):var num;在当前作用域声明

定义(defined):num=12;给声明的变量附一个值

页面加载时只把全局作用域中的变量提升,不管私有作用域里的变量,当函数执行时才把函数内的私有作用域下的变量提升

带var关键字的只是提前声明一下 并没有赋值;

带function关键字的在变量提升阶段把声明和定义都完成了

js代码执行时遇到创建函数的代码直接跳过(不在声明也不进行赋值操作)因为变量提升时 声明和定义都做过了

阅读全文 »

全局作用域:window global

变量和常量能存任何数据类型

js的数据类型

基础数据类型(值类型)

  • number
  • string
  • boolean
  • null
  • undefined

引用数据类型

对象

  • {} 普通对象(json)
  • [] 数组
  • /^$/ 正则
  • Math 对象数据类型

函数

  • function 普通函数

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var a=10;
var b=a;
b=14;
console.log(a) => 10

//改变了同一空间地址内的键值
var c={name:'haha'}
var d=c;
d.name='quququ';
console.log(c) => {name: "quququ"}

//从新定义了地址 不改变原有空间
var m={name:'aaa'}
var n=m;
n={name:'bbb'}
console.log(m.name) => aaa

操作规律

值类型(基本数据类型):

var a=12;

  • 1)首先在当前作用域中声明一个变量a,没有赋值是 undefined
  • 2)在当前作用域开辟一个位置存储12
  • 3)让声明的变量和存储的12进行关联

直接按值操作:把原有的值复制一份,放在新的空间位置上,和原来的值没有关系。 变量间相互不影响

一个变量只能存一个值

对象数据类型:(按内存空间操作)

  • 1、先创建一个变量(声明一个函数名和声明一个变量一样 ,如果两个变量名重复 是会冲突的);
  • 2、浏览器为其开辟一个新的内存空间,为了方便别的地方找到这个空间 会给空间分配一个16进制的地址 (16进制:0-9 a-f)
  • 3、按照一定顺序,把对象中的键值对存到内存空间
  • 4、把开辟内存的地址赋值给变量(或者其他的东西比如事件),以后变量就可以通过地址找到内存空间然后进行操作

操作的是空间的引用地址:把原来空间地址赋值给新变量,但是空间没有被克隆,还是一个空间,这样就会出现多个变量关联的是相同的空间相互之间就会存在影响

阅读全文 »

DOM树(dom tree):DOM结构

当浏览器加载HTML页面时,首先就是DOM结构计算,计算出来的DOM结构就是DOM树(把页面中的HTML标签像树状结构一样,分析出之间的层级关系)

DOM树描述了标签和标签之间的关系(节点间的关系)

我们只要知道任何一个标签,都可以依据DOM中提供的属性和方法,获取到页面中任意一个标签或者节点

Alt text

阅读全文 »

Math称为数学函数,但是它属于对象类型

typeof Math =》 ‘object’

之所以叫做数学函数,因为Math这个对象中提供了很多操作数字的方法

Math中提供的常用方法Math.XXX(n)

abs: 取绝对值,

ceil/floor: 向上/向下取整

1
2
3
4
5
Math.ceil(10.01)  =>11
Math.ceil(-10.01) =>-10

Math.floor(10.99) =>10
Math.floor(-10.99) =>-11

round: 四舍五入(正数.5向上,负数.5向下)

sqrt: 开平方

pow: 取幂 (n的m次方)

1
Math.pow(2,10)  =>1024

max/min: 取最大值、取最小值

1
2
Math.max(1,2,3,4)   //4
Math.min(1,2,3,4) //1

PI:获取圆周率

random:获取0-1之间的随机小数

Math.round(Math.random()*(m-n)+n):获取n->m之间的随机正整数

阅读全文 »

字符串是基本数据类型的,字符串的每一次操作都是直接的对值进行操作,不像数组是基于空间地址来操作的,所以不存在原有字符串是否改变的问题,肯定都是不变的

JS中所有用单引号或者双引号包起来的都是字符串,每一个字符串都由0到多个字符组成

字符串中的每一个字符都有一个自己对应的位置的索引,也有类似于数组一样的length代表自己的长度

1
2
3
4
5
6
7
var str='abcdefghijk'

str.length => 字符串长度
str[0] => 'a'
str[str.length-1] => 字符串最后一个字符
str[100] => undefined

charAt/charCodeAt

作用:charAt 根据索引获取指定位置的字符charCodeAt不是获取索引对应的字符,它获取的是索引对应的字符的Unicode编码值(ASC II码值)

参数:索引

返回值:字符或者对应的编码

和直接操作索引方式获取的区别:

索引不存在的时候,str[x] 获取的结果是undefined,运行机制和对象是一样的,而charAt(x)获取的结果是空字符串

通过编码返回原有字符:String.fromCharCode(108) => 'l'

1
2
3
4
5
6
7
var str='liyapei';
console.log(str.charAt(0)) //'l'
str[0] //'l'
console.log(str.charAt(10)) // ''
str[10] //undefined

str.charCodeAt(0) //'l' 对应的Unicode编码值(十进制) 108

indexOf / lastIndexOf

这两个方法不支持IE低版本浏览器(IE6,7,8)

作用:检测当前值在字符串中第一次或者最后一次出现位置的索引这个字符,返回大于等于0的索引,如果没有返回-1,基于这两个方法可以验证当前字符串中是否包含某一个字符

参数:要检测的值

返回值:索引

slice 查找

作用:str.slice(n,m) 从索引n开始找到索引为m处(包含n不包含m),把找到的字符当做新字符串返回

  • 1、和数组的slice操作是一样的
  • 2、不写m是查找到字符串的末尾
  • 3、n/m 都不写是字符串的克隆
  • 4、支持负数索引;用字符串的总长度+负数索引做运算
1
2
3
4
5
var str = 'liyapeiaixuexi'
str.slice(2,7) //'yapei'
str.slice(2) //'yapeiaixuexi'
str.slice() //'liyapeiaixuexi'
str.slice(-3,-1) //'ex'

substring

和slice语法完全一模一样;

唯一的区别 :slice支持负数索引,而substring不支持负数索引

负数索引返回 空字符串

1
2
3
4
5
var str = 'liyapeiaixuexi'
str.slice(2,7) //'yapei'
str.substring(2,7) //'yapei'
str.slice(-3,-1) //'ex'
str.substring(-3,-1) //''
阅读全文 »

数组去重

方法一

1、依次拿出数组中的每一项(排除最后一项:最后一项后面没有需要比较的内容)

2、和当前拿出项后面的每一项依次比较

3、如果发现有重复的,我们把找到的这个重复项原数组中删除掉(splice)

4、i-- 防止数组塌陷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var arr=[1,2,3,2,3,4,3,4,5]

//方法一
/**
*1、依次拿出数组中的每一项(排除最后一项:最后一项后面没有需要比较的内容)
*2、和当前拿出项后面的每一项依次比较
*3、如果发现有重复的,我们把找到的这个重复项在原数组中删除掉(splice)
*/

//=>arr.length-1 不用拿最后一项
for(var i=0;i<arr.length-1;i++){
var item =arr[i];
//item依次拿出每一项
//i:当前拿出项的索引
//和当前拿出项后面的每一项比较:起始索引为i+1
for(var j=i+1;j<arr.length;j++){
if(item === arr[j]){
arr.splice(j,1);
//这样会导致数组塌陷问题:当我们把当前项删除后,后面每一项都要向前进一位,也就是原有数组的索引发生了改变,此时我们j继续累加1下次拿出来的结果就会跳过一位
//所以删除后先--,再++时相当于没减
i--;
}
}
}
console.log(arr) //[1,2,3,2,4,5]
阅读全文 »

数组也是对象数据类型,也是由键值对组成

1、以数字作为索引(属性名),索引从0开始递增

2、有一个length的属性存储的是数组的长度

数组中每一项都可以是任何数据类型

arr[0] 获取第一项

arr[arr.length-1] 获取最后一项

splice改变、slice查找

1.1-1.4新增返回长度,删除返回删除项

slice参数都是索引值

1
2
3
4
5
6
7
8
9
10
var arr=[12,12,15]
/*
*结构:
* 0:12
* 1:12
* 2:15
* length:3
*/
1、以数字作为索引(属性名),索引从0开始递增
2、有一个length的属性存储的是数组的长度
阅读全文 »

函数 :具备一定功能的方法

函数诞生的目的就是为了实现封装:**把现实一个功能的代码封装到一个函数中,后期想要实现这个功能,只需要把函数执行即可,不必再次编写重复的代码,起到低耦合高内聚(减少页面冗余代码,提高代码的重复使用率)的作用,我们把以上特点叫做函数封装**

OOP面向对象编程思想,需要我们掌握类的继承、封装、多态

函数数据类型也是按照引用地址操作的

1
2
3
4
5
6
7
8
9
10
11
ES3:
function 函数名([参数]){
函数体:实现功能的js代码
}
函数名();

ES6箭头函数:
let 函数名 =([参数])=>{
函数体
}
函数名();
1
2
3
4
5
6
7
8
9
10
function  fn(){
//代码
}
fn; //=>输出函数本身
fn(); //=>函数执行

let fn=()=>{

}
fn();
阅读全文 »

值类型(基本数据类型):基本数据类型的值会存储在当前作用域下

var a=12;

  1. 首先在当前作用域下开辟一个空间存储12
    2)在当前作用域中声明一个变量a
    3)让声明的变量和存储的12进行关联

    直接按置操作:把原有的值复制一份,放在新的空间位置上,和原来的值没有关系,变量间相互不影响

    一个变量只能存一个值

对象数据类型(引用数据类型):按内存空间【引用地址】地址来操作

引用数据类型不能直接存储到当前作用域(因为存储的内容过于复杂),我们需要新开辟一个空间把内容存储在这个空间中

js遇到对象:

1、先创建一个变量(声明一个函数名和声明一个变量一样 ,如果两个变量名重复 是会冲突的)
2、浏览器为其开辟一个新的内存空间,为了方便别的地方找到这个空间 会给空间分配一个16进制的地址 (16进制:0-9 a-f)
3、按照一定顺序,把对象中的键值对存到内存空间
4、把开辟内存的地址赋值给变量(或者其他的东西比如事件),以后变量就可以通过地址找到内存空间然后进行操作

操作的是空间的引用地址:把原来空间地址赋值给新变量,但是空间没有被克隆,还是一个空间,这样就会出现多个变量关联的是相同的空间,相互之间就会存在影响

栈内存、堆内存

栈内存:本身就是一个供js代码执行的环境,所有的基本数据类型都会在栈内存中开辟一个位置进行存储;作用域就是一个栈内存

堆内存:用来存储引用类型中的信息值的,对象存储的是键值对函数存储的是代码字符串

阅读全文 »

+的 数学运算和字符拼接

1、当表达式中出现字符串,就是字符串拼接否则是数学运算
2、数学运算:遇到的只要不是字符串都先转化为数字
3、字符串拼接:遇到的只要不是字符串都先调用toString方法转为字符串
4、在对象数据类型的数学运算中除了普通对象,其他的都是先转字符串进行字符串拼接

  • 1+true => 2 数学运算
  • ‘1’ + true => ‘1true’ 字符串拼接
  • [12] + 10 => ‘1210’ 虽然现在没有字符串,但是引用数据类型转为数字先转为了字符串,所以变为了字符串拼接,(在对象数据类型中除了普通对象,其他的都是先转字符串再进行字符串拼接)
  • ({}) + 10 => “[object Object]10”
  • []+ 10 => ‘’ + 10 => ‘10’ 这些输出是控制台直接输出,console.log结果是"[object Object]10"
  • {} +10 => 10 这个和上边说的没关系,因为它既不是数学运算,也不是字符串拼接,他是两部分代码
    • {}代表一个代码块(块级作用域)
    • +10 才是我们的操作
    • 严格写法:{};+10; 结果是10
    • function(){} +10 => +10; => 10
    • +10 就是0+10
阅读全文 »