对line-height 的了解及其赋值形式
(1)line-height的概念:
- line-height 指一行文本的高度,蕴含了字间距,实际上是下一行基线到上一行基线间隔;
- 如果一个标签没有定义 height 属性,那么其最终体现的高度由 line-height 决定;
- 一个容器没有设置高度,那么撑开容器高度的是 line-height,而不是容器内的文本内容;
- 把 line-height 值设置为 height 一样大小的值能够实现单行文字的垂直居中;
- line-height 和 height 都能撑开一个高度;
(2)line-height 的赋值形式:
- 带单位:px 是固定值,而 em 会参考父元素 font-size 值计算本身的行高
- 纯数字:会把比例传递给后辈。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px
- 百分比:将计算后的值传递给后辈
代码输入后果
var obj = {
say: function() {
var f1 = () => {
console.log("1111", this);
}
f1();
},
pro: {
getPro:() => {
console.log(this);
}
}
}
var o = obj.say;
o();
obj.say();
obj.pro.getPro();
输入后果:
1111 window对象
1111 obj对象
window对象
解析:
- o(),o是在全局执行的,而f1是箭头函数,它是没有绑定this的,它的this指向其父级的this,其父级say办法的this指向的是全局作用域,所以会打印出window;
- obj.say(),谁调用say,say 的this就指向谁,所以此时this指向的是obj对象;
- obj.pro.getPro(),咱们晓得,箭头函数时不绑定this的,getPro处于pro中,而对象不形成独自的作用域,所以箭头的函数的this就指向了全局作用域window。
V8的垃圾回收机制是怎么的
V8 实现了精确式 GC,GC 算法采纳了分代式垃圾回收机制。因而,V8 将内存(堆)分为新生代和老生代两局部。
(1)新生代算法
新生代中的对象个别存活工夫较短,应用 Scavenge GC 算法。
在新生代空间中,内存空间分为两局部,别离为 From 空间和 To 空间。在这两个空间中,必然有一个空间是应用的,另一个空间是闲暇的。新调配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会查看 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制实现后将 From 空间和 To 空间调换,这样 GC 就完结了。
(2)老生代算法
老生代中的对象个别存活工夫较长且数量也多,应用了两个算法,别离是标记革除算法和标记压缩算法。
先来说下什么状况下对象会呈现在老生代空间中:
- 新生代中的对象是否曾经经验过一次 Scavenge 算法,如果经验过的话,会将对象从新生代空间移到老生代空间中。
- To 空间的对象占比大小超过 25 %。在这种状况下,为了不影响到内存调配,会将对象从新生代空间移到老生代空间中。
老生代中的空间很简单,有如下几个空间
enum AllocationSpace {
// TODO(v8:7464): Actually map this space's memory as read-only.
RO_SPACE, // 不变的对象空间
NEW_SPACE, // 新生代用于 GC 复制算法的空间
OLD_SPACE, // 老生代常驻对象空间
CODE_SPACE, // 老生代代码对象空间
MAP_SPACE, // 老生代 map 对象
LO_SPACE, // 老生代大空间对象
NEW_LO_SPACE, // 新生代大空间对象
FIRST_SPACE = RO_SPACE,
LAST_SPACE = NEW_LO_SPACE,
FIRST_GROWABLE_PAGED_SPACE = OLD_SPACE,
LAST_GROWABLE_PAGED_SPACE = MAP_SPACE
};
在老生代中,以下状况会先启动标记革除算法:
- 某一个空间没有分块的时候
- 空间中被对象超过肯定限度
- 空间不能保障新生代中的对象挪动到老生代中
在这个阶段中,会遍历堆中所有的对象,而后标记活的对象,在标记实现后,销毁所有没有被标记的对象。在标记大型对内存时,可能须要几百毫秒能力实现一次标记。这就会导致一些性能上的问题。为了解决这个问题,2011 年,V8 从 stop-the-world 标记切换到增量标记。在增量标记期间,GC 将标记工作合成为更小的模块,能够让 JS 应用逻辑在模块间隙执行一会,从而不至于让利用呈现进展状况。但在 2018 年,GC 技术又有了一个重大突破,这项技术名为并发标记。该技术能够让 GC 扫描和标记对象时,同时容许 JS 运行。
革除对象后会造成堆内存呈现碎片的状况,当碎片超过肯定限度后会启动压缩算法。在压缩过程中,将活的对象向一端挪动,直到所有对象都挪动实现而后清理掉不须要的内存。
DNS 记录和报文
DNS 服务器中以资源记录的模式存储信息,每一个 DNS 响应报文个别蕴含多条资源记录。一条资源记录的具体的格局为
(Name,Value,Type,TTL)
其中 TTL 是资源记录的生存工夫,它定义了资源记录可能被其余的 DNS 服务器缓存多长时间。
罕用的一共有四种 Type 的值,别离是 A、NS、CNAME 和 MX ,不同 Type 的值,对应资源记录代表的意义不同:
- 如果 Type = A,则 Name 是主机名,Value 是主机名对应的 IP 地址。因而一条记录为 A 的资源记录,提供了标 准的主机名到 IP 地址的映射。
- 如果 Type = NS,则 Name 是个域名,Value 是负责该域名的 DNS 服务器的主机名。这个记录次要用于 DNS 链式 查问时,返回下一级须要查问的 DNS 服务器的信息。
- 如果 Type = CNAME,则 Name 为别名,Value 为该主机的标准主机名。该条记录用于向查问的主机返回一个主机名 对应的标准主机名,从而通知查问主机去查问这个主机名的 IP 地址。主机别名次要是为了通过给一些简单的主机名提供 一个便于记忆的简略的别名。
- 如果 Type = MX,则 Name 为一个邮件服务器的别名,Value 为邮件服务器的标准主机名。它的作用和 CNAME 是一 样的,都是为了解决标准主机名不利于记忆的毛病。
如何判断数组类型
Array.isArray
+
操作符什么时候用于字符串的拼接?
依据 ES5 标准,如果某个操作数是字符串或者可能通过以下步骤转换为字符串的话,+ 将进行拼接操作。如果其中一个操作数是对象(包含数组),则首先对其调用 ToPrimitive 形象操作,该形象操作再调用 [[DefaultValue]],以数字作为上下文。如果不能转换为字符串,则会将其转换为数字类型来进行计算。
简略来说就是,如果 + 的其中一个操作数是字符串(或者通过以上步骤最终失去字符串),则执行字符串拼接,否则执行数字加法。
那么对于除了加法的运算符来说,只有其中一方是数字,那么另一方就会被转为数字。
ES6 之前应用 prototype 实现继承
Object.create() 会创立一个 “新” 对象,而后将此对象外部的 [[Prototype]] 关联到你指定的对象(Foo.prototype)。Object.create(null) 创立一个空 [[Prototype]] 链接的对象,这个对象无奈进行委托。
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function () {
return this.name;
}
// 继承属性,通过借用结构函数调用
function Bar(name, label) {
Foo.call(this, name);
this.label = label;
}
// 继承办法,创立备份
Bar.prototype = Object.create(Foo.prototype);
// 必须设置回正确的构造函数,要不然在会产生判断类型出错
Bar.prototype.constructor = Bar;
// 必须在上一步之后
Bar.prototype.myLabel = function () {
return this.label;
}
var a = new Bar("a", "obj a");
a.myName(); // "a"
a.myLabel(); // "obj a"
首屏和白屏工夫如何计算
首屏工夫的计算,能够由 Native WebView 提供的相似 onload 的办法实现,在 ios 下对应的是 webViewDidFinishLoad,在 android 下对应的是onPageFinished事件。
白屏的定义有多种。能够认为“没有任何内容”是白屏,能够认为“网络或服务异样”是白屏,能够认为“数据加载中”是白屏,能够认为“图片加载不进去”是白屏。场景不同,白屏的计算形式就不雷同。
办法1:当页面的元素数小于x时,则认为页面白屏。比方“没有任何内容”,能够获取页面的DOM节点数,判断DOM节点数少于某个阈值X,则认为白屏。 办法2:当页面呈现业务定义的错误码时,则认为是白屏。比方“网络或服务异样”。 办法3:当页面呈现业务定义的特征值时,则认为是白屏。比方“数据加载中”。
数据类型判断
核心思想:typeof
能够判断 Undefined、String、Number、Boolean、Symbol、Function
类型的数据,但对其余的都会认为是Object
,比方Null、Array
等。所以通过typeof
来判断数据类型会不精确。
解决办法:能够通过Object.prototype.toString
解决。
实现:
function mytypeof(obj) {
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}
- 应用
call
是为了绑定this
到obj
上 - 应用
slice
是因为这后面返回的后果是相似[Object xxx]
这样的,xxx
是依据obj
的类型变动的 - 应用
toLowerCase
是因为原生typeof
的返回后果的第一个字母是小写字母。
实现节流函数和防抖函数
函数防抖的实现:
function debounce(fn, wait) {
var timer = null;
return function() {
var context = this,
args = [...arguments];
// 如果此时存在定时器的话,则勾销之前的定时器从新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
函数节流的实现:
// 工夫戳版
function throttle(fn, delay) {
var preTime = Date.now();
return function() {
var context = this,
args = [...arguments],
nowTime = Date.now();
// 如果两次工夫距离超过了指定工夫,则执行函数。
if (nowTime - preTime >= delay) {
preTime = Date.now();
return fn.apply(context, args);
}
};
}
// 定时器版
function throttle (fun, wait){
let timeout = null
return function(){
let context = this
let args = [...arguments]
if(!timeout){
timeout = setTimeout(() => {
fun.apply(context, args)
timeout = null
}, wait)
}
}
}
iframe 有那些长处和毛病?
iframe 元素会创立蕴含另外一个文档的内联框架(即行内框架)。
长处:
- 用来加载速度较慢的内容(如广告)
- 能够使脚本能够并行下载
- 能够实现跨子域通信
毛病:
- iframe 会阻塞主页面的 onload 事件
- 无奈被一些搜索引擎索辨认
- 会产生很多页面,不容易治理
强类型语言和弱类型语言的区别
- 强类型语言:强类型语言也称为强类型定义语言,是一种总是强制类型定义的语言,要求变量的应用要严格合乎定义,所有变量都必须先定义后应用。Java和C++等语言都是强制类型定义的,也就是说,一旦一个变量被指定了某个数据类型,如果不通过强制转换,那么它就永远是这个数据类型了。例如你有一个整数,如果不显式地进行转换,你不能将其视为一个字符串。
- 弱类型语言:弱类型语言也称为弱类型定义语言,与强类型定义相同。JavaScript语言就属于弱类型语言。简略了解就是一种变量类型能够被疏忽的语言。比方JavaScript是弱类型定义的,在JavaScript中就能够将字符串’12’和整数3进行连贯失去字符串’123’,在相加的时候会进行强制类型转换。
两者比照:强类型语言在速度上可能略逊色于弱类型语言,然而强类型语言带来的严谨性能够无效地帮忙防止许多谬误。
代码输入问题
function fun(n, o) {
console.log(o)
return {
fun: function(m){
return fun(m, n);
}
};
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1); c.fun(2); c.fun(3);
输入后果:
undefined 0 0 0
undefined 0 1 2
undefined 0 1 1
这是一道对于闭包的题目,对于fun办法,调用之后返回的是一个对象。咱们晓得,当调用函数的时候传入的实参比函数申明时指定的形参个数要少,剩下的形参都将设置为undefined值。所以 console.log(o);
会输入undefined。而a就是是fun(0)返回的那个对象。也就是说,函数fun中参数 n 的值是0,而返回的那个对象中,须要一个参数n,而这个对象的作用域中没有n,它就持续沿着作用域向上一级的作用域中寻找n,最初在函数fun中找到了n,n的值是0。理解了这一点,其余运算就很简略了,以此类推。
防抖节流
题目形容:手写防抖节流
实现代码如下:
// 防抖
function debounce(fn, delay = 300) {
//默认300毫秒
let timer;
return function () {
const args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args); // 扭转this指向为调用debounce所指的对象
}, delay);
};
}
window.addEventListener(
"scroll",
debounce(() => {
console.log(111);
}, 1000)
);
// 节流
// 设置一个标记
function throttle(fn, delay) {
let flag = true;
return () => {
if (!flag) return;
flag = false;
timer = setTimeout(() => {
fn();
flag = true;
}, delay);
};
}
window.addEventListener(
"scroll",
throttle(() => {
console.log(111);
}, 1000)
);
IndexedDB有哪些特点?
IndexedDB 具备以下特点:
- 键值对贮存:IndexedDB 外部采纳对象仓库(object store)存放数据。所有类型的数据都能够间接存入,包含 JavaScript 对象。对象仓库中,数据以”键值对”的模式保留,每一个数据记录都有对应的主键,主键是举世无双的,不能有反复,否则会抛出一个谬误。
- 异步:IndexedDB 操作时不会锁死浏览器,用户仍然能够进行其余操作,这与 LocalStorage 造成比照,后者的操作是同步的。异步设计是为了避免大量数据的读写,拖慢网页的体现。
- 反对事务:IndexedDB 反对事务(transaction),这意味着一系列操作步骤之中,只有有一步失败,整个事务就都勾销,数据库回滚到事务产生之前的状态,不存在只改写一部分数据的状况。
- 同源限度: IndexedDB 受到同源限度,每一个数据库对应创立它的域名。网页只能拜访本身域名下的数据库,而不能拜访跨域的数据库。
- 贮存空间大:IndexedDB 的贮存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有下限。
- 反对二进制贮存:IndexedDB 不仅能够贮存字符串,还能够贮存二进制数据(ArrayBuffer 对象和 Blob 对象)。
Promise的根本用法
(1)创立Promise对象
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已胜利)和rejected(已失败)。
Promise构造函数承受一个函数作为参数,该函数的两个参数别离是resolve
和reject
。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作胜利 */){
resolve(value);
} else {
reject(error);
}
});
个别状况下都会应用new Promise()
来创立promise对象,然而也能够应用promise.resolve
和promise.reject
这两个办法:
- Promise.resolve
Promise.resolve(value)
的返回值也是一个promise对象,能够对返回值进行.then调用,代码如下:
Promise.resolve(11).then(function(value){
console.log(value); // 打印出11
});
resolve(11)
代码中,会让promise对象进入确定(resolve
状态),并将参数11
传递给前面的then
所指定的onFulfilled
函数;
创立promise对象能够应用new Promise
的模式创建对象,也能够应用Promise.resolve(value)
的模式创立promise对象;
- Promise.reject
Promise.reject
也是new Promise
的快捷模式,也创立一个promise对象。代码如下:
Promise.reject(new Error(“我错了,请原谅俺!!”));
就是上面的代码new Promise的简略模式:
new Promise(function(resolve,reject){
reject(new Error("我错了!"));
});
上面是应用resolve办法和reject办法:
function testPromise(ready) {
return new Promise(function(resolve,reject){
if(ready) {
resolve("hello world");
}else {
reject("No thanks");
}
});
};
// 办法调用
testPromise(true).then(function(msg){
console.log(msg);
},function(error){
console.log(error);
});
下面的代码的含意是给testPromise
办法传递一个参数,返回一个promise对象,如果为true
的话,那么调用promise对象中的resolve()
办法,并且把其中的参数传递给前面的then
第一个函数内,因而打印出 “hello world
”, 如果为false
的话,会调用promise对象中的reject()
办法,则会进入then
的第二个函数内,会打印No thanks
;
(2)Promise办法
Promise有五个罕用的办法:then()、catch()、all()、race()、finally。上面就来看一下这些办法。
- then()
当Promise执行的内容合乎胜利条件时,调用resolve
函数,失败就调用reject
函数。Promise创立完了,那该如何调用呢?
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then
办法能够承受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved
时调用,第二个回调函数是Promise对象的状态变为rejected
时调用。其中第二个参数能够省略。 then
办法返回的是一个新的Promise实例(不是原来那个Promise实例)。因而能够采纳链式写法,即then
办法前面再调用另一个then办法。
当要写有程序的异步事件时,须要串行时,能够这样写:
let promise = new Promise((resolve,reject)=>{
ajax('first').success(function(res){
resolve(res);
})
})
promise.then(res=>{
return new Promise((resovle,reject)=>{
ajax('second').success(function(res){
resolve(res)
})
})
}).then(res=>{
return new Promise((resovle,reject)=>{
ajax('second').success(function(res){
resolve(res)
})
})
}).then(res=>{
})
那当要写的事件没有程序或者关系时,还如何写呢?能够应用all
办法来解决。
2. catch()
Promise对象除了有then办法,还有一个catch办法,该办法相当于then
办法的第二个参数,指向reject
的回调函数。不过catch
办法还有一个作用,就是在执行resolve
回调函数时,如果呈现谬误,抛出异样,不会进行运行,而是进入catch
办法中。
p.then((data) => {
console.log('resolved',data);
},(err) => {
console.log('rejected',err);
}
);
p.then((data) => {
console.log('resolved',data);
}).catch((err) => {
console.log('rejected',err);
});
3. all()
all
办法能够实现并行任务, 它接管一个数组,数组的每一项都是一个promise
对象。当数组中所有的promise
的状态都达到resolved
的时候,all
办法的状态就会变成resolved
,如果有一个状态变成了rejected
,那么all
办法的状态就会变成rejected
。
javascript
let promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1);
},2000)
});
let promise2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2);
},1000)
});
let promise3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},3000)
});
Promise.all([promise1,promise2,promise3]).then(res=>{
console.log(res);
//后果为:[1,2,3]
})
调用all
办法时的后果胜利的时候是回调函数的参数也是一个数组,这个数组按程序保留着每一个promise对象resolve
执行时的值。
(4)race()
race
办法和all
一样,承受的参数是一个每项都是promise
的数组,然而与all
不同的是,当最先执行完的事件执行完之后,就间接返回该promise
对象的值。如果第一个promise
对象状态变成resolved
,那本身的状态变成了resolved
;反之第一个promise
变成rejected
,那本身状态就会变成rejected
。
let promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject(1);
},2000)
});
let promise2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2);
},1000)
});
let promise3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},3000)
});
Promise.race([promise1,promise2,promise3]).then(res=>{
console.log(res);
//后果:2
},rej=>{
console.log(rej)};
)
那么race
办法有什么理论作用呢?当要做一件事,超过多长时间就不做了,能够用这个办法来解决:
Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})
5. finally()
finally
办法用于指定不论 Promise 对象最初状态如何,都会执行的操作。该办法是 ES2018 引入规范的。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
下面代码中,不论promise
最初的状态,在执行完then
或catch
指定的回调函数当前,都会执行finally
办法指定的回调函数。
上面是一个例子,服务器应用 Promise 解决申请,而后应用finally
办法关掉服务器。
server.listen(port)
.then(function () {
// ...
})
.finally(server.stop);
finally
办法的回调函数不承受任何参数,这意味着没有方法晓得,后面的 Promise 状态到底是fulfilled
还是rejected
。这表明,finally
办法外面的操作,应该是与状态无关的,不依赖于 Promise 的执行后果。finally
实质上是then
办法的特例:
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);
下面代码中,如果不应用finally
办法,同样的语句须要为胜利和失败两种状况各写一次。有了finally
办法,则只须要写一次。
原型
构造函数是一种非凡的办法,次要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)(箭头函数以及Function.prototype.bind()没有)属性,
这个prototype(原型)属性是一个指针,指向一个对象,这个对象的用处是蕴含特定类型的所有实例共享的
属性和办法,即这个原型对象是用来给实例对象共享属性和办法的。每个实例对象的__proto__都指向这个
构造函数/类的prototype属性。
面向对象的三大个性:继承/多态/封装
对于new操作符:
1. new执行的函数, 函数外部默认生成了一个对象
2. 函数外部的this默认指向了这个new生成的对象
3. new执行函数生成的这个对象, 是函数的默认返回值
ES5例子:
function Person(obj) {
this.name = obj.name
this.age= obj.age
}
// 原型办法
Person.prototype.say = function() {
console.log('你好,', this.name )
}
// p为实例化对象,new Person()这个操作称为构造函数的实例化
let p = new Person({name: '番茄', age: '27'})
console.log(p.name, p.age)
p.say()
ES6例子:
class Person{
constructor(obj) {
this.name = obj.name
this.age= obj.age
}
say() {
console.log(this.name)
}
}
let p = new Person({name: 'ES6-番茄', age: '27'})
console.log(p.name, p.age)
p.say()
setInterval 模仿 setTimeout
形容:应用setInterval
模仿实现setTimeout
的性能。
思路:setTimeout
的个性是在指定的工夫内只执行一次,咱们只有在setInterval
外部执行 callback
之后,把定时器关掉即可。
实现:
const mySetTimeout = (fn, time) => {
let timer = null;
timer = setInterval(() => {
// 敞开定时器,保障只执行一次fn,也就达到了setTimeout的成果了
clearInterval(timer);
fn();
}, time);
// 返回用于敞开定时器的办法
return () => clearInterval(timer);
}
// 测试
const cancel = mySetTimeout(() => {
console.log(1);
}, 1000);
// 一秒后打印 1
数组去重
ES5 实现:
function unique(arr) {
var res = arr.filter(function(item, index, array) {
return array.indexOf(item) === index
})
return res
}
ES6 实现:
var unique = arr => [...new Set(arr)]
发表回复