面試題整理(華為)

題目概覽:
vuex的功能?能否進行兄弟組件之間的傳值?
Axios調(diào)取數(shù)據(jù)?
繼承prototype大概是怎么實現(xiàn)的?
es6中和原型一樣用來繼承的class和繼承是怎么實現(xiàn)的?
jQuery和Vue使用起來有什么區(qū)別?
vue父子組件傳值怎么實現(xiàn)的?
兄弟組件傳值怎么實現(xiàn)的?
怎么調(diào)程序中出現(xiàn)的代碼?
js的垃圾回收機制?
es6中const、let、var之間的區(qū)別?
閉包是什么?用let怎么實現(xiàn)閉包?

詳解:
1. vuex的功能?能否進行兄弟組件之間的傳值?
vuex專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。主要用于管理vue中的數(shù)據(jù),可以兄弟組件互相傳值;
state:管理項目的數(shù)據(jù)(進行數(shù)據(jù)初始化);
mutations:主要用于操作state中的數(shù)據(jù)store.commit('increment')
;
action:通過提交 mutation 的方式,而非直接改變?store.state.count
,是因為我們想要更明確地追蹤到狀態(tài)的變化;
getter:就像計算屬性,getter 的返回值會根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會被重新計算;getter 接受 state 作為其第一個參數(shù);
<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調(diào)取數(shù)據(jù)?
axios的特性
1、可以從瀏覽器中創(chuàng)建XHR對象
2、可以從nodeJS中創(chuàng)建HTTP請求
?3、支持Promise?
4、可以攔截請求和響應(yīng)?
5、可以轉(zhuǎn)換請求數(shù)據(jù)和響應(yīng)數(shù)據(jù)?
6、可以取消請求?
7、可以自動轉(zhuǎn)換JSON數(shù)據(jù)?
8、客戶端支持防御XSRF
axios get 方法:僅僅請求后臺數(shù)據(jù)
axios.get('index.php')
?????????.then(function (response) {
? ?????????????console.log(response);
?????????})
?????????.catch(function (error) {
? ?????????????console.log(error);
?????????});
aixos post方法:post請求更多的是要提交數(shù)據(jù),params屬性里的數(shù)據(jù)會出現(xiàn)在請求主體中。
axios.post('/user', {
? ?????firstName: 'Fred',
? ?????lastName: 'Flintstone'
?})
?.then(function (response) {
? ?????console.log(response);
?})
?.catch(function (error) {
? ?????console.log(error);
?});
多并發(fā)請求,一次性發(fā)幾個請求
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為第一個請求的結(jié)果,perms為第二個請求的結(jié)果
?}));
設(shè)置攔截器:
//請求攔截器
?axios.interceptors.request.use( ?
? ? ? ?config => {
? ? ? ? ? ?btn.innerHTML='請求數(shù)據(jù)中';
? ? ? ? ? ?return config;
? ? ? ?},
? ? ? ?// 錯誤時發(fā)生的事情
? ? ???err => {
? ? ? ? ? ?console.log(err)
? ? ? ?});?
// 響應(yīng)應(yīng)攔截器
? ? ? ?axios.interceptors.response.use(
? ? ? ?config => {
? ? ? ? ? ?btn.innerHTML='請求數(shù)據(jù)成功';
? ? ? ? ? ?return config;
? ? ? ?},
? ? ? ?// 錯誤時發(fā)生的事情
? ? ? ?err => {
? ? ? ? ? ?console.log(err)
? ? ? ?});
設(shè)置自定義請求頭:
第一步:先安裝Axios:npm install axios --save
第二步:再在main.js中引入Axios:
????import axios from 'axios'
????Vue.prototype.$http = axios;
第三步:即可在組件中調(diào)用Axios:
this.$axios.get('index.php/url')
?????.then(response => {
? ?????console.log(response)
?????})
????.catch(error => {
? ?????console.log(error)
?????});
第四步:然后設(shè)置自定義的頭請求:
axios.defaults.timeout = 5000;//請求超時的時間設(shè)定
axios.defaults.headers.post['Content-Type'] = 'application/json';?//axios默認的請求方式
axios.defaults.baseURL = 'http://localhost:8008';//axios默認的請求地址
axios.defaults.headers.common["token"] = "noname";//有些接口必須登錄才可以調(diào)用,而登陸注冊并未寫好,后臺給了一個故固定的token,寫在了頭里面

3. 繼承prototype大概是怎么實現(xiàn)的?
實例對象per的構(gòu)造器constructor是指構(gòu)造函數(shù)Person;
console.log(per.constructor==Person);//true
實例對象的_proto_
和構(gòu)造函數(shù)中的prototype相等;
console.log(per._proto_.constructor==Person.prototype.constructor);//true
原型鏈:實例對象使用的屬性或者方法,先在實例中查找,找到了則直接使用,找不到則去實例對象的__proto__
指向的原型對象prototype中找,找到了則使用,找不到則報錯。
實例對象中有_proto_
這個屬性,叫原型,也是一個對象,這個屬性是給瀏覽器使用,
不是標準的屬性----->proto----->可以叫原型對象;
構(gòu)造函數(shù)中有prototype這個屬性,叫原型,也是一個對象,這個屬性是給程序員使用,
是標準的屬性------>prototype--->可以叫原型對象;
1.原型繼承核心就是讓自定義的構(gòu)造器的prototype對象指向父類構(gòu)造器生成的對象:
//Person是個構(gòu)造函數(shù),Per是自定義的構(gòu)造器
function Per(){}
Per.prototype = new Person('Alice');
const person = new Per()//繼承父類實例定義的所有屬性以及父類構(gòu)造器原型上的屬性
2.?借用函數(shù)繼承:通過函數(shù)對象本身的?call
?和?apply
?來顯示的指定函數(shù)調(diào)用時必備的參數(shù);
function Per(name){
? ?Person.call(this,name)//當(dāng)成了普通函數(shù)來使用
}
const person = new Per('Alice')
//只能調(diào)用Person中定義的屬性和函數(shù),無法調(diào)用Person定義在prototype上的屬性和方法
3.組合繼承(原型鏈+借用函數(shù)):[為了解決借用函數(shù)無法使用函數(shù)原型上的屬性和方法]
function Per(name){
? ?Person.call(this,name)//當(dāng)成了普通函數(shù)來使用
}
Per.prototype = new Person('Alice')//這樣寫,會造成Animal實例化兩次,沒有自己的原型
//或者
Per.prototype = Person.prototype//這樣寫,就不會造成多次實例化
const person = new Per('Alice')
4.原型式繼承:提供一個被繼承的對象,把這個對象掛在到某個構(gòu)造函數(shù)的prototype上,再利用new;
function inherit (object) {
?????function fn () {} ??// 提供一個函數(shù)
?????fn.prototype = object ;?// 設(shè)置函數(shù)的prototype
?????return new fn() ? ?// 返回這個函數(shù)實例化出來的對象
}
const person = Person('Alice');
const me=inherit(person);//可以繼承peroson對象上所有的方法和屬性
5.寄生式繼承
6.寄生組合式繼承:利用?Object.create()
?方法

4. es6中和原型一樣用來繼承的class和繼承是怎么實現(xiàn)的?
typeof Point // "function",類的數(shù)據(jù)類型就是函數(shù)
Point === Point.prototype.constructor // true,類本身就指向構(gòu)造函數(shù)
使用的時候,也是直接對類使用new
命令,跟構(gòu)造函數(shù)的用法完全一致,不使用new會報錯。
類的所有方法都定義在類的prototype
屬性上面。
class Point {
?????constructor() {
???????????// ...
?????}
?????toString() {
???????????// ...
?????}
?????toValue() {
???????????// ...
?????}
}
//?等同于
Point.prototype = {
?????constructor() {},
?????toString() {},
?????toValue() {},
};
//Object.assign方法可以很方便地一次向類添加多個方法
Object.assign(Point.prototype, {
?????toString(){},
?????toValue(){}
});
類不存在變量提升(hoist),這一點與 ES5 完全不同。
Class 可以通過extends
關(guān)鍵字實現(xiàn)繼承。
class ColorPoint extends Point {}?//ColorPoint繼承了Point類所有的屬性和方法
super
關(guān)鍵字,表示父類的構(gòu)造函數(shù),用來新建父類的this
對象。
子類必須在constructor
方法中調(diào)用super
方法,否則新建實例時會報錯,只有調(diào)用super
之后,才可以使用this
關(guān)鍵字。
區(qū)別:
ES5 的繼承,實質(zhì)是先創(chuàng)造子類的實例對象this
,然后再將父類的方法添加到this
上面(Parent.apply(this)
)。
ES6 的繼承機制完全不同,實質(zhì)是先將父類實例對象的屬性和方法,加到this
上面(所以必須先調(diào)用super
方法),然后再用子類的構(gòu)造函數(shù)修改this
。
Class 作為構(gòu)造函數(shù)的語法糖,同時有prototype
屬性和__proto__
屬性,因此同時存在兩條繼承鏈。
(1)子類的_proto_
屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。
(2)子類prototype
屬性的_proto_
屬性,表示方法的繼承,總是指向父類的prototype
屬性。
子類實例的__proto__
屬性的__proto__
屬性,指向父類實例的__proto__
屬性。也就是說,子類的原型的原型,是父類的原型。
Object.getPrototypeOf
方法判斷,一個類是否繼承了另一個類。

5. jQuery和Vue使用起來有什么區(qū)別?
? ? ? ?從jquery到vue或者說是到mvvm的轉(zhuǎn)變則是一個思想的轉(zhuǎn)變,是將原有的直接操作dom的思想轉(zhuǎn)變到操作數(shù)據(jù)上去。
? ? ? ?從技術(shù)角度講,Vue.js 專注于 MVVM 模型的 ViewModel 層。它通過雙向數(shù)據(jù)綁定把 View 層和 Model 層連接了起來,通過對數(shù)據(jù)的操作就可以完成對頁面視圖的渲染。
? ? ? ?jQuery是使用選擇器($)選取DOM對象,對其進行賦值、取值、事件綁定等操作,和原生的區(qū)別只在于可以更方便的選取和操作DOM對象,其數(shù)據(jù)和界面是在一起的。
? ? ? ?Vue則是通過Vue對象將數(shù)據(jù)和View層分離開來。對數(shù)據(jù)進行操作不再需要引用相應(yīng)的DOM對象,通過Vue對象這個vm實現(xiàn)相互的綁定。
? ? ? ?vue適用的場景:復(fù)雜數(shù)據(jù)操作的后臺頁面,表單填寫頁面;vue側(cè)重數(shù)據(jù)綁定;
jquery適用的場景:比如說一些html5的動畫頁面,一些需要js來操作頁面樣式的頁面;jquery側(cè)重樣式操作,動畫效果等;

6. vue父子組件傳值怎么實現(xiàn)的?
父傳子:
先在父組件中綁定變量
<child :msg="parent"></child>
,parent是定義在父組件中的變量/值;再在子組件中添加props屬性接收父組件傳遞過來的變量
props:['msg']
;最后就可以在子組件中使用
{{msg}}
來表示父組件中parent變量中的值了。子傳父:
先在子組件中綁定事件
@change="sendChild"
,觸發(fā)的時候在setChild
事件中用$emit()
觸發(fā)父組件中的函數(shù),并將子組件中的變量作為參數(shù)傳遞;methods:{
? ?sendChild:function(){
? ? ? ?this.$emit('transparent',this.msg)
? ?}
}在父組件中綁定事件
<child @transparent="getChild"></child>
,當(dāng)子組件觸發(fā)這個事件的時候,就可以調(diào)用getChild
方法獲取到傳遞過來的參數(shù);methods:{
? ?getChild(msg){
? ? ? ?this.user=msg;
? ?}
}

7. 兄弟組件傳值怎么實現(xiàn)的?
1.?兄弟組件互相傳值,通過Vuex狀態(tài)管理傳值:
先通過npm加載vuex,創(chuàng)建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文件,發(fā)布者訂閱者模式:
import Bus from './bus.js'?? //一個子組件觸發(fā)
? methods:{
? ? ? Bus.$emit('觸發(fā)的方法名',需要傳遞的值);
? } ??//一個子組件監(jiān)聽
? mounted:{
? ? ? bus.$on("方法名",(傳遞的值)=>{ })
? }
3.?兄弟組件互相傳值$root
//一個子組件觸發(fā)
this.$root.$emit('觸發(fā)的方法名',需要傳遞的值);
this.$root.$off("方法名");//每次進入先關(guān)閉一下
//一個子組件監(jiān)聽
this.$root.$on("方法名",(傳遞的值)=>{ })

8. 怎么調(diào)程序中出現(xiàn)的代碼?
alert('方法一')
console.log('方法二')?
Chrome中的開發(fā)者工具:斷點設(shè)置、調(diào)試功能

9. js的垃圾回收機制?(摘自紅寶書)
離開作用域的值將被自動標記為可以回收,因此將在垃圾收集期間被刪除;
“?標記清除?”?是目前最主流的垃圾收集算法,這種算法的思想是給當(dāng)前不使用的值加上標記,然后再回收其內(nèi)存(當(dāng)變量進入環(huán)境時,將變量標記為“進入環(huán)境”。當(dāng)變量離開環(huán)境時,將其標記為“離開環(huán)境”,標記“離開環(huán)境”的就回收內(nèi)存);
另一種垃圾收集算法是?“?引用計數(shù)?”?,這種算法的思想是跟蹤記錄所有值被引用的次數(shù)。
JavaScript
引擎目前都不再使用這種算法;但在 IE 中訪問非原生JavaScript
對象(如DOM
元素)時,這種算法仍然可能會導(dǎo)致問題;當(dāng)代碼中存在循環(huán)引用現(xiàn)象時," 引用計數(shù) "算法就會導(dǎo)致問題;
解除變量的引用不僅有助于消除循環(huán)引用現(xiàn)象,而且對垃圾收集也有好處。為了確保有效的回收內(nèi)存,應(yīng)該及時解除不再使用的全局對象、全局對象屬性以及循環(huán)引用變量的引用。

10. es6中const、let、var之間的區(qū)別?
var定義的變量,作用域是整個封閉函數(shù),是全域的;
let定義的變量,作用域是在塊級或者字塊中;
變量提升:不論通過var聲明的變量處于當(dāng)前作用于的第幾行,都會提升到作用域的最頂部。
而let聲明的變量不會在頂部初始化,凡是在let聲明之前使用該變量都會報錯(引用錯誤ReferenceError);
只要塊級作用域內(nèi)存在
let
,它所聲明的變量就會綁定在這個區(qū)域;let不允許在相同作用域內(nèi)重復(fù)聲明(報錯同時使用var和let,兩個let)
const用來專門聲明一個常量,它跟let一樣作用于塊級作用域,沒有變量提升,重復(fù)聲明會報錯,不同的是const聲明的常量不可改變,聲明時必須初始化(賦值),const定義的對象可變。
const使用場景很廣,包括常量、配置項以及引用的組件、定義的 “大部分” 中間變量等,都應(yīng)該以cosnt做定義。反之就 let 而言,他的使用場景應(yīng)該是相對較少的,我們只會在 loop(for,while 循環(huán))及少量必須重定義的變量上用到他。

11. 閉包是什么?用let怎么實現(xiàn)閉包?
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。
一個閉包就是一個沒有釋放資源的棧區(qū),棧區(qū)內(nèi)的變量處于激活狀態(tài)。
在ES6中l(wèi)et實際是為js新增了塊級作用域。
let聲明的變量可以綁定在作用域中