JavaScript题
1.JavaScript中的数据类型?
在JavaScript中,分两种类型:
基本类型主要有以下6种:Number、String、Boolean、Undefined、null、symbol。
引用类型主要有Object、Array、Function。其它的有Date、RegExp、Map等。
2.DOM
文档对象模型(DOM)是HTML和XML文档的编程接口。
日常开发离不开DOM的操作,对节点的增删改查等操作。在以前,使用Jquery,zepto等库来操作DOM,之后在vue,Angular,React等框架出现后,通过操作数据来控制DOM(多数情况下),越来越少的直接去操作DOM。
3.BOM
3.1 BOM是什么?
BOM(Browser Object Model),浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象。其作用就是跟浏览器做一些交互效果,比如:进行页面的后退、前进、刷新、浏览器窗口发生变化,滚动条滚动等。
3.2 window
Bom的核心对象是window,它表示浏览器的一个实例。
在浏览器中,window即是浏览器窗口的一个接口,又是全局对象。
4 == 和 === 区别,分别在什么情况使用

等于操作符用俩个等于号(==)表示,如果操作数相等,则会返回true。
等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等。
全等操作符由3个等于号(===)表示,只有俩个操作数在不转换的前提下相等才返回true,即类型相同,值也相同。
区别:等于操作符(==)会做类型转换再进行值的比较,全等操作符不会做类型转换。
null 和undefined 比较,相等操作符为true 全等为false。
5 typeof 和 instanceof 的区别
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
instanceof 运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。
区别:
-
typeof 会返回一个变量的基本类型,instanceof 返回的是一个Boolean.
-
instanceof 可以准确的判断复杂引用数据类型,但是不能正确判断基础数据类型。
- 如果需要通用检测数据类型,可以通过
Object.prototype.toString,调用该方法,统一返回格式
[object XXX]的字符串。
6 JavaScript 原型,原型链?有什么特点?
原型
JavaScript常被描述为一种基于原型的语言---每个对象拥有一个原型对象。访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或达到原型链的末尾。
原型链
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链,它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
在对象实例和它的构造器之间建立一个链接(它是_proto_属性,是从构造函数的prototype属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。
- 一切对象都是继承自
Object对象,object对象直接继承根源对象null
- 一切的函数对象(包括
object对象),都是继承自Function对象
-
Object 对象直接继承自 Function 对象
-
Function 对象的 _proto_ 会指向自己的原型对象,最终还是继承自 Object 对象
7.对作用域链的理解
作用域,即变量和函数生效的区域或集合,作用域决定了代码区块中变量和其他资源的可见性。
- 全局作用域:任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在任意位置访问。
- 函数作用域:函数作用域也叫局部作用域,如果一个变量是在函数内部声明的,它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。
- 块级作用域:ES6引入了
let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号外面不能访问这些变量。
作用域链
当在JavaScript中使用一个变量的时候,首先JavaScript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域。
8. 谈谈对this对象的理解
8.1定义
函数的this关键字在JavaScript中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。在绝大数情况下,函数的调用方式决定了this的值。
this关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象。
8.2 new绑定
通过构造函数new 关键字生成一个实例对象,此时this指向这个实例对象。
apply()、call()、bind()、是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的就是这个第一个参数。
8.3 箭头函数
在ES6的语法中,提供了箭头函数法,让我们在代码书写时就能确定this的指向。
9.new操作符具体干了什么
- 创建一个新的对象
- 将对象与构建函数通过原型链链接起来
- 将构建函数中的
this绑定到新建的对象上
- 根据构建函数返回类型做判断,如果原始值则被忽略,如果是返回对象,需要正常处理。
10.bind、call、apply区别?
bind、call、apply、作用是改变函数执行时的上下文,改变函数运行时的this指向。
区别:
- 三者都可以改变函数的
this指向
- 三者第一个参数都是this要指向的对象,如果没有这个参数或者参数为
undefined或null,则默认指向全局window
- 三者都可以传参,但是
apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分多次传入
-
bind是返回绑定this之后的函数,apply、call则是立即执行
11.闭包的理解?闭包使用场景?
11.1 闭包是什么?
一个函数和对其周围状态的引用捆绑在一起,这样的组合就是闭包。闭包让你可以在一个内层函数中访问到其外层函数的作用域。
11.2 闭包使用场景
11.3 柯里化函数
柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用。
11.4 闭包的缺点
如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能有负面影响。
12.深拷贝浅拷贝的区别?实现一个深拷贝?
12.1 浅拷贝
Object.assign、Array.prototype.slice()、Array.prototype.concat()、拓展运算符实现复制。
var obj = {
name: 'xxx',
age: 17
}
var newObj = Object.assign({}, obj);
const a = [1,2,3];
const b = a.slice(0);
b[1] = 4;
console.log(a, b);// [1,2,3] [1,4,3]
const a = [1,2,3];
const b = [...a];
b[1] = 4;
console.log(a, b);// [1,2,3] [1,4,3]
12.2 深拷贝
常见深拷贝方式:
- _.cloneDeep()
- jQuery.extend()
- JSON.stringify()
- 手写循环递归
const _ = require('lodash');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f); // false
JSON.stringify()
// 有缺点 会忽略undefined、symbol、函数
const obj2=JSON.parse(JSON.stringify(obj1));
循环递归
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; //null或者undefined就不拷贝
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话不拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
12.3 区别
浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享一块内存,修改对象属性会影响原对象。
深拷贝会另外创建一个一模一样的对象,不共享内存,不影响原对象。
13. JavaScript字符串的常用方法
let stringValue = "hello world";
console.log(stringValue.slice(3, 7)); // "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7)); // "lo worl"
// 删除前、后或者前后所有空格符,再返回新的字符串
let stringValue = " hello world ";
let trimmedStringValue = stringValue.trim();
console.log(stringValue); // " hello world "
console.log(trimmedStringValue); // "hello world"
// 接收一个整数参数,将字符串复制多少次,返回拼接所有副本后的结果
let stringValue = "na ";
let copyResult = stringValue.repeat(2) // na na
- toUpperCase()、toLowerCase() 大小写转化
- indexOf() 从字符串开头去搜索传入的字符串,并返回位置(没找到返回-1)
- includes() 字符串是否包含传入的字符串
- split() 把字符串按照指定分隔符,拆分成数组
- replace() 接收俩个参数,第一个参数为匹配的内容,第二个参数为替换的元素
14.数组常用方法
增
- push() 添加到数组末尾
- unshift() 在数组开头添加
- splice() 传入3个参数,开始位置、0(要删除的元素数量)、插入的元素
- concat() 合并数组,返回一个新数组
删
- pop() 删除数组最后一项,返回被删除的项。
- shift() 删除数组的第一项,返回被删除的项。
- splice()传入两个参数,开始位置,删除元素的数量,返回包含删除元素的数组。
- slice() 用于创建一个包含原有数组中一个或多个元素的新数组,不会影响原始数组。
查
- indexOf() 返回要查找元素在数组中的位置,如果没找到则返回 -1.
- includes() 返回查找元素是否在数组中,有返回true,否则false.
- find() 返回第一个匹配的元素。
排序方法
- reverse() 将数组元素方向反转
- sort() 接受一个比较函数,用于判断那个值在前面
-
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
let values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values); // 0,1,5,10,15
转换方法
join() 方法接收一个参数,即字符串分隔符,返回包含所有项的字符串。
循环方法
some() 和 every() 方法一样
对数组每一项都运行传入的测试函数,如果至少有一个元素返回true,则这个方法返回true.
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let someResult = numbers.some((item, index, array) => item > 2);
console.log(someResult) // true
forEach()
对数组每一项都运行传入的函数,没有返回值
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
numbers.forEach((item, index, array) => {
//执行操作
});
filter()
函数返回true 的项会组成数组之后返回。
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let filterResult = numbers.filter((item, index, array) => item > 2);
console.log(filterResult); // 3,4,5,4,3
map()
返回由每次函数调用的结果构成的数组。
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let mapResult = numbers.map((item, index, array) => item * 2);
console.log(mapResult) // 2,4,6,8,10,8,6,4,2
15.事件循环的理解?
事件循环
JavaScript是一门单线程的语言,实现单线程非阻塞的方法就是事件循环。
在JavaScript中,所有的任务都可以分为:
- 同步任务:立即执行的任务,同步任务一般会直接进入到主线程执行。
- 异步任务:异步的比如
ajax网络请求,setTimeout定时函数等。

同步任务进入主线程,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程不断重复就是事件循环。
宏任务与微任务
console.log(1)
setTimeout(()=>{
console.log(2)
}, 0)
new Promise((resolve, reject)=>{
console.log('new Promise')
resolve()
}).then(()=>{
console.log('then')
})
console.log(3)
- 遇到 console.log(1),直接打印1
- 遇到定时器,属于新的宏任务,留着后面执行
- 遇到 new Promise,这个是直接执行的,打印'newPromise
- .then 属于微任务,放入微任务队列,后面再执行
- 遇到 console.log(3)直接打印 3
- 好了本轮宏任务执行完毕,现在去微任务列表查看是否有微任务,发现.then 的回调,执行它打印'then'
- 当一次宏任务执行完,再去执行新的宏任务,这里就剩一个定时器的宏任务了,执行它,打印 2
结果是:1=>'new Promise'=> 3 => 'then' => 2
异步任务执行顺序,事件队列其实是一个“先进先出”的数据结构,排在前面的事件会优先被主线程读取。
微任务
常见的微任务有:
- Promise.then
- MutaionObserver
- process.nextTice(node.js)
宏任务
宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合.
常见的宏任务有:
- script(可以理解为外层同步代码)
- setTimeout/setInterval
- Ul rendering/Ul事件
- postMessage、MessageChannel
- setlmmediate、1/0(Node.is)
这时候,事件循环,宏任务,微任务的关系如图所示

它的执行机制是:
- 执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
- 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
async 与 await
async就是用来声明一个异步方法,await是用来等待异步方法执行。
async函数返回一个promise对象,下面代码是等效的:
function f() {
return Promise.resolve('TEST');
}
async function asyncF() {
return 'TEST';
}
正常情况下, await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
async function f() {
// 等同于 return 123
return await 123
}
f().then(i => console.log(i)) // 123
不管 await 后面跟着的是什么,await 都会阻塞后面的代码。
async function fn1 (){
console.log(1)
await fn2()
console.log(2) // 阻塞
}
async function fn2 (){
console.log('fn2')
}
fn1()
console.log(3)
await 会阻塞下面的代码(即加入微任务队列),上面的例子中,先执行 async 外面的同步代码同步代码执行完,再回到 async函数中,再执行之前阻塞的代码
输出:1,fn2,3,2
async function async1() {
console.log('1')
await async2()
console.log('2')
}
async function async2() {
console.log('3')
}
console.log('4')
setTimeout(function () {
console.log('settimeout')
})
async1()
new Promise(function (resolve) {
console.log('5')
resolve()
}).then(function () {
console.log('6')
})
console.log('7');
// 输出结果: 4 1 3 5 7 2 6 settimeout
分析过程:
- 1.执行整段代码,遇到
console.log('4')直接打印结果,输出 4;
- 2.遇到定时器了,它是宏任务,先放着不执行;
- 3.遇到
async1(),执行 async1 函数,先打印 1 ,下面遇到 await 怎么办?先执行 async2,打印 3,然后阻塞下面代码(即加入微任务列表),跳出去执行同步代码
- 4.跳到
new Promise 这里,直接执行,打印 5,下面遇到 .then(),它是微任务,放到微任务列表等待执行;
- 5.最后一行直接打印
7 ,现在同步代码执行完了,开始执行微任务,即 await 下面的代码,打印 2;
- 6.继续执行下一个微任务,即执行
then 的回调,6;
- 7.上一个宏任务所有事都做完了,开始下一个宏任务,就是定时器,打印
settimeout所以最后的结果是: 4 1 3 5 7 2 6 settimeout。
16.JavaScript本地存储方式有哪些?区别及应用场景?
16.1 方式
javaScript 本地缓存的方法主要讲述以下四种:
- cookie
- sessionStorage
- localStorage
- indexedDB
16.1.1.cookie
Cookie ,类型为「小型文本文件」,指某些网站为了辨别用户身份而储存在用户本地终端上的数据。是为了解决 HTTP 无状态导致的问题。
作为一段一般不超过 4KB 的小型文本数据,它由一个名称(Name)、一个值(Value)和其它几个用于控制 cookie 有效期、安全性、使用范围的可选属性组成。
但是 cookie 在每次请求中都会被发送,如果不使用 HTTPS 并对其加密,其保存的信息很容易被窃取,导致安全风险。
16.1.2 localStorage
- 生命周期:持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
- 存储的信息在同一域中是共享的。
- 当本页操作(新增、修改、删除)了 localStorage 的时候,本页面不会触发 storage 事件,但是别的页面会触发 storage 事件。
- 大小:5M(跟浏览器厂商有关系)。
-
localstorage 本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡。
- 受同源策略的限制。
localStorage.setItem('username','你的名字');
localStorage.getItem('username');
localStorage.key(0) // 获取第一个键名
localStorage.removeItem('username');
localStorage.clear(); // 清空localStorage
16.1.3 sessionStorage
sessionStorage 和 localstorage 使用方法基本一致,唯一不同的是生命周期,一旦页面(会话)关闭,sessionStorage 将会删除数据。
16.1.4 indexedDB
indexedDB 是一种低级AP,用于客户端存储大量结构化数据(包括,文件/blobs)。该API使用索引来
实现对该数据的高性能搜索。
虽然 Web Storage 对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。
优点:
- 储存量理论上没有上限
- 所有操作都是异步的,相比LocalStorage 同步操作性能更高,尤其是数据量较大时
- 原生支持储存 JS 的对象
- 是个正经的数据库,意味着数据库能干的事它都能干
缺点:
区别
- 存储大小:
cookie 数据大小不能超过 4k,sessionStorage 和 localStorage 虽然也有存储大小的限制,但比cookie 大得多,可以达到5M或更大。
- 有效时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage 数据在当前浏览器窗口关闭后自动删除; cookie 设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭。
- 数据与服务器之间的交互方式,
cookie 的数据会自动的传递到服务器,服务器端也可以写 cookie 到客户端;sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存
17.Ajax 原理是什么?如何实现?
Ajax 的原理简单来说通过 XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后用 JavaScript 来操作 DOM 而更新页面。
简单封装一个ajax请求:
function ajax(options) {
//创建XMLHttpRequest对象
const xhr = new XMLHttpRequest();
//初始化参数的内容
options = options || {};
options.type = (options.type || 'GET').toUpperCase();
options.dataType = options.dataType 'json';
const params = options.data;
// 发送请求
if (options.type === 'GET') {
xhr.open('GET', options.url + '?' + params, true) xhr.send(null)
} else if (options.type === 'POST') {
xhr.open('POST', options.url, true) xhr.send(params)
// 接收请求
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
let status = xhr.status;
if (status >= 200 && status < 300) {
options.success && options.success(xhr.responseText, xhr.responseXML)
} else {
options.fail && options.fail(status)
}
}
}
}
}
// 调用
ajax({
type: 'post',
dataType: 'json',
data: {},
url: 'https://xxxx',
success: function(valse, xml){
console.log(valse)
},
fail: function(status){
console.log(status)
}
})
18. 防抖和节流?区别?如何实现?
- 节流: n秒内只运行一次,若在n秒内重复触发,只有一次生效。
- 防抖: n 秒后在执行该事件,若在n秒内被重复触发,则重新计时
应用场景:
防抖在连续的事件,只需触发一次回调的场景有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小 resize 。只需窗口调整完成后,计算窗口大小。防止重复渲染。
节流在间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
节流
function throttled(fn, delay) {
let timer = null;
let starttime = Date.now();
return function () {
let curTime = Date.now(); // 当前时间
let remaining = delay - (curTime - starttime); // 从上一次到现在,还剩下多少多余事件
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timer);
if (remaining <= 0) {
fn.apply(context, args);
starttime = Date.now();
} else {
timer = setTimeout(fn, remaining);
}
}
}
防抖
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
如果需要立即执行防抖,可加入第三个参数
function debounce(func, wait, immediate) {
let timeout;
return function() {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
if (timeout) clearTimeout(timeout); // timeout 不为 null
if (immediate) {
let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会触发
timeout = setTimeout(function() {
timeout = null;
},
wait);
if (callNow) {
func.apply(context, args)
}
} else {
timeout = setTimeout(function() {
func.apply(context, args)
},
wait);
}
}
}
区别
相同点
- 都可以通过使用 setTimeout 实现
- 目的都是,降低回调执行频率。节省计算资源
不同点
- 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout和 setTimeout 实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能。
- 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数,节流,每隔500ms 就执行一次。防抖,则不管调动多少次方法,在2s后,只会执行一次。
19. web常见的攻击方式有哪些?如何防御?
常见的有:
- XSS 跨站脚本攻击
- CSRF 跨站请求伪造
- SQL 注入攻击
防止csrf常用方案如下:
- 阻止不明外域的访问,
同源检测,Samesite Coolkie。
- 提交时要求附加本域才能获取信息
CSRF Token, 双重Cookie验证。
预防SQL如下:
- 严格检查输入变量的类型和格式
- 过滤和转义特殊字符
- 对访问数据库的web应用程序采用web应用防火墙
20.JavaScript内存泄露的几种情况?
内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存。
Javascript 具有自动垃圾回收机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。
常见的内存泄露情况:
- 意外的全局变量。
a='我是未声明的变量'.
- 定时器
21. JavaScript数字精度丢失的问题?如何解决?
0.1 + 0.2 === 0.3; // false
可以使用parseFloat解决
CSS题型整理
1.盒模型
盒模型:由4个部分组成,content,padding,border,margin.
2.BFC的理解
BFC:即块级格式化上下文。
常见页面情况有:
2.1清除内部浮动
元素添加overflow: hidden;
3.元素水平垂直居中的方法有哪些?
实现方式如下:
- 利用定位+margin:auto
- 利用定位+margin: 负值
- 利用定位+transform
- flex布局等
4.实现两栏布局,右侧自适应?三栏布局中间自适应?
两栏布局的话:
- 使用float左浮动布局
- 右边模块使用margin-left 撑出内容块做内容展示
- 为父级元素添加BFC,防止下方元素跟上方内容重叠。
flex布局:
三栏布局:
- 两边用float,中间用margin
- 两边用absolute,中间用margin
- display: table
- flex
- grid网格布局
5.css中,有哪些方式隐藏页面元素?
例如:
-
display: none; 最常用,页面彻底消失,会导致浏览器重排和重绘
-
visibility: hidden; dom存在,不会重排,但是会重绘
-
opacity: 0; 元素透明 元素不可见,可以响应点击事件
-
position: absolute; 将元素移出可视区域,不影响页面布局
6.如何实现单行/多行文本溢出的省略样式
单行:
<style>
p {
overflow: hidden;
line-height: 40px;
width:400px;
height:40px;
border:1px solid red;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
<p>文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本</p>
多行
<style>
.demo {
position: relative;
line-height: 20px;
height: 40px;
overflow: hidden;
}
.demo::after {
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding: 0 20px 0 10px;
}
</style>
<body>
<div class="demo">文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本</div>
</body>
css实现
<style>
p {
width: 400px;
border-radius: 1px solid red;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
</styl
7.CSS3新增了哪些新特性?
选择器:
nth-child(n)
nth-last-child(n)
last-child
新样式:
-
border-radius; 创建圆角边框
-
box-shadow; 为元素添加阴影
-
border-image; 图片绘制边框
-
background-clip; 确定背景画区
-
background-size; 调整背景图大小
文字:
-
word-wrap: normal|break-word; 使用浏览器默认的换行 | 允许在单词内换行;
-
text-overflow; clip | ellipsis; 修剪文本 | 显示省略符号来代表被修剪的文本;
-
text-decoration; text-fill-color| text-stroke-color | text-stroke-width;
transition 过渡、transform 转换、animatin动画、渐变、等
8.CSS提高性能的方法有哪些?
如下:
- 内联首屏关键
css
- 异步加载
css
- 资源压缩(
webpack/gulp/grunt)压缩代码
- 合理的使用选择器
- 不要使用
@import
-
icon图片合成等
ES6
1.var,let, const的区别?
-
var 声明的变量会提升为全局变量,多次生成,会覆盖。
-
let let声明的变量只在代码块内有效。
-
const 声明一个只读常量,常量的值不能改变。
区别:
- 变量提升,
var会提升变量到全局。let, const直接报错
- 暂时性死区
- 块级作用域
- 重复声明
- 修改声明的变量
2.ES6中数组新增了哪些扩展?
- 扩展运算符
...
- 构造函数新增的方法
Array.from(),Array.of()
- 数组实例新增方法有:copyWithin(),find(),findIndex(),fill(),includes(),keys(),values()等
3.对象新增了哪些扩展
对象名跟对应值名相等的时候,可以简写。
const a = {foo: foo} == const a = {foo}
属性的遍历:
- for...in:循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
- Object.keys(obj):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)的键名
- Object.getOwnPropertyNames(obj):回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)的键名
- Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有Symbol属性的键名----- Reflect.ownKeys(obj):返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是Symbol或字符串,也不管是否可枚举.
对象新增的方法
- Object.is();
- Object.assign();
- Object.getOwnPropertyDescriptors() ;
- Object.keys(), Object.values(),Object.entries();
- Object.fromEntries();
4.理解ES6中Promise的?
优点:
promise对象仅有三种状态,pending(进行中),fulfilled(已成功),rejected(已失败)。一旦状态改变(从 pending变为 fulfilled和从 pending变为 rejected),就不会再变,任何时候都可以得到这个结果。
使用方法
const promise = new Promise(function(resolve, reject) {});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和 reject
-
resolve函数的作用是,将Promise对象的状态从"未完成"变为"成功"
-
reject函数的作用是,将Promise对象的状态从"未完成"变为"失败"
实例方法:
-
then() 是实例状态发生改变时的回调函数。
-
catch() 指定发生错误时的回调函数。
-
finally() 不管Prosime对象最后状态如何,都会执行。
构造函数方法
Promise构造函数存在以下方法:
- all() 将多个
Promise实例包装成一个新的Promise实例。
- race() 将多个
Promise实例包装成一个新的Promise实例。
- allSettled() 接受一组Promise实例作为参数,只有等所有这些参数返回结果,实例才会结束。
- resolve() 将现有对象转为Promise对象。
- reject() 返回一个新的Promise实例,状态为rejected。
Vue2面试题
1.生命周期?
beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed。
1.4 数据请求在created和mouted的区别
created 是在组件实例一旦创建完成的时候立刻调用,这时候页面 dom 节点并未生成; mounted是在页面dom节点渲染完毕之后就立刻执行的。触发时机上created是比mounted要更早的,
两者的相同点:都能拿到实例对象的属性和方法。讨论这个问题本质就是触发的时机,放在mounted中的请求有可能导致页面闪动(因为此时页面dom结构已经生成),但如果在页面加载前完成请求,则不会出现此情况。建议对页面内容的改动放在 created 生命周期当中。
2.双向数据绑定是什么?
释义:当js代码更新Model时,view也会自动更新,用户更新view,Model的数据也会自动被更新,就是双向绑定。
3.Vue组件之间的通信方式有哪些?
- 1.通过props传递 (父给子组件传递)
- 2.通过$emit触发自定义事件 (子传父)
- 3.使用ref (父组件使用子组件的时候)
-
- EventBus (兄弟组件传值)
-
- attrs 与 listeners (祖先传递给子孙)
-
- Provide 与 Inject (在祖先组件定义provide)返回传递的值,在后代组件通过inject 接收组件传递过来的值。
-
- Vuex (复杂关系组件数据传递,存放共享变量)
4.v-if和v-for的优先级是什么?
v-for的优先级比v-if的高
注意
不能把v-if 和 v-for 同时在同一个元素上,带来性能方面的浪费。必须使用的话可以在外层套一个template
5. 未完待续。。。