看完这篇文章,你将了解

  • keydown 和 keypress 的区别
  • onblur 事件是什么,怎么用
  • readonly 属性是什么
  • 从一道题目进一步认识 prototype
  • 双重循环可以用哈希表优化
  • JavaScript 如何实现链表

keydown 和 keypress 的区别

  • keydown 和 keyup 配对,响应所有键盘按下,全键盘除了 fn 键都可以;keydown 的时候按住会持续触发
  • keypress 响应字母键盘输入,包括 a-z, 0-9 和符号键;响应按下或按住,按住的时候会持续触发

onblur 事件当一个元素失去焦点时会触发

  • onblur = fn 或者 addEventListener('blur', fn) 调用
  • 注意:onblur 是元素失去焦点,onfocus 是元素获得焦点
  • demo

readonly 属性

  • If set to true, then the user cannot change the value of the element. However, the value may still be modified by a script.

  • 可以用于 input 标签:A Boolean attribute which, if true, indicates that the input cannot be edited
  • readonly 只对 input 和 textarea 有效,而 disable 对所有表单元素有效

prototype 解析

看一个问题:

var A = {n: 4399}
var B = function() {this.n = 9999}
var C = function() {var n = 8888}
B.prototype = A
C.prototype = A

var b = new B()
var c = new C()

A.n++

// b.n === ?
// c.n === ?

解决的关键是要清楚:

  • 如果一个对象,自身属性和 proto 引用有相同属性,那么以自身属性优先

先找自己身上有没有该属性,找不到,再进入原型链搜索

  • new 的本质是让函数返回一个对象的语法糖,它干了这几件事

    function xx() {
        let obj = {}
        let this = obj
        
        ... // 原代码
        
        return obj
    }

所以 var n = 8888 不同于 this.n = 8888 ,不能让生成的对象具有属性 n


双重循环用哈希表优化

形如

for(let i=0; i<nums[i].length; i++) {
    for(let j=0; j<nums[j].length; j++) {
    }
}

的代码结构,有时可以用哈希表取代遍历,将两层遍历转化为两次遍历

比如

我一开始是这样

var twoSum = function(nums, target) {
    for(let i=0; i<nums.length; i++) {
        for(let j=i+1; j<nums.length; j++) {
            if(nums[i] + nums[j] === target) {
                return [i, j]
            }
        }
    }
};

优化后时间减半

var twoSum = function(nums, target) {
    // 遍历第一次,用哈希表记下 {数组值, 下标}
    let hash={}
    for(let i=0; i<nums.length; i++) {
        let value = i
        let key = nums[i]
        hash[key] = value
    }
    
    // 遍历第二次,根据差值找哈希表中是否答案
    for(let i=0; i<nums.length; i++) {
        let another = target - nums[i]
        let j = hash[another]
        if(j !== undefined && j !== i) {
            return [i, j]
        }
    }
};

JavaScript 如何实现链表

定义链表

 function ListNode(val) {
     this.val = val;
     this.next = null;
 }

可以用头结点的技巧新建链表

一开始没用头结点,导致代码比标准答案冗长。按照答案修改后又总是出 bug,后来细心观察才发现它用到了头结点的技巧。套路如下:

let l3 = new ListNode(null)
let k = l3

...

k.next = new ListNode(xx)
k = k.next

...

return l3.next  // 注意这里

这里是demo