默认的有效时间为-1,不设置过期时间时,在浏览器会话结束时过期。

重绘和回流

原型链01

function A() {
  this.do = function () {
    return 'foo'
  }
}
A.prototype = function () {
  this.do = function () {
    return 'bar'
  }
}
var x = new A().do(); // 'foo'

new运算符对函数A进行构造调用,首先创建一个空对象,然后将this指向这个对象,再执行函数A中的代码,最后返回这个对象。A.prototype=重写了函数A的原型,所以如果当函数A中没有定义do()时,下面的运行结果将是xxx is not a function

原型链02

function A(x) {
  this.x = x;
}
A.prototype.x = 1;

function B(x) {
  this.x = x;
}
B.prototype = new A(); // new A();并没有给A的原型链上的x赋值
var a = new A(2); // a.x = 2; a.__proto__.x = 1;
var b = new B(3); // b.x = 3; b.__proto__ = B.prototype = { x: undefined }
delete b.x; // 删除的是对象b上的属性x
console.log(a.x); // 2
console.log(b.x); // 读的是原型链上的x:undefined

总结原型链

闭包和内存堆栈

function test() {
    var n = 4399;
    function add() {
        n++;
        console.log(n);
    }
    return {n: n, add: add}
}
var result = test();
var result2 = test();

此时,resultresult2都形成了各自的内存堆栈,有各自的闭包,两个互不相干,我在这里容易搞错,以前以为是resultresult2同时引用了函数test中的n,实践表明并不是。

关于this指向

var user = {
    count: 1,
    getCount: function () {
        return this.count;
    }
}
var func = user.getCount;
console.log(func());  // undefined

func只引用了赋值给user.getCount变量的匿名函数的内存地址,执行func()时,其实是window.func()此时匿名函数中的thiswindow,并没有变量count,所以打印出来的就是undefined

自运行函数

segmentfault

自运行函数中var声明的变量不会提升到全局作用域中

// 自运行函数前一般会加上一个;分号,避免产生一些其它问题
;(function() {
  var a = 1;
  console.log(a);
})()
console.log(a);  // ReferenceError: a is not defined

let变量声明的暂时性死区

let x = 10;
let foo = () => {
  console.log(x);
  let x = 20;
  x++;
}
foo();

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

——《ES6入门》

就是说不会在块级作用域之上的作用域中寻找变量。

浮点数取整

var a = 10.42;
parseInt(a);  // 取整数,默认为十进制,10
Math.floor(a);  // 向下取整,10
Math.ceil(a);  // 向上取整,11
a.split('.')[0];  // 字符串才有鬼split方法,报错

匿名函数赋值给变量和命名函数

var foo = function (x, y) {
  return x - y;
}
function foo(x, y) {
  return x + y;
}
var num = foo(1, 2);  // -1

命名函数和var一样会被提升到代码的最前面,而匿名函数赋值给变量则只在代码执行到该行时才赋值给变量,所以num输出-1

事件循环

for循环

for循环中包含四个部分:

// var i = 0 为初始化表达式
// i < 10 计算条件的值
// i++ 更新表达式
// 循环体
for(var i = 0; i < 10; i++) {
  console.log(i);  // 0~9
  setTimeout(() => {
    console.log(i);
  }, 10)
}
// 因为循环到i=9是符合条件,所以更新了表达式,最终i=10
console.log(i);  // 10

运算符

JavaScript拥有如下运算符:

  1. 赋值运算符。

  2. 比较运算符。

  3. 算数运算符。

  4. 位运算符

  5. 逻辑运算符。

  6. 字符串运算符。

  7. 条件(三元)运算符。

  8. 逗号运算符。

    对两个操作数进行求值并返回最终操作数的值。它常常用在 for 循环中,在每次循环时对多个变量进行更新。

    一般出现在for循环中的初始化表达式和更新表达式中。

  9. 一元运算符。

    voiddeletetypeof

  10. 关系运算符。

    ininstanceof

运算符的优先级

function out(x) {
  var temp = 2;
  function inside(y) {
    // ()圆括号运算符优先级最高,递减运算符--后置,则返回递减前的值,反之则是递减之后的值
    console.log(x + y + (temp--));  // 3 + 5 + 2 = 10;
    console.log(temp);  // 1
  }
  inside(5);
}
out(3);

函数提升

(function () {
  var x = foo();  // Uncaught TypeError: foo is not a function
  var foo = function foo() {
    return "foobar"
  };
  return x;
})();

具名函数赋值给变量并不会被提升,而且名字只能在函数内部使用(既递归调用)。

冒泡

不支持冒泡的事件:blurfocusmouseentermouseleaveloadunloadresize

node包引用查找顺序

  1. 首先加载核心模块(在核心模块中查找)。
  2. 再是扩展名分析,查找node_modules中是否有引入的xxx.js文件。
  3. 没有的话就继续查找node_modules中是否有xxx文件夹,依次加载其中的index.jsindex.nodeindex.json
  4. 还没有找到对应的模块就向上一级目录找。

事件冒泡与捕获

preventDefault();
stopImmediatePropagation();
stopPropagation();
cancelBubbe();
returnValue();

正则表达式的内置方法

正则对象的实例方法:

RegExp.prototype.compile()  // 已废弃
RegExp.prototype.exec()  // 返回数组或者null,会更新正则对象的lastIndex属性
RegExp.prototype.test()
RegExp.prototype.toString()  // 返回一个表示正则的字符串
RegExp.prototype.exec()

截屏2020-12-22 下午11.56.12

图中的index为匹配到的字符位于原始字符串的基于0的索引值。

RegExp.prototype.test()
lastIndex

字符串实例上与正则有关的方法:

String.prototype.match()
String.prototype.matchAll()
String.prototype.replace()
String.prototype.search()
String.prototype.split()

Array.prototype.splice()

[1, 2, 3].splice(1, 1, 1) == [2]  // false

上面的方法用自然语义来说:删除数组[1, 2, 3]索引为1开始的元素,总共删除1个,并在索引为1的位置添加一个元素1,最后以数组的形式返回删除的元素。

返回的是[2],但是由于与==后面的[2]并不是一个内存地址,所以为false


刷题

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

下拉框组件问题梳理 上一篇
搭建git服务器 下一篇