问题先导
对html语义化的理解,有哪些常见的语义化标签?【
html
】css中有哪些常见的可继承属性,不可继承属性?【
css
】判断js数据类型的方法有哪些?【
js
】阐述Vue的基本实现原理【
vue
】-
算法题:无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
知识梳理
对HTML标签语义化的理解,有哪些常见的语义化标签?
语义化就是我们通过标签本身就知道标签所代码的内容具有什么意义,即用使用特定的功能属性的标签做特定的事。比如使用h1
标签我们就知道这是一个标题,使用header
就知道这是页眉,使用footer
就知道这是页脚。
语义化标签就是具有特定功能或属性的标签,语义化标签有两个好处:
- 一是对机器友好。语义化能让搜索引擎爬虫更有效地捕获页面结构,有利于SEO;利于页面结构分析,如识别文章标题,生成目录等等。
- 二是对开发者友好。语义化让文档结构更清晰,便于整理和优化页面结构。
常见的语义化标签有:
页眉
文档中的区段、小节
标签规定文档的主要内容区域
定义外部的内容,其中的内容独立于文档的其余部分。文章、评论等
参考文献的引用
标签定义块引用。
代码片段
我们最常用的两个无语义标签div
和span
,如果你知道某处文档片段的意图,应该使用正确的语义化标签来替代或者包裹这些无语义标签,如果没有具体的语义标签,也可以通过增加类名来给标签分类,以到语义化标签的属性标记效果。
标签:HTML
css中有哪些常见的可继承属性,不可继承属性?
样式继承的目的是为了更好地适应页面变化,也就是修改样式时让页面更平滑地过渡:设置父元素时希望子元素样式保持统一,那么就继承,如果继承后页面属性变化比较突兀,就不应该继承,比如我设置了div
的字体大小,那么是希望其子元素的字体大小均被继承的,但对于盒模型属性、定位属性这种“比较私有”的属性,如果继承了,反而比较突兀。
常见的可继承属性有:
- 字体系列属性:
font-size
等 - 文本系列属性:
text-align
等 - 其他:
visibility
、cursor
等
其余基本基本都是默认不可继承的,因为样式继承容易造成界面发生非预期的不可控变化。
实际上,所有属性都是可继承的,上面说的不可继承是指默认不可继承,如果需要继承某属性,我们可以使用inherit
属性值来规定:
div > p {
border: inherit;
}
如果希望所有属性都继承,则使用all: inherit;
来控制。
标签:CSS基础
判断js数据类型的方法有哪些?
js数据类型分为两种:基本数据类型和引用数据类型。一般情况下,判断基本数据类型使用typeof
关键字,而判断引用类型使用instanceof
关键字。
-
typeof
typeof 2 === 'number' typeof 'jinx' === 'string' typeof null === 'object' typeof Ayyay === 'function'
实际上,
typeof
运算符的原理同Object.prototype.toString
一样:var toString = Object.prototype.toString; console.log(toString.call(2)); // [object Number] console.log(toString.call(true)); // [object Boolean] console.log(toString.call('str')); // [object String] console.log(toString.call([])); // [object Array] console.log(toString.call(function(){})); // [object Function] console.log(toString.call({})); // [object Object] console.log(toString.call(undefined)); // [object Undefined] console.log(toString.call(null)); // [object Null]
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。值得注意的是,该运算符只适用于实例对象,也就是说判断基本数据类型无效。object instanceof constructor
:某个实例对象 instanceof 某个构造函数。
标签:js数据类型
阐述Vue的基本实现原理
以往的前端都是使用js直接控制DOM来实现页面的变化,js也更像是为页面服务的小弟(脚本)。但随着web应用的复杂化,js和页面的复杂程度和以往相比都不是一个量级的,有组织有架构的工程化开发就变得十分必要,随着MV*
类架构的发展,很多桌面应用都迁移到了web端,变成了web app,也就是单页面应用(single page web application)。
在这些变化中,数据驱动视图成为主流设计,比如Vue采用的MVVM
模型也是如此:
Vue实例创建时:
- 解析指令(Compiler):通过
template
和data
等参数构建渲染函数Render Function
。 - 劫持数据变化(Obverser):并通过
Object.defineProperty
的getter/setter
来劫持数据变化。(Vue3.0通过Proxy代理对象来实现) - 发布订阅模式实现数据响应:上面做数据劫持的目的就是为了监听数据变化,也就是发布订阅中的观察者身份
Obverser
,当数据变化后,会发送通知给Dep
对象,也就是发布订阅模式中的事件中心(经纪人),然后又Dep
告知订阅者Watcher
对象,Watcher
便响应式地触发了re-render
重新渲染的过程。
注:从上图来看,Vue更像是观察者模式,比如Obverser
调用Notify
来告知Watcher
,实际上,这里只是省略了Dep
对象。而观察者模式和发布订阅模式虽然从结构上来说,发布订阅多了一个事件中心对象Dep
,也就是观察者和订阅者之间没有直接关联了,解耦合了,但从意图上来看,这两种模式都是为了实现一对多依赖关系而设计,因此,往往可以不必过于纠结于此,发布订阅模式可看作是观察者模式的升级版。
另外,渲染函数更新的其实是Virtual Dom
即虚拟Dom,然后才是通过虚拟Dom更新视图,这有助于视图更新的性能优化,更多细节可参考:virtual dom - github
参考:
深入响应式原理 - Vue
Vue基本原理
发布订阅模式
标签:Vue基础
算法题:无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
暴力解法通常就是万能解法,但一般都不是我们需要的算法,然而通过对暴力算法的分析,我们可以往往能找到解决问题的关键,进而加以优化,就能得到较为优质的答案。
本题的暴力解法是:循环两次,找到所有的子串,然后判断该子串是否包含重复字符,并记录出现的最长无重复字符子串。其中的关键点有:获取子串;判断是否具有重复字符;记录最长子串。
子串的获取我们实际上通过双指针遍历一次就能实现,而不用遍历两次。判断是否存在重复子串我们可以用hash表来协助。这样,双指针的移动逻辑就成了本题的解题关键:当我们未遇到重复字符时,遍历指针不断后移即可,当遇到了重复字符,前指针就指向重复字符之后的那个字符以保障整个子串不重复。
简单来说就是通过滑动双指针的方案,在遍历过程以维护子串没有重复字符为目标而滑动指针,当遍历结束,判断也随之结束,这样,时间复杂度就变为了O(n)
。
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let i = 0;
let hash = [];
let maxLen = 0;
for(let j = 0; j < s.length; j++) {
const c = s[j];
// 出现重复
if(hash.includes(c)) {
maxLen = Math.max(maxLen, j - i );
const now = hash.indexOf(c) + 1;
i += now; // 滑动左指针
// 左指针之前的hash值都要移除
hash = hash.splice(now);
}
// 记录出现的字符
hash.push(c)
}
return Math.max(maxLen, s.length - i);
};