前端面试题2
文章目录
- 1.DOM 和 BOM 的区别
- 2.什么是闭包
- 3.JavaScript 的数据类型
- 4.null,undefined 的区别
- 5.JavaScript 中什么情况下会返回 undefined 值
- 6.原型链
- 7.常见的 js 中的继承方法有哪些
- 8.什么是跨域, 如何解决跨域问题
- 解决方式
- 9.jsonp 的原理
- 10.Vue 怎么实现跨域
- 11.ES5 和 ES6 的区别,说几个 ES6 的新增方法
- 12.ES6 的继承和 ES5 的继承有什么区别?
- 13.var、let、const 之间的区别?
- 14.class、extends 是什么,有什么作用?
- 15.Vue 的优势是什么?
- 16.mvvm 和 mvc 区别是什么?
- 17.Vue双向绑定原理?
- 18.Object.defineProperty和Proxy的优缺点?
- 19.Vue 常用的指令都有哪些?
- 20.你对盒子模型的理解是什么样的?
- 21.谈谈你对 flex 的理解?
- 22.在 CSS 中有哪些定位方式?
- 23.几种前端存储的区别是什么?
- 24.HTTP状态码有哪些?
- 25.URL 的各个部分,分别是什么意思?
- 26.什么是 window 对象?什么是 document 对象?
- 27.HTTP 缓存机制?
- 28.箭头函数和普通函数的区别?
- 29.箭头函数中的this指向什么?
- 30.对this的理解?
- 31.谈谈你对原型链的理解?
- 32.谈谈对于继承的理解?
- 33.new 实例对象过程?
- 34.如何判断是否是数组?
- 35.Vue双向绑定原理?
- 36.Object.defineProperty和Proxy的优缺点?
- 37.Vue组件之间如何进行通信?
跳转上篇文章:前端面试题总结1https://blog.csdn.net/m0_62181310/article/details/125726651?spm=1001.2014.3001.5502
1.DOM 和 BOM 的区别
1、BOM
BOM 是 Browser Object Model 的缩写,即浏览器对象模型。
BOM 没有相关标准。
BOM 的最根本对象是window
2、DOM
DOM 是 Document Object Model 的缩写,即文档对象模型。
DOM 是 W3C 的标准。 DOM 最根本对象是
document(实际上是 window.document)
DOM 是 W3C * 万维网联盟 * 的标准
DOM 定义了访问 HTML 和 XML 文档的标准
什么是 W3C
- “W3C 文档对象模型(DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。”
- W3C DOM 标准被分为 3 个不同的部分
- 核心 DOM - 针对任何结构化文档的标准模型
- XML DOM - 针对 XML 文档的标准模型
- HTML DOM - 针对 HTML 文档的标准模型
- DOM 是 Document Object Model(文档对象模型)的缩写
2.什么是闭包
1、定义:
一个作用域可以访问另外一个函数内部的局部变量 ,或者说一个函数(子函数)访问另一 个函数(父函数)中的变量。
此时就会有闭包产生 ,那么这个变量所在的函数我们就称之为 闭包 函数。
function aaa() {
var a = 0;
return function () {
alert(a++);
};
}
var fun = aaa();
fun(); // 1
2、优缺点:
闭包的主要作用: 延伸了变量的作用范围, 因为闭包函数中的局部变量不会等着闭包函数 执行完就销毁, 因为还有别的函数要调用它 , 只有等着所有的函数都调用完了他才会销毁 闭包会造成内存泄漏,
如何解决:用完之后手动释放
3、详解:
闭包不仅仅可以实现函数内部的作用域访问这个函数中的局部变量, 还可以实现全局作用域或者是别的地方的作用域也可以访问到函数内部的局部变量 , 实现方法就是 return 了一个函数
所以 return 函数也是我们实现闭包的一个主要原理, 因为返回的这个函数本身就是我们 fn 函数内部的一个子函数 ,所以子函数是可以访问父函数里面的局部变量的, 所以返回完毕 之后 ,外面的函数一调用, 就会回头调用返回的这个函数, 所以就可以拿到这个子函数对 应的父函数里面的局部变量
4、注意:
1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包, 否则会造成网页的性能问题,在 IE 中可能导致内存泄露。解决方法是,在退出函数之前, 将不使用的局部变量全部删除。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象 (object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私 有 属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
3.JavaScript 的数据类型
1、数据类型
基本数据类型:Number、String、Boolean、null、undefined
引用数据类型:Function、Object、Array、data
2、null 和 undefined 的区别
undefined:表示变量声明但未初始化时的值
null:表示准备用来保存对象,还没有真正保存对象的值。
从逻辑角度看,null 值表示一 个空对象指针
- ECMA 标准要求 null 和 undefined 等值判断返回 true
null == undefined // true
null === undefined // false
4.null,undefined 的区别
1、区别:
null 表示一个对象被定义了,值为“空值”
undefined 表示不存在这个值
typeof undefined //“undefined”
undefined : 是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但还没有定义。当尝试读取时会返回 undefined
例如变量被声明了,但没有赋值时,就等于 undefined
typeof null //“object”
null : 是一个对象(空对象, 没有任何属性和方法)
例如作为函数的参数,表示该函数的参数不是对象
注意: 在验证 null 时,一定要使用=== ,因为 == 无法分别 null 和 undefined
undefined 表示"缺少值",就是此处应该有一个值,但是还没有定义
2、用法是:
- 变量被声明了,但没有赋值时,就等于 undefined
- 调用函数时,应该提供的参数没有提供,该参数等于 undefined
- 对象没有赋值的属性,该属性的值为 undefined
- 函数没有返回值时,默认返回 undefined null 表示"没有对象",即该处不应该有值。典型用法是:
- 作为函数的参数,表示该函数的参数不是对象
- 作为对象原型链的终点
5.JavaScript 中什么情况下会返回 undefined 值
1、访问声明,但是没有初始化的变量
var aaa;
console.log(aaa); // undefined
2、访问不存在的属性
var aaa = {};
console.log(aaa.c);
3、访问函数的参数没有被显式的传递值
(function (b){
console.log(b); // undefined
})();
4、访问任何被设置为 undefined 值的变量
var aaa = undefined;console.log(aaa); // undefined
5、没有定义 return 的函数隐式返回
function aaa(){}console.log(aaa()); // undefined
6、函数 return 没有显式的返回任何内容
function aaa(){
return;
}
console.log(aaa()); // undefined
6.原型链
JavaScript 原型:每个对象都会在其内部初始化一个属性,就是prototype(原型)
1、原型链:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去 它的__proto__隐式原型上查找,即它的构造函数的 prototype,如果还没有找到就会再在构造函数的 prototype 的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,称为原型链
2、特点:
JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型 副本。当我们修改原型时,与之相关的对象也会继承这一改变
7.常见的 js 中的继承方法有哪些
ES5 继承有以下六种方法:
- 原型链继承 JavaScript 实现继承的基本思想:通过原型将一个引用类型继承另一个引用类型 的属性和方法
- 借用构造函数继承(伪造对象或经典继承) JavaScript 实现继承的基本思想:在子类构造 函 数内部调用超类型构造函数。 通过使用 apply()和 call()方法可以在新创建的子类对象上执行构造 函数
- 组合继承(原型+借用构造)(伪经典继承) JavaScript 实现继承的基本思想:将原型链和 借用 构造函数的技术组合在一块,从而发挥两者之长的一种继承模式,将原型链和借用构造函数的技 术组合到一起,从而取长补短发挥两者长处的一种继承模式
- 型式继承 JavaScript 实现继承的基本思想:借助原型可以基于已有的对象创建新对象, 同 时还不必须因此创建自定义的类型
- 寄生式继承 JavaScript 实现继承的基本思想:创建一个仅用于封装继承过程的函数,该函数 在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。 寄生式继承是原型式继承的加强版
- 寄生组合式继承 JavaScript 实现继承的基本思想:通过借用函数来继承属性,通过原型链 的混成形式来继承方法
ES5 继承有以下六种方法:
1、使用 class 构造一个父类
class Parent {
constructor(name,age){
this.name = name
this.age = age
}sayName(){
console.log(this.name);
}
}
2、使用 class 构造一个子类,并使用 extends 实现继承,super 指向父类的原型对象
class Child extends Parent{
constructor(name,age,gender){
super(name,age)
this.gender = gender
}sayGender(){
console.log(this.gender);
}
}
3、实例化对象
const ming = new Child('ming',18,'男')
ming.sayGender()
ming.sayName()
console.log(ming.name);
console.log(ming.age);
8.什么是跨域, 如何解决跨域问题
跨域: 指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制,防止他人恶意攻击网站
解决方式
1、jsonp
原理:
动态创建一个 script 标签。利用 script 标签的 src 属性不受同源策略限制。
因为所有 的 src 属性和 href 属性都不受同源策略限制。
可以请求第三方服务器数据内容
步骤:
- 去创建一个 script 标签
- script 的 src 属性设置接口地址
- 接口参数,必须要带一个自定义函数名 要不然后台无法返回数据。
- 通过定义函数名去接收后台返回数据
//去创建一个 script 标签
var script = document.createElement("script");
//script 的 src 属性设置接口地址 并带一个 callback 回调函数名称
script.src = "HTTP://127.0.0.1:8888/index.php?callback=jsonpCallback";
//插入到页面
document.head.appendChild(script);
//通过定义函数名去接收后台返回数据
function jsonpCallback(data){
//注意 jsonp 返回的数据是 json 对象可以直接使用
//Ajax 取得数据是 json 字符串需要转换成 json 对象才可以使用。
}
2、CORS:跨域资源共享
原理:
服务器设置 Access-Control-Allow-OriginHTTP 响应头之后,浏览器将会允许跨域请求
限制:
浏览器需要支持 HTML5,可以支持 POST,PUT 等方法兼容 ie9 以上
需要后台设置
Access-Control-Allow-Origin: * //允许所有域名访问,或者
Access-Control-Allow-Origin: HTTP://a.com //只允许所有域名访问
3、反向代理
4、window+iframe
9.jsonp 的原理
1、什么是 jsonp,jsonp 的作用:
jsonp 并不是一种数据格式,而 json 是一种数据格式,jsonp 是用来解决跨域获取数据的一种 解决方案
2、具体原理:
是通过动态创建 script 标签,然后通过标签的 src 属性获取 js 文件中的 js 脚本,该脚本的内容是一个函数调用,参数就是服务器返回的数据,为了处理这些返回的数据,需要事先在页面定义好回调函数,本质上使用的并不是 Ajax 技术,Ajax 请求受同源策略的影响,不允许进行跨域请求,而 script 标签的 src 属性中的链接却可以访问跨域的 js 脚本,利用这个特性,服务端不在返回 json 格式的数据,而是返回调用某个函数的 js 代码,在 src 中进行了调用,这样就实现了跨域
10.Vue 怎么实现跨域
1、什么是跨域:
跨域指浏览器不允许当前页面的所在的源去请求另一个源的数据。
源指 协议,端口,域名。
只要这个 3 个中有一个不同就是跨域
2、使用 Vue-cli 脚手架搭建项目时 proxyTable 解决跨域问题:
打开 config/index.js,在 proxyTable 中添写如下代码:
proxyTable: {
'/api': { //使用"/api"来代替"http://f.apiplus.c"
target: 'http://f.apiplus.cn', //源地址
changeOrigin: true, //改变源
pathRewrite: {
'^/api': 'http://f.apiplus.cn' //路径重写
}
3、使用 CORS( 跨域资源共享 ):
1、前端设置:
前端Vue设置axios允许跨域携 带 cookie(默认是不带 cookie )
axios.defaults.withCredentials = true;
2、后端设置:
- 跨域请求后的响应头中需要设置:
- Access-Control-Allow-Origin 为发起请求的主机地址。
- Access-Control-Allow-Credentials,当它被设置为 true 时,允许跨域带 cookie,但此时 Access-Control- Allow-Origin 不能为通配符*。
- Access-Control-Allow-Headers,设置跨域请求允许的请求头。
- Access-Control-Allow-Methods,设置跨域请求允许的请求方式。
11.ES5 和 ES6 的区别,说几个 ES6 的新增方法
1、ES5 和 ES6 的区别
ECMAScript5,即 ES5,是 ECMAScript 的第五次修订,于 2009 年完成标准化
ECMAScript6,即 ES6,是 ECMAScript 的第六次修订,于 2015 年完成,也称 ES2015
ES6 是继 ES5 之后的一次改进,相对于 ES5 更加简洁,提高了开发效率
2、ES6 的新增方法
1、新增声明命令 let 和 const
在 ES6 中通常用 let 和 const 来声明,let 表示变量、const 表示常量
- 特点
- let 和 const 都是块级作用域。
以{}代码块作为作用域范围 只能在代码块里面使用不存在变量提升,只能先声明再使用,否则会报错。
语法上,称为“暂时性死区” 在同一个代码块内,不允许重复声明- const 声明的是一个只读常量,在声明时就需要赋值。
如果 const 的是一个对象,对象所包含的值是可以被修改的。
抽象一点儿说,就是对象所指向的地址不能改变,而 变量成员是可以修改的。
3、模板字符串(Template String)
用一对反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,也可以 在字符串中嵌入变量,js 表达式或函数,变量、js 表达式或函数需要写在${ }中。
4、函数的扩展
- 函数的默认参数 ES6 为参数提供了默认值。在定义函数时便初始化了这个参数,以便在参数没有被传 递 进去时使用。
- 箭头函数
在 ES6 中,提供了一种简洁的函数写法,我们称作“箭头函数”
- 写法
函数名=(形参)=>{……} 当函数体中只有一个表达式时,{}和 return 可以省略 当函数体中形参只有一个时,()可以省略。- 特点
箭头函数中的 this 始终指向箭头函数定义时的离 this 最近的一个函数,如果没有最近 的函数就指向 window。
5、对象的扩展
- 属性的简写
ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。var foo = 'bar'; var baz = {foo}; //等同于 var baz = {foo: foo}; 方法的简写。省略冒号与 function 关键字。 var o = { method() { return "Hello!"; } }; // 等同于 var o = { method: function() { return "Hello!"; } };
- Object.keys()方法
获取对象的所有属性名或方法名(不包括原形的内容),返回一个数组。var obj={name: "john", age: "21", getName: function () { alert(this.name)}}; console.log(Object.keys(obj)); // ["name", "age", "getName"] console.log(Object.keys(obj).length); //3 console.log(Object.keys(["aa", "bb", "cc"])); //["0", "1", "2"] console.log(Object.keys("abcdef")); //["0", "1", "2", "3", "4", "5"]
- Object.assign ()
assign 方法将多个原对象的属性和方法都合并到了目标对象上面。可以接收多个参数, 第一个参数是目标对象,后面的都是源对象var target = {}; //目标对象 var source1 = {name : 'ming', age: '19'}; //源对象 1 var source2 = {sex : '女'}; //源对象 2 var source3 = {sex : '男'}; //源对象 3,和 source2 中的对象有同名属性 sex Object.assign(target,source1,source2,source3); console.log(target); //{name : 'ming', age: '19', sex: '男'}
6、for…of 循环
var arr=["小林","小吴","小佳"]; for(var v of arr){ console.log(v); } //小林 //小吴 //小佳
7、import 和 export
ES6 标准中,JavaScript 原生支持模块(module)。这种将 JS 代码分割成不同功能的小块进行 模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通 过模块的导入的方式可以在其他地方使用 export 用于对外输出本模块(一个文件可以理解为一个模块)变量的接口 import 用于在一个模块中加载另一个含有 export 接口的模块
import 和 export 命令只能在模块的顶部,不能在代码块之中
8、Promise 对象
Promise 是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,避免了层层 嵌套的回调函数,要是为了解决异步处理回调地狱(也就是循环嵌套的问题)而产生的 Promise 构造函数包含一个参数和一个带有 resolve(解析)和 reject(拒绝)两个参数的回 调。在回调中执行一些操作(例如异步),如果一切都正常,则调用 resolve,否则调用 reject。 对于已经实例化过的 Promise 对象可以调用 Promise.then() 方法,传递 resolve 和 reject 方法作为回调。then()方法接收两个参数:onResolve 和 onReject,分别代表当前 Promise 对 象在成功或失败时
Promise 的 3 种状态
Fulfilled 为成功的状态,Rejected 为失败的状态,Pending 既不是 Fulfilld 也不是 Rejected 的状态,可以理解为 Promise 对象实例创建时候的初始状态
9、 解构赋值
- 数组的解构赋值
解构赋值是对赋值运算符的扩展。 是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。 在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。 数组中的值会自动被解析到对应接收该值的变量中,数组的解构赋值要一一对应如果 有对应不上的就是 undefined。let [a, b, c] = [1, 2, 3]; // a = 1 // b = 2 // c = 3
- 对象的解构赋值
对象的解构赋值和数组的解构赋值其实类似,但是数组的数组成员是有序的,而对象的属性则是无序的,所以对象的解构赋值简单理解是等号的左边和右边的结构相同。let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb' let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd
10、 Set 数据结构
Set 数据结构,类似数组。所有的数据都是唯一的,没有重复的值。它本身是一个构造函数。
- Set 属性和方法
Size() 数据的长度。 Add() 添加某个值,返回 Set 结构本身。 Delete() 删除某个值,返回一个布尔值,表示删除是否成功。 Has() 查找某条数据,返回一个布尔值。 Clear()清除所有成员,没有返回值。
- 主要应用场景:数组去重。
11、 class
class 类的继承 ES6 中不再像 ES5 一样使用原型链实现继承,而是引入 Class 这个概念。
ES6 所写的类相比于 ES5 的优点:
- 区别于函数,更加专业化, 写法更加简便,更加容易实现类的继承
12、 …
展开运算符可以将数组或对象里面的值展开;还可以将多个值收集为一个变量。
13、 async、await
使用 async/await, 搭配 Promise,可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性和可读性 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方 法执行完成 。
14、 修饰器
@decorator 是一个函数,用来修改类甚至于是方法的行为。修饰器本质就是编译时执行的函数。
15、 Symbol
Symbol 是一种基本类型。Symbol 通过调用 symbol 函数产生,它接收一个可选的名字参数,该函数返回的 symbol 是唯一的。
16、 Proxy
Proxy 代理使用代理(Proxy)监听对象的操作,然后可以做一些相应事情。
12.ES6 的继承和 ES5 的继承有什么区别?
ES5 的继承是通过原型或者是构造函数机制来实现 ES6 用过 class 关键字定义类,里面有构造方法,类之间通过 extends 关键字实现,子类必须 在 constructor 方法中调用 super 方法。
13.var、let、const 之间的区别?
区别:
var 声明变量可以重复声明,而 let 不可以重复声明
var 是不受限于块级的,而 let 是受限于块级
var 会与 window 相映射(会挂一个属性),而 let 不与 window 相映射
var 可以在声明的上面访问变量,而 let 有暂存死区,在声明的上面访问变量会报错
const 声明之后必须赋值,否则会报错
const 定义不可变的量,改变了就会报错
const 和 let 一样不会与 window 相映射、支持块级作用域、在声明的上面访问变量会报错
14.class、extends 是什么,有什么作用?
1、class 的作用
ES6 的 Class 可以看作只是一个 ES5 生成实例对象的构造函数的语法糖。 它参考了 java 语言,定义了一个类的概念,让对象原型写法更加清晰,对象实例化更像是 一种面向对象编程。
2、extends 的作用
extends 是 ES6 引入的关键字,其本质仍然是构造函数+原型链的组合式继承。 class 类可以通过 extends 实现继承。
3、class 和 ES5 构造函数的不同点
1、类的内部定义的所有方法,都是不可枚举的。
2、ES6 的 class 类必须用 new 命令操作,而 ES5 的构造函数不用 new 也可以执行。
3、ES6 的 class 类不存在变量提升,必须先定义 class 之后才能实例化,不像 ES5 中可以将 构造函数写在实例化之后。
4、ES5 的继承,实质是先创造子类的实例对象 this,然后再将父类的方法添加到 this 上面。 ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到 this 上面(所以 必须先调用 super 方法),然后再用子类的构造函数修改 this。
15.Vue 的优势是什么?
- Vue 作为一款轻量级框架、简单易学、 数据绑定、组件化、数据和结构的分离、虚拟 DOM、运行速度快,并且作者是中国人尤雨溪,对应的 API 文档对国内开发者优化,作为前端开发人员的首选入门框架。
- Vue 有很多优势: Vue.js 可以进行组件化开发,使代码编写量大大减少,读者更加易于理解。
- Vue.js 最突出的优势在于可以对数据进行双向绑定。 相比传统的页面通过超链接实现页面的切换和跳转,Vue 使用路由不会刷新页面。
- Vue 是单页面应用,使页面局部刷新,不用每次跳转页面都要请求所有数据和 dom, 这样大大加快了访问速度和提升用户体验。 而且他的第三方 UI 组件库使用起来节省很多开发时间,从而提升开发效率。
16.mvvm 和 mvc 区别是什么?
1、MVVM 基本定义
MVVM 即 Model-View-ViewModel 的简写。
即模型-视图-视图模型。
- 模型(Model)指的是后端传递的数据。
- 视图(View)指的是所看到的页面。
视图模型 (ViewModel)是 mvvm 模式的核心,它是连接 view 和 model 的桥梁。
它有两个方向:
- 一是将模型(Model)转化成视图(View),即将后端传递的数据转化成所看到的页面。
实现的方式是:数据绑定。- 二是将视图(View)转化成模型(Model),即将所看 到的页面转化成后端的数据。
实现的方式是:DOM 事件监听。
_
这两个方向都实 现的,我们称之为数据的双向绑定。
17.Vue双向绑定原理?
在 Vue 2.x 中,利⽤的是
Object.defineProperty
去劫持对象的访问器(Getter、Setter),当对象属性值发⽣变化时可获取变化,然后根据变化来作后续响应。
在 Vue 3.0 中,则是通过
Proxy
代理对象进⾏类似的操作。
18.Object.defineProperty和Proxy的优缺点?
1、Proxy
- 可以直接监听整个对象,⽽⾮是对象的属性 。
- 可以直接监听数组的变化。
- 拦截⽅法丰富:多达13种,不限于
apply
、ownKeys
、deleteProperty
、has
等。
比Object.defineProperty
强大很多。- 返回的是⼀个新对象,可以在不影响原对象的情况下,只操作新对象来达到⽬的;⽽
Object.defineProperty
只能遍历原对象属性并直接修改原对象。- 受到各浏览器⼚商的重点持续性能优化,能享受到作为新标准的性能红利 。
2、Object.defineProperty
- 兼容性较好(可⽀持到 IE9)
19.Vue 常用的指令都有哪些?
- v-model 多用于表单元素实现双向数据绑定。
- v-for 格式:
v-for=“字段名 in(of) 数组 json” 循环数组 或 json,需要注意从 Vue2 开始取消了$index
。- v-show 显示内容。
- v-hide 隐藏内容。
- v-if 显示与隐藏(dom 元素的删除添加)。
- v-else-if 必须和 v-if 连用。
- v-else 必须和 v-if 连用,不能单独使用,否则会报错 (模板编译错误)。
- v-bind 动态绑定 作用:及时对页面的数据进行更改。
- v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数,函数必须写在 methods 里面。
- v-text 解析文本。
- v-html 解析 html 标签。
- v-bind:class 三种绑定方法:
- 对象型 ‘{red:isred}’
- 三元型 ‘isred?“red”:“blue”’
- 数组型 ‘[{red:“isred”},{blue:“isblue”}]’
- v-once 进入页面时,只渲染一次,不在进行渲染
20.你对盒子模型的理解是什么样的?
浏览器的渲染引擎在对网页文档进行布局时,会按照 “CSS 基础盒模型” (CSS Basic Box Model)标准,将文档中的所有元素都表示为一个个矩形的盒子,再用 CSS 去决定这些盒子的大小尺寸、显示位置、以及其他属性(如颜色、背景、边框等)。
它由几部分组成:
- 内容(content)
- 内边距(padding)
- 边框(border)
- 外边距(margin)
21.谈谈你对 flex 的理解?
- 在真实的应用场景中,通常会遇到各种各样不同尺⼨和分辨率的设备,为了能在所有这些设备上正常的布局我们的应用界面,就需要响应式的界⾯设计方式来满⾜这种复杂的布局需求。
- flex 弹性盒模型的优势在于开发⼈员只需要声明布局应该具有的⾏为,⽽不需要给出具体的实现⽅式,浏览器负责完成实际布局,当布局涉及到不定宽度,分布对⻬的场景时,就要优先考虑弹性盒布局。
你能联想到的flex语法有哪些呢?
- flex-direction: 调整主轴方向。
- row:主轴方向为水平向右 。
- column:主轴方向为竖直向下。
- row-reverse:主轴方向为水平向左 。
- column-reverse:主轴方向是竖直向上。
- justify-content主要用来设置主轴方向的对齐方式。
- flex-start: 弹性盒子元素将向起始位置对齐。
- flex-end: 弹性盒子元素将向结束位置对齐。
- center: 弹性盒子元素将向行中间位置对齐。
- space-around: 弹性盒子元素会平均地分布在行里。
- space-between:第一个贴左边,最后一个贴右边,其他盒子均分,保证每个盒子之间的空隙是相等的。
- align-items用于调整侧轴的对齐方式
- flex-start: 元素在侧轴的起始位置对齐。
- flex-end: 元素在侧轴的结束位置对齐。
- center: 元素在侧轴上居中对齐。
- stretch: 元素的高度会被拉伸到最大(不给高度时, 才拉伸)。
- flex-wrap属性控制flex容器是单行或者多行,默认不换行
- nowrap: 不换行(默认),如果宽度溢出,会压缩子盒子的宽度。
- wrap: 当宽度不够的时候,会换行。
- align-content用来设置多行的flex容器的排列方式
- flex-start: 各行向侧轴的起始位置堆叠。
- flex-end: 各行向弹性盒容器的结束位置堆叠。
- center: 各行向弹性盒容器的中间位置堆叠。
- space-around: 各行在侧轴中平均分布。
- space-between: 第一行贴上边,最后一个行贴下边,其他行在弹性盒容器中平均分布。
- stretch:拉伸,不设置高度的情况下。
22.在 CSS 中有哪些定位方式?
1、static 正常文档流定位
- 此时设置 top、right、bottom、left 以及 z-index 都无效
- 块级元素遵循从上往下纵向排列,行级元素遵循从左到右排列
2、relative 相对定位
这个 “相对” 是指相对于正常文档流的位置。
3、absolute 绝对定位
当前元素相对于最近的非 static 定位的祖先元素
来确定自己的偏移位置。
例如:当前为 absolute 的元素的父元素、祖父元素都为 relative,则当前元素会相对于父元素进行偏移定位。
4、fixed 固定定位
当前元素相对于屏幕视口 viewport 来确定自己的位置。并且当屏幕滚动时,当前元素的位置也不会发生改变。
5、sticky 粘性定位
这个定位方式有点像 relative 和 fixed 的结合。当它的父元素在视口区域、并进入 top 值给定的范围内时,当前元素就以 fixed 的方式进行定位,否则就以 relative 的方式进行定位。
<style>
* {
margin: 0;
padding: 0;
}
.header {
width: 100%;
height: 100px;
background-color: orange;
}
.nav {
width: 100%;
height: 200px;
background-color: pink;
position: sticky;
top: 0px;
}
.main {
width: 100%;
height: 100px;
background-color: skyblue;
}
</style>
<div class="header">我是头部</div>
<div class="nav">我是导航</div>
<div class="container">
<div class="main">我是主体部分1</div>
<div class="main">我是主体部分2</div>
<div class="main">我是主体部分3</div>
<div class="main">我是主体部分4</div>
<div class="main">我是主体部分5</div>
<div class="main">我是主体部分6</div>
<div class="main">我是主体部分7</div>
<div class="main">我是主体部分8</div>
</div>
跳转上篇文章:前端面试题总结1https://blog.csdn.net/m0_62181310/article/details/125726651?spm=1001.2014.3001.5502
23.几种前端存储的区别是什么?
方式名称 | 标准说明 | 功能说明 |
---|---|---|
Cookies | HTML5 前加入 | 1.会为每个请求自动携带所有的Cookies数据,比较方便,但是也是缺点,浪费流量; 2.每个domain(站点)限制存储20个cookie; 3.容量只有4K 4.浏览器API比较原始,需要自行封装操作。 (js-cookie) |
localStorage | HTML5 加入 | 1.兼容IE8+,操作方便; 2.永久存储,除非手动删除; 3.容量为5M |
sessionStorage | HTML5 加入 | 1.功能基本与 localStorage 相似,但当前页面关闭后即被自动清理; 2.与Cookies、localStorage 不同点是不能在所有同源窗口间共享,属于会话级别的存储 |
Web SQL | 非标准功能 | 1.2010年已被废弃,但一些主流浏览器中都有相关的实现; 2.类似于 SQLite 数据库,是一种真正意义上的关系型数据库,⽤SQL进⾏操作; |
IndexedDB | HTML5 加入 | 1.是一种 NoSQL 数据库,⽤键值对进⾏储存,可进⾏快速读取操作; 2.适合复杂 Web存储场景,⽤JS操作⽅便 (前端大量存数据的场景较少, 如果有, 可以用) 3.存储空间容量, 大于等于 250MB,甚至没有上限 |
24.HTTP状态码有哪些?
跳转上篇文章:HTTP状态码有哪些?https://blog.csdn.net/m0_62181310/article/details/126505576?spm=1001.2014.3001.5501
25.URL 的各个部分,分别是什么意思?
例:scheme://host:port/path?query#fragment
- .scheme:通信协议,常用的 HTTP,ftp,maito 等
- .host:主机,服务器(计算机)域名系统 (DNS) 主机名或 IP 地址
- .port:端口号,整数,可选,省略时使用方案的默认端口,如 HTTP 的默认端口为 80
- .path:路径,由零或多个"/"符号隔开的字符串,一般用来表示主机上的一个目录或 文件地址
- .query:查询,可选,用于给动态网页传递参数,可有多个参数,用"&“符号隔开, 每个参数的名和值用”="符号隔开
- .fragment:信息片断,字符串,用于指定网络资源中的片断。例如一个网页中有多 个名词解释,可使用 fragment 直接定位到某一名词解释。(也称为锚点)
26.什么是 window 对象?什么是 document 对象?
1、什么是 window 对象
- Window 对象表示浏览器中打开的窗口,document 是 window 的一个对象属性。
- 如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外的 window 对象。
- 所有的全局函数和对象都属于 Window 对象的属性和方法。
- 它是一个顶层对象,而不是另一个对象的属性,即浏览器的窗口。
属性:
- defaultStatus 缺省的状态条消息
- document 当前显示的文档(该属性本身也是一个对象)
- frame 窗口里的一个框架((FRAME>)(该属性本身也是一个对象)
- frames array 列举窗口的框架对象的数组,按照这些对象在文档中出现的顺序列出(该属性本身也是一个对象)
- history 窗口的历史列表(该属性本身也是一个对象)
- length 窗口内的框架数
- location 窗口所显示文档的完整(绝对)URL(该属性本身也是一个对象)不要把它与如 document.location 混淆,后者是当前显示文档的 URL。
用户可以改变 window.location(用另一个文档 取代当前文档),但却不能改变document.location (因为这是当前显示文档的位置)- name 窗口打开时,赋予该窗口的名字
- opener 代表使用 window.open 打开当前窗口的脚本所在的窗口(这是 Netscape Navigator 3.0beta 3 所引入的一个新属性)
- parent 包含当前框架的窗口的同义词。frame 和 window 对象的一个属性。
- self 当前窗口或框架的同义词
- status 状态条中的消息
- top 包含当前框架的最顶层浏览器窗口的同义词
- window 当前窗口或框架的同义词,与 self 相同
方法:
- alert() 打开一个 Alert 消息框
- clearTimeout() 用来终止 setTimeout 方法的工作
- close() 关闭窗口
- confirm() 打开一个 Confirm 消息框,用户可以选择 OK 或 Cancel,如果用户单击 OK,该 方法返回 true,单击 Cancel 返回 false
- blur() 把焦点从指定窗口移开(这是 Netscape Navigator 3.0 beta 3 引入的新方法)
- focus() 把指定的窗口带到前台(另一个新方法)
- open() 打开一个新窗口
- prompt() 打开一个 Prompt 对话框,用户可向该框键入文本,并把键入的文本返回到脚本
- setTimeout() 等待一段指定的毫秒数时间,然后运行指令事件处理程序事件处理程序
- onload() 页面载入时触发
- onunload() 页面关闭时触发
2、什么是 document 对象
document 对象是 window 和 frames 对象的一个属性,是显示于窗口或框架内的一个文档。
属性:
- alinkColor 活动链接的颜色(ALINK)
- anchor 一个 HTMI 锚点,使用<A NAME=>标记创建(该属性本身也是一个对象)
- anchors array 列出文档锚点对象的数组(<A NAME=>)(该属性本身也是一个对象)
- bgColor 文档的背景颜色(BGCOLOR)
- cookie 存储于 cookie.txt 文件内的一段信息,它是该文档对象的一个属性
- fgColor 文档的文本颜色(标记里的 TEXT 特性)
- form 文档中的一个窗体()(该属性本身也是一个对象)
- forms anay 按照其出现在文档中的顺序列出窗体对象的一个数组(该属性本身也是一个对象)
- lastModified 文档最后的修改日期
- linkColor 文档的链接的颜色,即标记中的 LINK 特性(链接到用户没有观察到的 文档)
- link 文档中的一个<A HREF=>标记(该属性本身也是一个对象)
- links array 文档中 link 对象的一个数组,按照它们出现在文档中的顺序排列(该属性本身也是一个对象)
- location 当前显示文档的 URL。用户不能改变 document.location(因为这是当前显示文档的位置)。但是,可以改变 window.location (用其它文档取代当前文档)window.location 本身也是 一个对象,而 document.location 不是对象
- referrer 包含链接的文档的 URL,用户单击该链接可到达当前文档
- title 文档的标题((TITLE>)
- vlinkColor 指向用户已观察过的文档的链接文本颜色,即标记的 VLINK 特性
方法:
- clear 清除指定文档的内容
- close 关闭文档流
- open 打开文档流
- write 把文本写入文档
- writeln 把文本写入文档,并以换行符结尾
3、两者区别:
1、window 指窗体。document 指页面。
document 是 window 的一个子对象。
2、用户不能改变document.location( 因为这是当前文档显示的位置) 。但是, 可以改变window.location ( 用其他文档取代当前文档),window.location 本身也是一个对象 , 而 document.location 不是对象
27.HTTP 缓存机制?
1、基本认知
Web 服务缓存 大致可以分为:
数据库缓存、服务器端缓存(代理服务器缓存、CDN 服务器缓存)、浏览器缓存。
浏览器缓存 也包含很多内容:
HTTP 缓存、indexDB、cookie、localstorage 等等。
这里只讨论 HTTP 缓存相关内容
。
HTTP缓存:
- 强缓存
- 协商缓存
在具体了解 HTTP 缓存之前先来明确几个术语:
- 缓存命中率:从缓存中得到数据的请求数 与 所有请求数的比率。理想状态是越高越好。
- 过期内容:超过设置的有效时间,被标记为“陈旧”的内容。
- 验证:验证缓存中的过期内容是否仍然有效,验证通过的话刷新过期时间。
- 失效:失效就是把内容从缓存中移除。
浏览器缓存主要是 HTTP 协议定义的缓存机制。
浏览器缓存, HTTP缓存分类
浏览器缓存分为 强缓存
和 协商缓存
,浏览器加载一个页面的简单流程如下:
- 浏览器先根据这个资源的
http头信息
来判断是否命中强缓存
。
如果命中则直接加载在缓存中的资源,并不会将请求发送到服务器。(强缓存)- 如果未命中强缓存,则浏览器会将资源加载请求发送到服务器。
服务器来判断浏览器本地缓存是否失效。
若可以使用,则服务器并不会返回资源信息,浏览器继续从缓存加载资源。(协商缓存)- 如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。(新的请求)
2、强缓存 (过期时间判断)
(进行判断, 是否资源过期, 如果未过期, 直接用缓存)
强缓存
命中强缓存时,浏览器并不会将请求发送给服务器。
在Chrome的开发者工具中看到http的返回码是200,但是在Size列会显示为(from cache)。
强缓存是利用http的返回的响应头中的Expires
或者Cache-Control
(优先级更高) 两个字段来控制的,用来表示资源的缓存时间。
Expires
: 指定一个具体时间(2020年12月12日 17:00), 到了这个时间了, 缓存过期了, 在时间内, 都是有效的, 可以直接读Cache-Control
: 指定一个过期时间 (3600s), 这个资源你加载到后, 可以用 3600s
Expires
缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。但在上面我们提到过,cache-control的优先级更高
。
- Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
- 该字段会返回一个时间,比如Expires: Wed, 23 Nov 2050 16:00:01 GMT 。这个时间代表着这个资源的失效时间,也就是说在xx年xx月xx日时间之前都是有效的,即命中缓存。
- 这种方式有一个明显的缺点,由于失效时间是一个
绝对时间
,所以当 服务器与客户端时间偏差很大 以后,就会导致缓存混乱。于是发展出了Cache-Control。
Cache-Control
- Cache-Control是一个
相对时间
,例如Cache-Control:max-age 3600,代表着资源的有效期是3600秒。 - 由于是相对时间,并且都是与客户端时间比较,所以服务器与客户端时间偏差也不会导致问题。
- Cache-Control与Expires可以在服务端配置同时启用或者启用任意一个,同时启用的时候Cache-Control优先级高。
- Cache-Control 可以由多个字段组合而成,主要有以下几个取值:
- max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。
例如设置:
Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 / 60)天,
第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。
在没有禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。- no-cache 强制所有缓存了该响应的用户,在使用已缓存的数据前,发送带验证的请求到服务器, 问服务器是否可以读缓存。
不是字面意思上的不缓存。- `no-store 禁止缓存,每次请求都要向服务器重新获取数据。
3、协商缓存 (找供货商专家协商)
- 看看过期时间, 没过期, 直接用 (直接读缓存, 不发请求) 强缓存
- 时间过期了, 能不能用呢? 问问专家(服务器), 专家瞅了一眼, 没过期 (响应304, 不返回内容) , 直接用(协商缓存)
- 如果问过专家(服务器), 专家瞅了一眼, 过期了, 原来的不要了, 我重新给你发一个 (响应200, 并返回内容)
协商缓存
- 若未命中强缓存(强缓存过期了),则浏览器会将请求发送至服务器。
- 服务器根据http头信息中的
Last-Modify/If-Modify-Since
或Etag/If-None-Match
来判断是否命中协商缓存。- 如果命中,则http返回码为304 (本地之前加载的资源是有效的),浏览器从缓存中加载资源。
Last-Modify/If-Modify-Since
- 浏览器第一次请求一个资源的时候, 服务器返回的header中会加上Last-Modify,
Last-modify是一个时间标识该资源的最后修改时间
例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT
。- 当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。
服务器收到If-Modify-Since后,根据实际服务器的资源的最后修改时间, 进行判断是否命中缓存。
如果命中缓存,则返回 http304,并且不会返回资源内容,并且不会返回Last-Modify。- 由于对比的是服务端时间,所以客户端与服务端时间差距不会导致问题。
但是有时候通过最后修改时间来判断资源是否修改还是不太准确(资源变化了最后修改时间也可以一致)。
比如: 最后修改只能精确到秒级, 一秒进行了多次修改, 就不行了,于是出现了ETag/If-None-Match。
ETag/If-None-Match
- 与Last-Modify/If-Modify-Since (最后修改时间)不同的是,Etag/If-None-Match返回的是一个校验码(ETag: entity tag)。
- ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。
- ETag值的变更则说明资源状态已经被修改。
- 服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。
ETag生成靠以下几种因子:
- 文件的i-node编号,是Linux/Unix用来识别文件的编号。
- 文件最后修改时间
- 文件大小
…
生成Etag的时候,可以使用其中一种或几种因子,使用抗碰撞散列函数来生成。生成一个标记文件的唯一值
既生 Last-Modified 何生 Etag ?
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?
Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
- Last-Modified标注的最后修改只能精确到秒级
如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间 - 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。
- 不会仅仅只根据最后的修改时间判断是否进行使用缓存
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
总结:
- 强缓存: 大大的减少了 服务器的请求次数, 在过期时间内, 直接从客户端内存中读
- 协商缓存: 强缓存命中失效了, 超过过期时间了, 拿着标识(最后的修改时间, 唯一标识etag), 去问服务器, 是否真的过期了
如果验证通过, 服务器会直接响应 304, 且不会返回资源
28.箭头函数和普通函数的区别?
- 用了箭头函数,this 就不是指向 window,而是父级(指向是可变的)
- 不能够使用 arguments 对象
- 不能用作构造函数,这就是说不能够使用 new 命令,否则会抛出一个错误
- 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数
29.箭头函数中的this指向什么?
- 箭头函数不同于传统函数,它其实没有属于⾃⼰的
this
,- 它所谓的
this
是, 捕获其外层 上下⽂的this
值作为⾃⼰的this
值。- 并且由于箭头函数没有属于⾃⼰的
this
,它是不能被new
调⽤的。
我们可以通过 Babel 转换前后的代码来更清晰的理解箭头函数:
// 转换前的 ES6 代码
const obj = {
test() {
return () => {
console.log(this === obj)
}
}
}
// 转换后的 ES5 代码
var obj = {
test: function getArrow() {
var that = this
return function () {
console.log(that === obj)
}
}
}
这里我们看到,箭头函数中的
this就是它上层上下文函数中的
this。
30.对this的理解?
this
是一个在运行时才进行绑定的引用,在不同的情况下它可能会被绑定不同的对象。- 默认绑定 (指向window的情况) (函数调用模式 fn() )
- 默认情况下,
this
会被绑定到全局对象上,比如在浏览器环境中就为window
对象,在node.js环境下为global
对象。
如下代码展示了这种绑定关系:
message = "Hello";
function test () {
console.log(this.message);
}
test() // "Hello"
隐式绑定 (谁调用, this指向谁) (方法调用模式 obj.fn() )
如果函数的调用是从对象上发起时,则该函数中的 this
会被自动隐式绑定为对象:
function test() {
console.log(this.message);
}
let obj = {
message: "hello,world",
test: test
}
obj.test() // "hello,world"
显式绑定 (又叫做硬绑定) (上下文调用模式, 想让this指向谁, this就指向谁)
硬绑定 => call apply bind
可以显式的进行绑定:
function test() {
console.log(this.message);
}
let obj1 = {
message: "你好世界123"
}
let obj2 = {
message: "你好世界456"
}
test.bind(obj1)() // "你好世界123"
test.bind(obj2)() // "你好世界456"
new 绑定 (构造函数模式)
另外,在使用 new
创建对象时也会进行 this
绑定
当使用 new
调用构造函数时,会创建一个新的对象并将该对象绑定到构造函数的 this
上:
function Greeting(message) {
this.message = message;
}
var obj = new Greeting("hello,world")
obj.message // "hello,world"
31.谈谈你对原型链的理解?
1、原型对象
在 JavaScript 中,除去一部分内建函数,绝大多数的函数都会包含有一个叫做
prototype
的属性,指向原型对象,
基于构造函数创建出来的实例, 都可以共享访问原型对象的属性。
例如我们的hasOwnProperty
,toString
⽅法等其实是 Obejct 原型对象的方法,它可以被任何对象当做⾃⼰的⽅法来使⽤。
hasOwnProperty
用于判断, 某个属性, 是不是自己的 (还是原型链上的)
let person = {
name: "Tom",
age: 18,
job: "student"
}
console.log(person.hasOwnProperty("name")) // true
console.log(person.hasOwnProperty("hasOwnProperty")) // false
console.log(Object.prototype.hasOwnProperty("hasOwnProperty")) // true
hasOwnProperty
并不是 person
对象的属性,但是 person
却能调用它。
那么 person
对象是如何找到 Object 原型中的 hasOwnProperty
的呢?这就要靠原型链的能力了。
2、原型链
- 在 JavaScript 中,每个对象中都有一个
__proto__
属性,这个属性指向了当前对象的构造函数的原型。- 对象可以通过自身的
__proto__
属性与它的构造函数的原型对象连接起来,而因为它的原型对象也有__proto__
,因此这样就串联形成一个链式结构,也就是我们称为的原型链。
32.谈谈对于继承的理解?
1、为什么要学习继承 ?
- 写的构造函数, 定义了一个类型 (人类), 万一项目非常大, 又有了细化的多个类型 (老师, 工人, 学生)
- 学习继承, 可以让多个构造函数之间建立关联, 便于管理和复用
2、什么是继承 ?
- 继承: 从别人那里, 继承东西过来 (财产, 房产)
- 代码层面的继承: 继承一些属性和方法
3、继承 - 原型继承
原型继承: 通过改造原型链, 利用原型链的语法, 实现继承方法!
分析需求:
- 人类, 属性: name, age
- 学生, 属性: name, age, className
- 工人, 属性: name, age, companyName
无论学生, 还是工人, => 都是人类, 所以人类原型上有的方法, 他们都应该要有
// 1. 定义Person构造函数
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function () {
console.log('人类会说话')
}
// 2. 定义Student构造函数
function Student (name, age, className) {
this.name = name
this.age = age
this.className = className
}
// 3. 原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
// 语法: 子构造函数.prototype = new 父构造函数()
Student.prototype = new Person()
Student.prototype.study = function() {
console.log('学生在学习')
}
let stu = new Student('张三', 18, '80期')
stu.say()
console.log(stu)
4、继承 - 组合继承
- 组合继承有时候也叫伪经典继承,指的是将原型链 和 借用构造函数 call 技术组合到一块,从而发挥二者之长的一种继承模式
- 思路: 是使用原型链实现对原型属性和方法的继承 (主要是方法),而通过借用构造函数来实现对实例属性构造的继承。
- 这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有它的自己的属性。
// 1. 定义Person构造函数
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function () {
console.log('人类会说话')
}
// 2. 定义Student构造函数
function Student (name, age, className) {
Person.call(this, name, age) // 实现构造属性的继承
this.className = className
}
// 3. 原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
// 语法: 子构造函数.prototype = new 父构造函数()
Student.prototype = new Person()
Student.prototype.study = function() {
console.log('学生在学习')
}
let stu = new Student('张三', 18, '80期')
stu.say()
console.log(stu)
// 方法通过 原型继承
// 属性通过 父构造函数的.call(this, name, age)
5、继承 - 寄生组合继承
student实例上有 name age, 而原型 __proto__
上不需要再有这些属性, 所以利用 Object.create 改装下Object.create(参数对象),
- Object.create 会创建一个新对象,
- 并且这个新对象的
__proto__
会指向传入的参数对象
// 1. 定义Person构造函数
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function () {
console.log('人类会说话')
}
// 2. 定义Student构造函数
function Student (name, age, className) {
Person.call(this, name, age)
this.className = className
}
// 3. 原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
// 语法: 子构造函数.prototype = new 父构造函数()
Student.prototype = Object.create(Person.prototype)
Student.prototype.study = function() {
console.log('学生在学习')
}
let stu = new Student('张三', 18, '80期')
stu.say()
console.log(stu)
// 总结:
// Object.create() 以参数的对象, 作为新建对象的__proto__属性的值, 返回新建的对象
6、es6 - class 实现继承 extends
// 继承关键字 => extends
class Person {
constructor (name, age) {
this.name = name
this.age = age
}
jump () {
console.log('会跳')
}
}
class Teacher extends Person {
constructor (name, age, lesson) {
super(name, age) // extends 中, 必须调用 super(), 会触发执行父类的构造函数
this.lesson = lesson
console.log('构造函数执行了')
}
sayHello () {
console.log('会打招呼')
}
}
let teacher1 = new Teacher('zs', 18, '体育')
console.log(teacher1)
33.new 实例对象过程?
4行代码
- 实例化object对象
- 改变构造函数的this指向
- 原型链继承
- 返回这个对象
// js中new的时候做了什么事情
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.run = function () {
console.log(this.name, this.age)
}
const p = new Person("黄昏", 20)
p.run()
// 创建一个createPerson的函数,实现js中new的效果
function createPerson (name, age) {
// 1.实例化object对象
const o = new Object()
// 2.改变构造函数的this指向
Person.call(o,name,age)
// 3.原型链继承
o._proto_ = Person.prototype
// 4.返回这个对象
return o
}
const w = createPerson("阿尼亚",12)
w.run()
34.如何判断是否是数组?
方法一:使用 toString
方法
function isArray(arg) {
return Object.prototype.toString.call(arg) === '[object Array]'
}
let arr = [1,2,3]
isArray(arr) // true
方法二:使用 ES6 新增的 Array.isArray
方法
let arr = [1,2,3]
Array.isArray(arr) // true
35.Vue双向绑定原理?
- 在 Vue 2.x 中,利⽤的是
Object.defineProperty
去劫持对象的访问器(Getter、Setter),当对象属性值发⽣变化时可获取变化,然后根据变化来作后续响应; - 在 Vue 3.0 中,则是通过
Proxy
代理对象进⾏类似的操作。
36.Object.defineProperty和Proxy的优缺点?
Proxy
-
可以直接监听整个对象,⽽⾮是对象的属性
-
可以直接监听数组的变化
-
拦截⽅法丰富:多达13种,不限于
apply
、ownKeys
、deleteProperty
、has
等。比Object.defineProperty
强大很多 -
返回的是⼀个新对象,可以在不影响原对象的情况下,只操作新对象来达到⽬的;⽽
Object.defineProperty
只能遍历原对象属性并直接修改原对象 -
受到各浏览器⼚商的重点持续性能优化,能享受到作为新标准的性能红利
Object.defineProperty
- 兼容性较好(可⽀持到 IE9)
37.Vue组件之间如何进行通信?
props
和 $emit + v-on
- 通过
props
将数据在组件树中进行⾃上⽽下的传递; - 通过
$emit
和v-on
来作信息的向上传递。
EventBus
- 可通过 EventBus 进⾏信息的发布与订阅。
Vuex
- 全局状态管理库。可通过它来进行全局数据流的管理。
$attrs
和 $listeners
- 在 Vue 2.4 版本中加⼊的
$attrs
和$listeners
可以用来作为跨级组件之间的通信机制。
provide
和 inject
- 由于
provide
和inject
可以允许⼀个祖先组件向它的所有⼦孙组件注⼊⼀个依赖(不论组件层次有多深),并在其上下游关系成⽴的时间⾥始终⽣效,因此这种机制也就成为了一种跨组件通信的手段。
跳转上篇文章:前端面试题总结1https://blog.csdn.net/m0_62181310/article/details/125726651?spm=1001.2014.3001.5502