面试题整理(华为)

题目概览:
vuex的功能?能否进行兄弟组件之间的传值?
Axios调取数据?
继承prototype大概是怎么实现的?
es6中和原型一样用来继承的class和继承是怎么实现的?
jQuery和Vue使用起来有什么区别?
vue父子组件传值怎么实现的?
兄弟组件传值怎么实现的?
怎么调程序中出现的代码?
js的垃圾回收机制?
es6中const、let、var之间的区别?
闭包是什么?用let怎么实现闭包?

详解:
1. vuex的功能?能否进行兄弟组件之间的传值?
vuex专为 Vue.js 应用程序开发的状态管理模式。主要用于管理vue中的数据,可以兄弟组件互相传值;
state:管理项目的数据(进行数据初始化);
mutations:主要用于操作state中的数据store.commit('increment')
;
action:通过提交 mutation 的方式,而非直接改变 store.state.count
,是因为我们想要更明确地追踪到状态的变化;
getter:就像计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算;getter 接受 state 作为其第一个参数;
<div id="app1">
{{count}}
</div>//store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state:{
count:0
}
});
new Vue({
el:'#app1',
store,
computed:{
count(){
return this.$store.state.count
}
}
})

2. Axios调取数据?
axios的特性
1、可以从浏览器中创建XHR对象
2、可以从nodeJS中创建HTTP请求
3、支持Promise
4、可以拦截请求和响应
5、可以转换请求数据和响应数据
6、可以取消请求
7、可以自动转换JSON数据
8、客户端支持防御XSRF
axios get 方法:仅仅请求后台数据
axios.get('index.php')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
aixos post方法:post请求更多的是要提交数据,params属性里的数据会出现在请求主体中。
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
多并发请求,一次性发几个请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// acct为第一个请求的结果,perms为第二个请求的结果
}));
设置拦截器:
//请求拦截器
axios.interceptors.request.use(
config => {
btn.innerHTML='请求数据中';
return config;
},
// 错误时发生的事情
err => {
console.log(err)
});
// 响应应拦截器
axios.interceptors.response.use(
config => {
btn.innerHTML='请求数据成功';
return config;
},
// 错误时发生的事情
err => {
console.log(err)
});
设置自定义请求头:
第一步:先安装Axios:npm install axios --save
第二步:再在main.js中引入Axios:
import axios from 'axios'
Vue.prototype.$http = axios;
第三步:即可在组件中调用Axios:
this.$axios.get('index.php/url')
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
});
第四步:然后设置自定义的头请求:
axios.defaults.timeout = 5000;//请求超时的时间设定
axios.defaults.headers.post['Content-Type'] = 'application/json'; //axios默认的请求方式
axios.defaults.baseURL = 'http://localhost:8008';//axios默认的请求地址
axios.defaults.headers.common["token"] = "noname";//有些接口必须登录才可以调用,而登陆注册并未写好,后台给了一个故固定的token,写在了头里面

3. 继承prototype大概是怎么实现的?
实例对象per的构造器constructor是指构造函数Person;
console.log(per.constructor==Person);//true
实例对象的_proto_
和构造函数中的prototype相等;
console.log(per._proto_.constructor==Person.prototype.constructor);//true
原型链:实例对象使用的属性或者方法,先在实例中查找,找到了则直接使用,找不到则去实例对象的__proto__
指向的原型对象prototype中找,找到了则使用,找不到则报错。
实例对象中有_proto_
这个属性,叫原型,也是一个对象,这个属性是给浏览器使用,
不是标准的属性----->proto----->可以叫原型对象;
构造函数中有prototype这个属性,叫原型,也是一个对象,这个属性是给程序员使用,
是标准的属性------>prototype--->可以叫原型对象;
1.原型继承核心就是让自定义的构造器的prototype对象指向父类构造器生成的对象:
//Person是个构造函数,Per是自定义的构造器
function Per(){}
Per.prototype = new Person('Alice');
const person = new Per()//继承父类实例定义的所有属性以及父类构造器原型上的属性
2. 借用函数继承:通过函数对象本身的 call
和 apply
来显示的指定函数调用时必备的参数;
function Per(name){
Person.call(this,name)//当成了普通函数来使用
}
const person = new Per('Alice')
//只能调用Person中定义的属性和函数,无法调用Person定义在prototype上的属性和方法
3.组合继承(原型链+借用函数):[为了解决借用函数无法使用函数原型上的属性和方法]
function Per(name){
Person.call(this,name)//当成了普通函数来使用
}
Per.prototype = new Person('Alice')//这样写,会造成Animal实例化两次,没有自己的原型
//或者
Per.prototype = Person.prototype//这样写,就不会造成多次实例化
const person = new Per('Alice')
4.原型式继承:提供一个被继承的对象,把这个对象挂在到某个构造函数的prototype上,再利用new;
function inherit (object) {
function fn () {} // 提供一个函数
fn.prototype = object ; // 设置函数的prototype
return new fn() // 返回这个函数实例化出来的对象
}
const person = Person('Alice');
const me=inherit(person);//可以继承peroson对象上所有的方法和属性
5.寄生式继承
6.寄生组合式继承:利用 Object.create()
方法

4. es6中和原型一样用来继承的class和继承是怎么实现的?
typeof Point // "function",类的数据类型就是函数
Point === Point.prototype.constructor // true,类本身就指向构造函数
使用的时候,也是直接对类使用new
命令,跟构造函数的用法完全一致,不使用new会报错。
类的所有方法都定义在类的prototype
属性上面。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
//Object.assign方法可以很方便地一次向类添加多个方法
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
类不存在变量提升(hoist),这一点与 ES5 完全不同。
Class 可以通过extends
关键字实现继承。
class ColorPoint extends Point {} //ColorPoint继承了Point类所有的属性和方法
super
关键字,表示父类的构造函数,用来新建父类的this
对象。
子类必须在constructor
方法中调用super
方法,否则新建实例时会报错,只有调用super
之后,才可以使用this
关键字。
区别:
ES5 的继承,实质是先创造子类的实例对象this
,然后再将父类的方法添加到this
上面(Parent.apply(this)
)。
ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this
上面(所以必须先调用super
方法),然后再用子类的构造函数修改this
。
Class 作为构造函数的语法糖,同时有prototype
属性和__proto__
属性,因此同时存在两条继承链。
(1)子类的_proto_
属性,表示构造函数的继承,总是指向父类。
(2)子类prototype
属性的_proto_
属性,表示方法的继承,总是指向父类的prototype
属性。
子类实例的__proto__
属性的__proto__
属性,指向父类实例的__proto__
属性。也就是说,子类的原型的原型,是父类的原型。
Object.getPrototypeOf
方法判断,一个类是否继承了另一个类。

5. jQuery和Vue使用起来有什么区别?
从jquery到vue或者说是到mvvm的转变则是一个思想的转变,是将原有的直接操作dom的思想转变到操作数据上去。
从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层。它通过双向数据绑定把 View 层和 Model 层连接了起来,通过对数据的操作就可以完成对页面视图的渲染。
jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,和原生的区别只在于可以更方便的选取和操作DOM对象,其数据和界面是在一起的。
Vue则是通过Vue对象将数据和View层分离开来。对数据进行操作不再需要引用相应的DOM对象,通过Vue对象这个vm实现相互的绑定。
vue适用的场景:复杂数据操作的后台页面,表单填写页面;vue侧重数据绑定;
jquery适用的场景:比如说一些html5的动画页面,一些需要js来操作页面样式的页面;jquery侧重样式操作,动画效果等;

6. vue父子组件传值怎么实现的?
父传子:
先在父组件中绑定变量
<child :msg="parent"></child>
,parent是定义在父组件中的变量/值;再在子组件中添加props属性接收父组件传递过来的变量
props:['msg']
;最后就可以在子组件中使用
{{msg}}
来表示父组件中parent变量中的值了。子传父:
先在子组件中绑定事件
@change="sendChild"
,触发的时候在setChild
事件中用$emit()
触发父组件中的函数,并将子组件中的变量作为参数传递;methods:{
sendChild:function(){
this.$emit('transparent',this.msg)
}
}在父组件中绑定事件
<child @transparent="getChild"></child>
,当子组件触发这个事件的时候,就可以调用getChild
方法获取到传递过来的参数;methods:{
getChild(msg){
this.user=msg;
}
}

7. 兄弟组件传值怎么实现的?
1. 兄弟组件互相传值,通过Vuex状态管理传值:
先通过npm加载vuex,创建store.js文件
//store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const state={name:'Alice'};
const mutations={
newName(state,message){
state.name=message
}
}
export default new Vuex.Store({state,mutations})
2. 兄弟组件互相传值,引入bus.js文件,发布者订阅者模式:
import Bus from './bus.js' //一个子组件触发
methods:{
Bus.$emit('触发的方法名',需要传递的值);
} //一个子组件监听
mounted:{
bus.$on("方法名",(传递的值)=>{ })
}
3. 兄弟组件互相传值$root
//一个子组件触发
this.$root.$emit('触发的方法名',需要传递的值);
this.$root.$off("方法名");//每次进入先关闭一下
//一个子组件监听
this.$root.$on("方法名",(传递的值)=>{ })

8. 怎么调程序中出现的代码?
alert('方法一')
console.log('方法二')
Chrome中的开发者工具:断点设置、调试功能

9. js的垃圾回收机制?(摘自红宝书)
离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除;
“ 标记清除 ” 是目前最主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存(当变量进入环境时,将变量标记为“进入环境”。当变量离开环境时,将其标记为“离开环境”,标记“离开环境”的就回收内存);
另一种垃圾收集算法是 “ 引用计数 ” ,这种算法的思想是跟踪记录所有值被引用的次数。
JavaScript
引擎目前都不再使用这种算法;但在 IE 中访问非原生JavaScript
对象(如DOM
元素)时,这种算法仍然可能会导致问题;当代码中存在循环引用现象时," 引用计数 "算法就会导致问题;
解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效的回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。

10. es6中const、let、var之间的区别?
var定义的变量,作用域是整个封闭函数,是全域的;
let定义的变量,作用域是在块级或者字块中;
变量提升:不论通过var声明的变量处于当前作用于的第几行,都会提升到作用域的最顶部。
而let声明的变量不会在顶部初始化,凡是在let声明之前使用该变量都会报错(引用错误ReferenceError);
只要块级作用域内存在
let
,它所声明的变量就会绑定在这个区域;let不允许在相同作用域内重复声明(报错同时使用var和let,两个let)
const用来专门声明一个常量,它跟let一样作用于块级作用域,没有变量提升,重复声明会报错,不同的是const声明的常量不可改变,声明时必须初始化(赋值),const定义的对象可变。
const使用场景很广,包括常量、配置项以及引用的组件、定义的 “大部分” 中间变量等,都应该以cosnt做定义。反之就 let 而言,他的使用场景应该是相对较少的,我们只会在 loop(for,while 循环)及少量必须重定义的变量上用到他。

11. 闭包是什么?用let怎么实现闭包?
闭包是指有权访问另一个函数作用域中的变量的函数。
一个闭包就是一个没有释放资源的栈区,栈区内的变量处于激活状态。
在ES6中let实际是为js新增了块级作用域。
let声明的变量可以绑定在作用域中