在此分享、整理前端面試題,若有解答錯誤的地方,煩請各位大佬指正,感謝!!javascript
每一個函數都有一個 prototype 屬性,函數的 prototype屬性指向了一個對象,這個對象正是調用該構造函數而建立的實例的原型前端
那什麼是原型呢?你能夠這樣理解:每個JavaScript對象(null除外)在建立的時候就會與之關聯另外一個對象,這個對象就是咱們所說的原型,每個對象都會從原型"繼承"屬性。java
這是每個JavaScript對象(除了 null )都具備的一個屬性,叫__proto__,這個屬性會指向該對象的原型。git
原型鏈解決的主要是繼承問題。github
每一個對象擁有一個原型對象,經過 proto 指針指向其原型對象,並從中繼承方法和屬性,同時原型對象也可能擁有原型,這樣一層一層,最終指向 null(Object.proptotype.proto 指向的是null)。這種關係被稱爲原型鏈 (prototype chain),經過原型鏈一個對象能夠擁有定義在其餘對象中的屬性和方法。面試
function Person() {
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true
複製代碼
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
複製代碼
function Person() {
}
var person = new Person();
console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
// 順便學習一個ES5的方法,能夠得到對象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
複製代碼
做用域是指程序源代碼中定義變量的區域。數組
做用域規定了如何查找變量,也就是肯定當前執行代碼對變量的訪問權限。promise
變量聲明提高:
foo; // undefined
var foo = function () {
console.log('foo1');
}
foo(); // foo1,foo賦值
複製代碼
能夠想象成:全部的聲明(變量和函數)都會被「移動」到各自做用域的最頂端
JS 中分爲七種內置類型,七種內置類型又分爲兩大類型:基本類型和對象(Object)。
基本類型有六種: null,undefined,boolean,number,string,symbol。
棧
內存(不包含閉包中的變量)堆
內存引用類型有:Object、Array、Date、RegExp、Function
var arr = [1,2,3,4,5,6,7,8,9,10];
var newArr = [];
let length=arr.length
for(let i=0;i<length;i++){
let randomIndex = Math.floor(Math.random()*arr.length);
newArr[i]=arr[randomIndex]
arr.splice(randomIndex,1)
}
console.log(newArr)
複製代碼
call和apply的區別在於傳入參數的不一樣; 第一個參數都是,指定函數體內this的指向;
第二個參數開始不一樣,apply是傳入帶下標的集合,數組或者類數組,apply把它傳給函數做爲參數,call從第二個開始傳入的參數是不固定的,都會傳給函數做爲參數。
call比apply的性能要好,日常能夠多用call,
call傳入參數的格式正是內部所須要的格式,
閉包:函數 A 返回了一個函數 B,而且函數 B 中使用了函數 A 的變量,函數 B 就被稱爲閉包。
做用有:
封裝私有變量 模仿塊級做用域(ES5中沒有塊級做用域) 實現JS的模塊
function _new(fn, …arg) {
const obj = Object.create(fn.prototype);
const ret = fn.apply(obj, arg);
return ret instanceof Object ? ret : obj;
}
複製代碼
ECMAScript6是ES2015標準;
AMD規範:是 RequireJS在推廣過程當中對模塊定義的規範化產出的,
CMD規範:是SeaJS 在推廣過程當中對模塊定義的規範化產出的。 區別
CMD 推崇依賴就近;AMD 推崇依賴前置
CMD 是延遲執行;AMD 是提早執行
CMD性能好,由於只有用戶須要的時候才執行;AMD用戶體驗好,由於沒有延遲,依賴模塊提早執行了
垃圾回收是一種內存管理機制。咱們聲明一個變量和函數的時候都會佔用內存,可是內存容量有限,當一個變量離開執行環境的時候。考慮到它不會再使用的,就會被回收,釋放內存
方法:
內存泄漏是指計算機可用的內存愈來愈少,主要是由於程序不能釋放那些再也不使用的內存。
無心的全局變量、循環、定時器、回調
強緩存表示在緩存期間不須要請求,state code 爲 200 expires(本地過時時間)和cache-control(單位是秒,多少秒後過時),cache-control優於expires
若是緩存過時了,咱們就可使用協商緩存來解決問題。協商緩存須要請求,若是緩存有效會返回 304。
冒泡排序
重複遍歷全部的元素,兩個元素比較,若是大小順序不對,就交換它們的位置。重複遍歷直到沒有再須要交換,排序完成。
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { //相鄰元素兩兩對比
var temp = arr[j+1]; //元素交換
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
複製代碼
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { //尋找最小的數
minIndex = j; //將最小數的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
複製代碼
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for (var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while(preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex+1] = arr[preIndex];
preIndex--;
}
arr[preIndex+1] = current;
}
return arr;
}
複製代碼
function quickSort(arr, left, right) {
var len = arr.length,
partitionIndex,
left = typeof left != 'number' ? 0 : left,
right = typeof right != 'number' ? len - 1 : right;
if (left < right) {
partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex-1);
quickSort(arr, partitionIndex+1, right);
}
return arr;
}
function partition(arr, left ,right) { //分區操做
var pivot = left, //設定基準值(pivot)
index = pivot + 1;
for (var i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index-1;
}
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
複製代碼
實現繼承 主要是依靠原型鏈來實現的.
布爾值 let isDone: boolean = false;
數字
全部數字類型都是浮點數
let decLiteral: number = 6;
字符串
模版字符串也是這個類型
let name: string = "bob";
數組
元組
元組類型容許表示一個已知元素數量和類型的數組,各元素的類型沒必要相同。 好比,你能夠定義一對值分別爲 string和number類型的元組。
let x: [string, number];
枚舉enum
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
複製代碼
nerver
Object
Null 和 Undefined
Void
Any
var 和 let 用以聲明變量,const 用於聲明只讀的常量;
var 聲明的變量,不存在塊級做用域,在全局範圍內都有效,let 和 const 聲明的,只在它所在的代碼塊內有效;
let 和 const 不存在像 var 那樣的 「變量提高」 現象,因此 var 定義變量能夠先使用,後聲明,而 let 和 const 只可先聲明,後使用;
let 聲明的變量存在暫時性死區,即只要塊級做用域中存在 let,那麼它所聲明的變量就綁定了這個區域,再也不受外部的影響。
let 不容許在相同做用域內,重複聲明同一個變量;
const 在聲明時必須初始化賦值,一旦聲明,其聲明的值就不容許改變,更不容許重複聲明;
如 const 聲明瞭一個複合類型的常量,其存儲的是一個引用地址,不容許改變的是這個地址,而對象自己是可變的。
變量與內存之間的關係,主要由三個部分組成:
變量名
內存地址
內存空間
JS 引擎在讀取變量時,先找到變量綁定的內存地址,而後找到地址所指向的內存空間,最後讀取其中的內容。當變量改變時,JS 引擎不會用新值覆蓋以前舊值的內存空間(雖然從寫代碼的角度來看,確實像是被覆蓋掉了),而是從新分配一個新的內存空間來存儲新值,並將新的內存地址與變量進行綁定,JS 引擎會在合適的時機進行 GC,回收舊的內存空間。
const 定義變量(常量)後,變量名與內存地址之間創建了一種不可變的綁定關係,阻隔變量地址被改變,當 const 定義的變量進行從新賦值時,根據前面的論述,JS 引擎會嘗試從新分配新的內存空間,因此會被拒絕,便會拋出異常。
處理中文輸入,在input框綁定compositionsend,就能夠監聽中文輸入結束
簡化版
var request = new XMLHttpRequest();
request.open('GET', '/xxx');
request.onload = () => {console.log('請求成功'};
request.send();
複製代碼
詳細版
var request = new XMLHttpRequest();
request.open('GET', 'xxx');
request.onreadystatechange = function() {
if(request.readyState === 4 ) {
console.log('請求完成');
if(request.respondse.status >=200 && request.respondse.status) {
console.log('請求成功')
}else{
}
}
}
request.send();
複製代碼
經常使用:使用JSON.parse(JSON.stringify(obj))
原理是把一個對象序列化成爲一個JSON字符串,將對象的內容轉換成字符串的形式再保存在磁盤上,再用JSON.parse()反序列化將JSON字符串變成一個新的對象
缺點是: 會忽略undefined、symbol、funciton
實現:遞歸+判斷類型
一個簡單的代碼
// 數字 字符串 function是不須要拷貝的
function deepClone(value) {
if (value == null) return value;
if (typeof value !== 'object') return value;
if (value instanceof RegExp) return new RegExp(value);
if (value instanceof Date) return new Date(value);
// 我要判斷 value 是對象仍是數組 若是是對象 就產生對象 是數組就產生數組
let obj = new value.constructor;
for(let key in value){
obj[key] = deepClone(value[key]); // 看一看當前的值是否是一個對象
}
return obj;
}
複製代碼
function Promise(executor) {
let self = this;
self.status = 'pending'; //等待態
self.value = undefined; //成功的返回值
self.reason = undefined; //失敗的緣由
function resolve(value){
if(self.status === 'pending'){
self.status = 'resolved';
self.value = value;
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);// 捕獲時發生異常,就直接失敗
}
}
//onFufiled 成功的回調
//onRejected 失敗的回調
Promise.prototype.then = function (onFufiled, onRejected) {
let self = this;
if(self.status === 'resolved'){
onFufiled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = Promise;
複製代碼
window.onload--頁面上全部的DOM,樣式表,腳本,圖片都已經加載完成
document.onload/document.body.onload--僅當DOM加載完成,--也就是DOMContentLoaded的時間(打開devtools-network-DOMContentLoaded)
splice做用於數組,會修改原數組,有刪除或替換、添加的功能,返回被刪除的元素,若是沒有元素被刪除,返回空數組
var months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'June']
months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'May']
複製代碼
slice能夠做用於數組和字符串,不修改選數組,返回一個新數組
var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]
複製代碼