JavaScript语言核心基础重点总结(一)

182 阅读6分钟

变量和变量声明提升

变量的命名规范

以字母、数字、下划线、美元符号构成,不能以数字开头,不能是关键字和保留字。

// 合法变量
var a;
var a_;
var _;
var $000;
// 非法变量
var 2year;
var function;
var a@3;

变量的默认值

变量默认值是undefined

var a;
console.log(a); // undefined
var a, b, c = 4;
console.log(a); // undefined
console.log(b); // undefined
console.log(c); // 4

变量声明提升

JS有一个独一无二的“预解析”阶段。在预解析阶段,会提升所有变量声明。

注意:只提升声明,不提升值。

console.log(a); // undefined
var a = 10;

注意,面试题会结合变量作用域考察。

var m = 5;
function fun() {
    console.log(m); // undefined
    var m = 3;
}
fun();

注意,提升无视if语句

var a = true;
function fun() {
    if (!a) {
        var a = 3;
    }
    console.log(a);
}
fun();

注意,if语句会在预解析阶段被无视。所以a此时是局部变量。

当程序执行时,if语句判断的是if(!undefined),所以if语句能够执行,a此时被赋值为3。程序正确答案是输出3。

运算符

数学运算符

+、-、*、/、%

== 是不带类型判断相等,有隐式转换

console.log(5 == '5'); // true
console.log(null == undefined); // true
console.log('1' == true); // true

逻辑运算符

!、&&、||

短路计算:口诀“借假钱,花真钱”

console.log(3 && 8); // 8
console.log(0 && 8); // 0
console.log(undefined && 8); // undefined
console.log(null && 8); // null
console.log(3 || 8); // 3
console.log(0 || 8); // 8
console.log(undefined || null); // null
console.log('' || 'ABC'); // 'ABC'

注意,JS中没有连比,就是判断一个变量a是否介于18到70之间,正确写法:

a >= 18 && a <= 70

赋值运算符

JS中,一个等号表示赋值,不是表示相等。表示相等用==运算符。等号=是赋值。

  • += 是累加器那个符号;
  • *= 是累乘器那个符号。

重点是a++和++a的区别。给大家一个面试题:

var a = 0;
    while(++a < 3) {
    console.log(a);
}
和
var a = 0;
while(a++ < 3) {
      console.log(a);
}
有什么区别?

讲解:

整体而言,第一段程序是先自增1再比;第二段程序,是先比再增1。

第一段程序:

while(++a < 3),此时会先把a进行加1操作,然后和3进行比较大小。

也就是说,a一开始是0。然后此时++a让a变为1,1和3进行了比较,确实1小于3,所以输出1;

然后此时++a让a变为2,2和3进行了比较,确实2小于3,所以输出2;

然后此时++a让a变为3,3和3进行了比较,3不满足小于3,所以不进入循环体了。

第二段程序:

var a = 0;

while(a++ < 3) {

    console.log(a);

}

while(a++ < 3),此时会先把a和3进行比较大小,然后自增1。

也就是说,a一开始是0。先比再增1。0和3进行了比较,确实0小于3,然后a++让a变为1,所以输出1;

然后,先比再增1。1和3进行了比较,确实1小于3,然后a++让a变为2,所以输出2;

然后,先比再增1。2和3进行了比较,确实2小于3,然后a++让a变为3,所以输出3;

还有这一题:

var a = 3;
var b = 4;
console.log(a++ + ++a + b++ + ++b);

是3、5、4、6相加,答案是18。

类型

JS类型划分

基本类型值:number、string、boolean、undefined、null

引用类型值:数组、对象、函数、正则表达式、DOM对象

typeof的检测特殊结果

记住这些:

  • 注意 typeof undefined 值是 undefined 。
  • 注意 typeof null 值是 object 。人认为null不是对象,是基本类型值,是null类型。
  • 注意 typeof [] 值是 object 。

这里有一个引申问题,就是如何判断一个值是数组,不能用typeof判断值是不是数组。因为typeof检测

结果是object。怎么办?用 Array.isArray()

Array.isArray([]) // true
Array.isArray([3, 4, 5, 6]) // true
Array.isArray({a: 1}) // false

隐式转换

隐式转换,记忆规律,还不如记忆特殊情况。

隐式转换底层调用的是Number、String、Boolean。

其他东西转为数字

Number(true) // 1
Number(false) // 0
Number(null) // 0
Number(undefined) // NaN
Number('3年') // NaN
Number('123') // 123

意义:做数学运算的时候,能够进行隐式转换

console.log(1 + true); // 2
console.log(1 + null); // 1,因为null会被转为0
console.log(1 + undefined); // NaN

其他东西转为布尔

Boolean(undefined) // false
Boolean(NaN) // false
Boolean(1) // true
Boolean(6) // true
Boolean(0) // false
Boolean('') // false
Boolean('false') // true,只要字符串不是空,就是true

意义:if语句的圆括号中,会用Boolean隐式转换

if (6) { // 能进入 }
if ('') { // 不能进入 }
if ('a') { // 能进入 }
if (undefined) { // 不能进入 }

判等规则

不总结,记忆特殊值即可。

0 == false // true
1 == true // true
6 == true // false
undefined == null // true
NaN == NaN // false,记住,NaN不自等。
'1' == true // true,对于字符串来说,只有'1'能等于true,别的字符串都不等于true
'0' == false // true,对于字符串来说,只有'1'能等于false,别的字符串都不等于true

if语句

跳楼现象

if语句满足一个分支,就不再执行其他分支了,就退出if语句体了。

var a = 3;
if (a == 3) {
    a++;
} else if (a == 4) {
    a++;
}
console.log(a); // 4

单行if可以省略大括号

注意,如果if语句没有else,也没有else if。并且if的大括号中,只有一条语句,可以省略大括号。

比如:

var a = 3;
if (a > 2) {
    console.log('你好');
}

等价于:

var a = 3;
if (a > 2) console.log('你好');

如果语句多于1条。就不能用省略大括号这个技巧。比如:

var a = 3;
if (a > 444) console.log('你好'); console.log('哈哈哈');

程序运行结果是输出哈哈哈。因为JS认为,只有 console.log('你好'); 被if语句限制了。

即,只有一条语句能够省略大括号。

switch-case语句

注意case穿透。

var a = 2;
switch (a) {
    case 1:
        console.log('A');
    case 2:
        console.log('B');
    case 3:
        console.log('C');
    case 4:
        console.log('D');
        break;
    case 5:
        console.log('E');
}

输出B、C、D。因为case穿透。如果一个满足了,那么会无条件执行后续所有的。直到遇见break。

循环语句

for循环

现在,语法已经不是问题了。 for(var i = 0; i < arr.length; i++) 已经能够嗷嗷写了。

最大的就是就是算法题目了。

算法:累加器

基本累加器

最基本的计算1+2+3+……+100已经算是基本题目了。

var sum = 0;
    for (var i = 1; i <= 100; i++) {
    sum += i;
}
console.log(sum);

不是基本题目的累加器有哪些呢?

车厢法

车厢法,真谛:寻找后一项和前一项的关系。

比如题目:

计算2+22+222+2222+……+2222222

答案:

var sum = 0;
var temp = 0;
for (var i = 1; i <= 7; i++) {
    temp = temp * 10 + 2;
    sum += temp;
}
console.log(sum);

比如题目:

10.png

答案:

var sum = 0;
var temp = 1;
for (var i = 1; i <= 3; i++) {
    temp = temp * (i / (i + 1))
    sum += temp;
}
console.log(sum);

i / i + 1 法

比如题目:

计算1/2 + 2/3 + 3/4 …… + 9/10

此时用i/i+1法。

// 1/2 + 2/3 + 3/4 …… + 9/10
var sum = 0;
for (var i = 1; i <= 9; i++) {
    sum += i / (i + 1);
}
console.log(sum);

算法:穷举法

列出来,一个一个试验,看看是不是满足条件。满足就输出。

输出1~100所有“逆数”大于它本身的数。比如35,它的逆数是53。再比如67,逆数就是76。6的逆数就是6。70的逆数就是7。

还记得以前学习的“我爱JS”变为“SJ爱我”。思路就是字符串,变为数组,逆序,变为字符串。

for(var i = 1; i <= 100; i++) {
    var nishu = Number(String(i).split('').reverse().join(''));
    
    if (nishu > i) {
        console.log(i);
    }
}

while循环

没有范围的时候,用while循环。

寻找最小的,除以3余1 除5余2 除7余4 除13余6的数字

答案:

var n = 0;
while (true) {
    n++;
    
    if (n % 3 == 1 && n % 5 == 2 && n % 7 == 4 && n % 13 == 6) {
        console.log(n);
        break;
    }
}

要记住,while(true)非常好用,结合break使用。二阶段考试题,不会提示你用什么循环。但是,只要

你看见“寻找最小的”这样的字眼,就是while循环。因为你不知道范围。

数组

数组的方法

必须死记硬背:

变异方法,就是会改变数组的:

push()
pop()
unshift()
shift()
splice()
reverse()
sort()

非变异方法:

slice()
join()
includes()
indexOf()

数组的常见算法

记住,所有关于数组的算法,一定要遍历数组的每一项。没有例外!

数组,生来为遍历!

for(var i = 0 ; i < arr.length; i++) {

}

数组求和:

var arr = [3, 4, 6, 2, 1, 3];
var sum = 0;
for (var i = 0; i < arr.length; i++) {
    sum += arr[i];
}

console.log(sum);

数组求最大值:

var arr = [3, 4, 6, 2, 1, 3];
var max = arr[1];
for (var i = 1; i < arr.length; i++) {
    if (arr[i] > max) {
        max = arr[i];
    }
}
console.log(max);

数组去重:

var arr = [3, 4, 6, 6, 6, 6, 2, 1, 3];
var result = [];
for (var i = 0; i < arr.length; i++) {
    if (!result.includes(arr[i])) {
        result.push(arr[i]);
    }
}
console.log(result);

数组交集:

var arr1 = [3, 4, 6, 2, 1];
var arr2 = [5, 3, 9, 6];
var result = [];
for (var i = 0; i < arr1.length; i++) {
    if (arr2.includes(arr1[i])) {
        result.push(arr1[i]);
    }
}
console.log(result);

求数组的连续最长子串:

var arr = [3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6];
var temp = arr[0];
var count = 1;
var zy = arr[0];
var zy_c = 1;

for (var i = 1; i <= arr.length; i++) {
    if (arr[i] == temp) {
        count++;
    } else {
        if (count > zy_c) {
            zy = temp;
            zy_c = count;
        }
        temp = arr[i];
        count = 1;
    }
}
console.log(zy, zy_c);

这个算法,记住,用A4认认真真,写写画画一遍。算法这个东西,确实很神奇,只要理解了,头脑中有了,终身忘不掉。

相邻项差值最大(减肥)

var arr = [50, 49, 51, 49, 48, 45, 36, 41, 43, 39];
var max = 0;
// 遍历数组,每一项都和下一项做减法。如果减法差值大于了max,那么它就是max。
for (var i = 0; i <= arr.length - 2; i++) {
    if (arr[i] - arr[i + 1] > max) {
        max = arr[i] - arr[i + 1];
    }
}

console.log(max.toFixed(2));

对象

var xiaoming = {
    name: '小明',
    age: 12
}

我们学习对象的意义,是后端给我们的数据,叫做JSON结构,就是数组+对象的形式。要会进行处理。

说白了,对象一般不纯考面试题,而是结合数组,进行一些算法题。算法和数组的算法是一样的,只不过增加了对象的成分。

比如,给你全班考试成绩,问你谁是总分状元?

var arr = [
    { name: '小A', a: 3, b: 5, c: 1 },
    { name: '小B', a: 5, b: 2, c: 2 },
    { name: '小C', a: 1, b: 3, c: 7 },
    { name: '小D', a: 5, b: 5, c: 3 },
    { name: '小E', a: 7, b: 5, c: 4 }
];

var max = 0;
var name = '';
for (var i = 0; i < arr.length; i++) {
    if (arr[i].a + arr[i].b + arr[i].c > max) {
        max = arr[i].a + arr[i].b + arr[i].c;
        name = arr[i].name;
    }
}
console.log(max, name);

函数

函数作用域

我们的JS中,用var定义的变量,作用域是定义时函数内部。

function fun() {
    var a = 5; // a是在fun里面定义的,所以a是局部变量
}
fun();
console.log(a); // 报错,因为a是局部变量

注意遮蔽现象:

var a = 666;
function fun(a) {
    a++;
    console.log(a); // 输出5,局部变量a,因为形式参数a把全局的a遮蔽了。
}
fun(4);
console.log(a); // 输出666。它没有被加1。因为函数里面是局部变量。
var a = 666;
function fun() {
    var a = 5; // a是在fun里面定义的,所以a是局部变量
    console.log(a); // 输出5。局部的a把外部的a遮蔽了。
}
fun();

注意:JS中如果有这样的写法 var a = b = 3 。那么此时会这样顺序执行:

① 先将3的值赋给b,同时认为b会被定义为全局变量。为啥?没为啥,因为JS特性。

② 再将3的值赋给a,同时由于a前面有var,所以它是局部变量。

这种叫做“一个值连等赋给两个变量,那么中间那个变量,就是全局变量了”。

给我们的启示是,如果想一个值赋给两个变量,只能拆开写:

var a = 3, b= 3;

不能:

var a = b = 3;

var a = 666;
function fun() {
    var a = b = 3;
    console.log(a); // 输出3,因为局部的a把全局遮蔽了
}
fun();
console.log(b); // 输出3,不报错,因为JS特性,b是全局变量了。

闭包

  • 闭包是什么:函数本身,和定义时所处的外部环境,合称为“闭包”。
  • 表现:函数如果被挪到了其他地方执行,那么仍然能够使用定义时候的作用域。
  • 功能:1、制作记忆性的程序,比如调用一次inner()就让内部a加1; 2、能够私有化变量,让a被保管的安全一些,只能让它增加,不能减少。
  • 缺点:容易造成内存泄露。比如外部函数已经设置为null了,闭包还在。

例子:

function fun() {
    var a = 3;
    return function() {
        console.log(a);
    }
}
var inner = fun();
var a = 8;
inner();

函数整体提升

函数提升整体,但是 var fun = function(){} 只提升定义。

要会这种恶心题:

fun(); // C

function fun() {
    console.log('A');
}

fun(); // C
    var fun = function () {
    console.log('B');
}

fun(); // B

function fun() {
    console.log('C');
}

fun(); // B

var fun = function () {
    console.log('D');
}

fun(); // D

递归

我们慢慢学吧,DOM时期、JS高阶、面试题时期,都是Danny老师讲。“师承教育”。

现在只需要会一个题目,递归求阶乘:

function jiecheng(n) {
    return n == 1 ? 1 : n * jiecheng(n - 1);   
}

函数的算法

如果能简化问题,那么写封装函数。

var arr = [
    { name: '小A', h: 1.75, w: 50 },
    { name: '小B', h: 1.65, w: 60 },
    { name: '小C', h: 1.73, w: 70 },
    { name: '小D', h: 1.65, w: 72 },
    { name: '小E', h: 1.85, w: 60 }
];

for (var i = 0; i < arr.length; i++) {
    console.log(arr[i].name + '的情况是' + bmi(arr[i].h, arr[i].w));
}

function bmi(h, w) {
    var m = w / (h * h);
    if (m > 27) {
        return '肥胖';
    } else if (m > 24) {
        return '正常';
    } else if (m > 18) {
        return '偏瘦';
    } else {
        return '太瘦了';
    }
}