一、JS的基本數據類型和引用數據類型有哪些,二者區別javascript
基本數據類型->string、number、Boolean、null、undefined、symbolcss
引用數據類型->array、object、functionhtml
基本數據類型是保存在棧內存中,操做的是值,改變源數據不會影響新的變量java
引用數據類型保存在堆內存中,操做的是地址,改變其中一個會影響另外一個node
二、數據類型中爲假的有哪些?jquery
false (布爾型)es6
0(數值型)ajax
null(定義空的或者不存在,如今沒有,未來可能有)正則表達式
undefined(未定義,一直不存在)express
NaN(不是一個有效數字)
空字符串(空字符串,字符類型)
三、舉例JavaScript的基本規範,以及如何編寫高性能代碼
基本規範
1)代碼縮進,建議使用「四個空格」縮進
2)語句結束使用分號
3)變量和函數在使用前進行聲明
4)以大寫字母開頭命名構造函數,全大寫命名常量
5)使用ID最好先獲取一下
6)規範定義JSON對象,補全雙引號
1)遵循嚴格模式:"use strict";
2)將js腳本放在頁面底部,加快渲染頁面
3)儘可能減小使用閉包
4)儘可能使用直接量建立對象和數組
5)儘可能減小對象成員嵌套
6)最小化重繪(repaint)和迴流(reflow)
四、JS有哪些內置對象
Object、Array、Boolean、Number、String、Function、Arguments、Math、Date、RegExp
ES6新增對象:Symbol、Map、Set、Promises、Proxy
五、怎麼實現string和number的相互轉換
String 轉換成 Number:Number()、parseInt()、parseFloat()
Number 轉換成 String:String()、toString()
六、怎麼建立、添加、替換、克隆、刪除元素
建立-> document.createElement('標籤名')
添加-> parent.appendChild()
parent.insertBefore(新插入的元素,老元素)
替換-> replaceChild(new,old)
克隆-> cloneChild()
刪除->removeChild()
七、什麼狀況下會轉爲字符串
1)基於alert、confirm、document.write等輸出內容時,會先把值轉爲字符串後在輸出
2)基於'+'進行字符串拼接時
3)把複合類型值轉換數字時候。首先會轉換字符串而後再轉爲數字
4)給對象設置屬性名時候,若是不是字符串 先轉爲字符串,而後在做爲屬性存儲到對象中(對象屬性只能是字符串和數字)
5)手動調用toString、toFixed(將 Number 四捨五入爲指定小數位數的數字)、join、String方法時候,也是爲了轉換字符串
八、獲取對象屬性[]和.的區別
.後面的是這個對象的屬性,凡是用.的地方均可以用[]
[]中括號的內容能夠是字符串也能夠是變量,基本上[]放的是變量
九、null和undefined的區別
Null:表明空對象指針。如今沒有,未來可能會有
undefined:空,未定義。如今沒有,未來也不會有(Js中獨有的數據類型)
十、檢測數據類型的幾種方式,以及他們的對比
typeof、instanceof、constructor、Object.prototype.toString.call()
typeof只針對基本數據類型,遇到引用數據類型是不起做用的(沒法細分對象)
instanceof用來判斷對象和函數,不適合判斷字符串和數字
constructor是Object其中的一個屬性。默認指向實例的構造函數
經過Object.prototype.toString方法,判斷某個對象值屬於哪一種內置類型
十一、in 與 hasOwnProperty
二者都表明查看某個屬性是否是本身的
in判斷的是對象的全部屬性,包括對象實例及其原型的屬性
hasOwnProperty則是判斷對象實例的是否具備某個屬性
十二、innerHTML和innerText區別
innerHTML能夠獲取結構和文本
innerText只獲取文本內容
1三、如何清除一個定時器?
clearTimeout(timer)
1四、說一下倒計時原理及公式
將來時間-如今時間= 剩餘時間
let d = Math.floor(t/86400); t % =86400; let h = Math.floor(t/3600); t % = 3600; let m = Math.floor(t/60); t % = 60;
1五、什麼時候使用 === 什麼時候使用 ==
判斷對象的屬性是否存在可使用雙等,其他都用全等
===更嚴謹,不只值相等類型也要相等,不用進行類型轉換,而且比==速度快
1六、eval 是作什麼的?
它的功能是把對應的字符串解析成JS代碼並運行
由JSON字符串轉換爲JSON對象的時候能夠用 eval('('+ str +')');
應避免使用eval,由於不安全,耗性能
1七、數組經常使用的一些方法有哪些
push()向數組末尾添加數據
pop()刪除數組最後一項
unshift()向數組首位添加新內容
shift()刪除數組的第一項
slice()按照條件查找出其中的部份內容
splice()對數組進行增刪改
join()用指定的分隔符對數組拼接
concat()用於鏈接兩個或多個數組
indexOf()/lastIndexOf()當前值在數組中第一次/最後一次出現的位置索引
includes()判斷一個數組是否包含指定的值
sort()對數組進行排序
reverse()把數組倒過來排列
forEach()循環遍歷數組每一項
1八、說一下什麼是DOM映射機制
經過DOM中方法獲取到的元素,與頁面一一對應的這種關係稱之爲DOM映射
querySelectorAll獲取到的元素集合沒有DOM映射,必須是元素的內置屬性發生變化,瀏覽器才能監聽獲得
1九、一行代碼實現數組去重
[...new Set([1,2,3,4])]
20、節點類型都有哪些,如何判斷當前節點類型
1元素節點,2屬性節點,3文本節點,8註釋節點、9文檔節點
經過nodeObject.nodeType判斷節點類型,其中,nodeObject爲節點對象
該屬性返回以數字表示的節點類型,例如,元素節點返回1,屬性節點返回2
2一、重繪和迴流(重排)區別,什麼狀況會觸發重排和重繪
當頁面元素(寬高,位置)發生改變,回致使頁面重排,瀏覽器會根據新位置進行從新渲染
迴流必將引發重繪,而重繪不必定會引發迴流。重繪相對於迴流性能消耗較低
任何改變用來構建渲染樹的信息都會致使一次重排或重繪
好比添加、刪除、更新DOM節點,經過display: none隱藏,調整樣式屬性,調整窗口大小,滾動等等
2二、如何最小化重繪(repaint)和迴流(reflow)
1)須要對元素進行復雜的操做時,能夠先display:none隱藏,操做完再顯示
2)須要建立多個DOM節點時,使用DocumentFragment建立完後一次性的加入document
3)儘可能避免用table佈局
4)避免使用css表達式(expression),每次調用都會從新計算值(包括加載頁面)
5)儘可能使用css簡寫,如:用border代替border-width,border-style, border-color
2三、什麼是自執行函數,用於什麼場景
自執行函數,即定義和調用合爲一體,好比匿名函數自執行
他能夠建立一個獨立做用域,防止做用域污染,防止變量影響到全局,以避免產生衝突
多用於框架和插件
2四、改變this指向的方法
call、apply、bind
call和apply能夠自動執行,bind須要手動調用,返回值爲函數
call和bind都有無數個參數,apply只有兩個參數,而且第二個爲數組
2五、iframe的優缺點
優勢:
1)iframe可以原封不動的把嵌入的網頁展示出來
2)頭部和底部同樣時能夠寫成一個頁面,用iframe來嵌套,能夠增長代碼的可重用
3)引用多個頁面,只須要修改iframe的內容,就能夠實現頁面內容的更改
缺點:
不容易管理、用戶體驗度差、不利於搜索引擎優化、兼容性差、增長服務器的http請求,通常用Ajax來代替iframe
2六、類數組轉數組的方法
Array.from
Array.prototype.slice.call
[].slice.call
2七、請解釋什麼是暫時性死區
let 和 const 聲明的變量不存在變量提高,其做用域都是塊級做用域,凡是在聲明變量以前使用變量就會報錯,
因此,在代碼塊內,使用let命令聲明變量以前,該變量都是不可用的。這在語法上,稱爲「暫時性死區」
2八、嚴格模式與非嚴格模式的區別
非嚴格模式又被被稱爲懶散模式
嚴格模式 use strict是一種ECMAscript 5添加的運行模式,這種模式使得 Js在更嚴格的條件下運行,使JS編碼更加規範化
消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲。
嚴格模式中變量必須顯示聲明
在嚴格模式下,arguments和eval是關鍵字,不能被修改
在嚴格模式下,函數的形參也不能夠同名
2九、驗證手機號碼和郵箱的正則表達式
手機號碼驗證
/^(13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[8-9])[0-9]{8}$/
郵箱驗證
^[A-Za-z]\w{3,17}@[1-9A-Za-z]{2,8}\.(com|cn|net)$
30、window 和document常見的方法和屬性
Window對象常見的屬性:
top 表明當前全部窗口的最頂層窗口
parent 指當前窗口的父窗口
self 指當前窗口
status 指定當前窗口狀態欄中的信息
Window對象常見的方法:
alert 顯示帶有一個「肯定」按鈕的對話框
confirm 顯示帶有「肯定」和「取消」兩個按鈕的對話框
open 打開一個新的窗口
close 關閉用戶打開的窗口
Document常見屬性:
title 設置文檔標題,也就是html的標籤
bgColor 設置頁面的背景色
URL 設置url屬性
fileSize 文件大小
Document常見的方法:
write() 動態向頁面寫入內容
createElement(Tag) 建立一個HTML標籤
getElementById(ID) 得到指定id的對象
getElementsByName(Name) 得到以前Name的對象
3一、如何添加HTML元素的事件,有幾種方法
標籤之中直接添加 onclick="fn()"
JS添加 btn.onclick = method
綁定事件 obj.addEventListener('click', method, false)
3二、使用js去除字符串空格
str.trim()
使用replace正則匹配:str.replace(/\s*/g,"")
3三、什麼是閉包,有什麼優缺點
在Js中當函數套函數,子函數使用了父函數的參數或者變量,而且子函數被外界所使用(沒有釋放),
此時父函數的參數和變量,是不會被瀏覽器垃圾回收機制立馬收回,這個時候父級造成了閉包環境。
function fn(){ let a = 10; return function(){ console.log(a); } } let f = fn(); console.dir(f);// 控制檯中的closure就表明閉包
優勢:
保護—閉包會造成私有做用域,保護裏面的私有變量不受外界干擾
存儲—閉包能夠把父函數的參數或變量存儲起來
缺點:
相對於普通函數要消耗內存,閉包使用不當將會在IE(IE9以前)中形成內存泄漏
3四、理解的JavaScript垃圾回收機制
Js具備自動垃圾回收機制。垃圾收集器會按照固定的時間間隔週期性的執行
垃圾回收機制主要有兩種方法:
一、標記清除法
打開頁面時,先把全部的變量打上標記,而後把被使用的變量清除標記。若是下次查詢以前標記的沒有被引用,此時就回收
二、引用計數法
變量每用一次就記錄一次,一開始爲0,下次引用+1,每少用一次就-1。當變爲0時候 就清空回收
直接給變量賦值一個null的地址能夠解決閉包消耗的內存
3五、什麼狀況會引發內存泄漏,產生緣由及解決方案?
1)意外的全局變量引發的內存泄漏
緣由:全局變量,不會被回收
解決:可使用嚴格模式避免
2)閉包引發的內存泄漏
緣由:閉包能夠維持函數內局部變量,使其得不到釋放
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用
3)沒有清理的DOM元素引用
緣由:雖然別的地方刪除了,可是對象中還存在對dom的引用
解決:手動刪除便可
4) 忘記的定時器或者回調
緣由:定時器中有dom的引用,即便dom刪除了,可是定時器還在
解決:手動清除定時器和dom
3六、什麼是原型,什麼是原型鏈,二者關係
原型(prototype):函數自帶的屬性,函數的實例化對象找不到某個屬性或者方法,必定會去構造函數的原型下去找
原型鏈(__proto__):實例化對象身上自帶一個屬性
原型關係鏈:函數的實例化對象找不到某個屬性或方法,必定會去構造函數的原型下去找,若是尚未會去原型下的原型鏈查找,直到找到Object.prototype爲止
二者關係:實例化對象的原型鏈 === 構造函數的原型
3七、如何合併兩個數組
//第一種 var arr1=[1,2,3]; var arr2=[4,5,6]; arr1 = arr1.concat(arr2); console.log(arr1); //第二種 var arr1=[1,2,3]; ar arr2=[4,5,6]; Array.prototype.push.apply(arr1,arr2); console.log(arr1);
3八、簡述this出現的狀況
1)全局下的this是window
2)單純的函數名+括號執行,this是window
3)匿名函數自執行,this是window
4)定時器中的this是window
5)事件觸發,觸發誰this就是誰
6)對象方法中,.前面是誰 this就指向誰
7)構造函數中this是實例化對象
8)嚴格模式下this是undefined
9)箭頭函數中this指向上一級
10)箭頭函數中this暴露在外面就指向window
3九、函數聲明和函數表達式的區別
fn() //不會報錯 function fn(){ //聲明 } fn1() //會報錯:fn1 is not a function var a = function(){ //表達式 }
40、說一下對變量提高的理解
在某一做用域中,聲明變量的語句會默認解析,在該做用域的最開始就已經聲明瞭
4一、Js有哪些解決異步的方案
1)callback 回調函數
2)promise
3)事件監聽
4)async await
4二、new以後發生了什麼
使用new以後不用加括號同樣會執行函數
new以後this變爲實例化對象
默認返回值就不是undefined而是實例化對象
寫了return,若是return後面是簡單類型,返回結果依然是實例化對象,若是是複合類型,返回結果則是這個複合類型
4三、寫一個原生的xhr請求過程,readystate的幾種狀態 分別什麼含義?
let xhr = new XMLHttpRequest(); xhr.open('get','./package.json'); xhr.onreadystatechange = function () { if(xhr.readyState == 4 && xhr.status == 200) { let result = JSON.parse(xhr.responseText); console.log(result.name) } }; xhr.send()
readyState的幾種狀態
0:請求未初始化(此時尚未調用open)
1:服務器鏈接已創建,已經發送請求開始監聽
2:請求已接收,已經收到服務器返回的內容
3:請求處理中,解析服務器響應內容
4:請求已完成,且響應就緒
4四、什麼是做用域、做用域鏈
做用域分爲全局做用域、局部做用域(包括es6新增塊級做用域)
簡單理解做用域就是一個獨立的空間,讓變量不會暴露。不一樣做用域下同名變量不會衝突
當前做用域未定義的變量(自由變量)會向父級做用域查找,若是父級沒有再一層層往上找,直到全局做用域,這種一層層的關係稱爲做用域鏈
4五、淺拷貝和深拷貝,實現的幾種方式
淺拷貝只複製某個對象的指針,而不復制對象自己,新舊對象仍是共享同一塊內存
深拷貝會開闢一個新的棧,新對象跟原對象不共享內存,修改新對象不影響原對象
簡單來講假如B複製了A,當修改A時候B若是跟着改變就是淺拷貝,B沒有改變則爲深拷貝
淺拷貝實現方式:
Object.assign()、Array.prototype.concat()、Array.prototype.slice()
深拷貝實現方式:
JSON.parse(JSON.stringify())、手寫遞歸、jquery的$.extend
4六、聲明變量和聲明函數的提高有什麼區別
變量聲明提高:變量申明在進入執行上下文就完成了
只要變量進行聲明,不管在哪一個位置,js引擎都會將它的聲明放在做用域的頂部
函數聲明提高:執行代碼以前會先讀取函數聲明,能夠把函數申明放在調用它的語句後面
函數聲明會覆蓋變量聲明,但不會覆蓋變量賦值
4七、說一下變量提高機制
關於變量提高:
不管條件成不成立都會先進行預解析
匿名函數不會預解析
es6不存在變量提高
預解析的函數只解析一次(再遇到就會跳過)
變量提高機制:
1、變量提高
1)先找var進行提高,賦值undefined,變量名同樣,後者覆蓋前者
2)碰見函數,把函數名提高,賦值整個代碼塊
函數名同名,後者覆蓋前面,只看最後一個函數便可
3)變量名與函數名同名狀況下,最終留下代碼塊
若是是函數聲明,就只解讀一次,遇到別的直接跳過
函數表達式是帶等號的因此會解讀
2、逐行解讀代碼
只看帶有等號的,若是有賦值,這個變量就是被賦值的值
就算下面有函數聲明也不會繼續看了
4八、平時怎麼樣進行數據交互?若是後臺沒有提供數據怎麼進行開發?mock數據與後臺返回的格式不統一怎麼辦?
由後臺編寫接口文檔、提供數據接口實、前臺經過ajax訪問實現數據交互;
在沒有數據的狀況下尋找後臺提供靜態數據或者本身定義mock數據
返回數據不統一時編寫映射文件 對數據進行映射
4九、什麼是回調函數
回調函數callback,就是一個函數執行完後馬上執行另外一個
它與箭頭函數不同的是,它會拿返回的值做爲參數
50、什麼是構造函數?與普通函數有什麼區別
構造函數:是一種特殊的方法、主要用來建立對象時初始化對象,總與new運算符一塊兒使用。建立對象的語句中構造函數的函數名必須與類名徹底相同
與普通函數相比只能由new關鍵字調用,構造函數是類的標示
5一、ajax 和 jsonp區別
相同點:都是請求一個url
不一樣點:ajax的核心是經過xmlHttpRequest獲取內容
jsonp的核心則是動態添加<script>標籤來調用服務器 提供的js腳本
5二、JavaScript 有哪幾種建立對象的方式?
1)對象字面量的方式
2)用function來模擬無參的構造函數
3)用工廠方式來建立(內置對象)
4)用原型方式來建立
5三、舉例ES5數組新增的哪些方法
1)forEach() 專門用來遍歷數組
2)map() 將調用的數組中每一個元素傳遞給指定的函數,並返回一個新數組
3)filter() 過濾,返回知足條件的元素組成的新數組
4)every()全部元素知足條件就返回true,有一個不知足條件就返回false
5)some()全部元素只要有一個知足條件就返回true,都不知足條件就返回false
6)reduce()累加器,數組中的每一個值(從左到右)開始縮減,最終計算爲一個值
5四、獲取隨機數,要求是長度一致的字符串格式
var random = Math.random() + '0000000000'; var random = random.slice(0,10);
5五、移動端點擊事件300ms延遲如何去掉,產生緣由
產生緣由:
移動端會有雙擊縮放的這個操做,所以瀏覽器在click以後要等待300ms,看用戶有沒有下一次點擊(也就是此次操做是否是雙擊)
解決方法:
1)禁用縮放
<meta name="viewport" content="user-scalable=no"> <meta name="viewport" content="initial-scale=1,maximum-scale=1">
2)更改默認的視口寬度
<meta name="viewport" content="width=device-width"/>
3)使用fastClick插件
window.addEventListener( "load", function() { FastClick.attach( document.body ); }, false );
5六、let有什麼用,有了var爲何還要用let ?
ES6以前,聲明變量只能用var,他有一些不合理的地方。
let聲明的變量擁有本身的塊級做用域,且修復了var聲明變量帶來的變量提高問題
5七、請描述一下對事件冒泡、事件捕獲、事件流的理解,怎麼阻止冒泡
事件冒泡:就是從目標元素自下而上一直到window(結束)這樣一個過程
事件捕獲:就是從window自上而下一直到目標元素的這樣一個過程
通常是先執行捕獲,後執行冒泡
事件流:當一個事件觸發時候,通常會經歷3個過程,第一個爲捕獲階段,第二個爲目標階段,第三個爲冒泡階段這麼一個過程
使用stopPropagation() 和 cancelBubble阻止冒泡
5八、什麼是事件委託,有什麼好處
事件委託又叫事件代理。利用冒泡的原理,把事件加到父級上,觸發執行效果
好處:新添加的元素還會有以前的事件;提升性能
5九、拖拽會用到哪些事件?
使用onmousedown、onmousemove、onmouseup來實現
60、什麼是移動端點透事件,如何解決
一個元素下有焦點(好比a 、input)在300毫秒以內讓上層元素消失,這時手機會記錄按下的位置並進行監聽(是否觸發兩次)
由於要監聽是否雙擊,在第一次按下時捕捉到了座標,正好座標下有焦點元素,此時就會觸發焦點元素
解決方案:
一、在上層元素消失時候延遲執行
二、不使用焦點元素。好比以div代替a
三、在touch事件裏面調用e.preventDefault() 進行阻止
6一、簡述一下你理解的面向對象
把相同的代碼抽象出來歸爲一類,把描述特徵的功能掛在這個類的原型上的一種設計編程思想
面向對象具備封裝性,繼承性,多態性。提升了大型程序的重用性和可維護性
6二、如何獲取hash,並設置一個hash
window.location.hash
window.location.hash = 'p=0';
6三、js延遲加載的方式有哪些
defer和async、動態建立DOM方式、按需異步載入js
6四、什麼是事件默認行爲,如何阻止
當用戶觸發某個事件的時候,某種行爲不是咱們主動寫的而是瀏覽器默認就有的事件
阻止:
DOME0:return false
DOME1:ev.preventDefault
6五、列舉js經常使用的事件
onmouseover鼠標移入、onmouseout鼠標移出
onmouseenter鼠標穿過、onmouseleave鼠標離開
onmousemove鼠標移動、onmousewheel 鼠標滾輪
onclick點擊、oncontextmenu右擊菜單
onchange改變內容、onfocus獲取焦點、onblur失去焦點
onresize改變窗口、onload加載完成
onkeyup鍵盤擡起、onkeydown鍵盤按下
6六、構造函數、原型對象、實例對象三者的關係
三者的關係是,每一個構造函數都有一個原型對象,原型對象上包含着一個指向構造函數的指針,而實例都包含着一個指向原型對象的內部指針。
通俗的說,實例能夠經過內部指針訪問到原型對象,原型對象能夠經過constructor找到構造函數
6七、Js中,有一個函數,執行對象查找時,永遠不會去查找原型,這個函數是哪一個
hasOwnProperty
該函數方法返回一個布爾值,指出一個對象是否具備指定名稱的屬性。此方法沒法檢查該對象的原型鏈中是否具備該屬性;該屬性必須是對象自己的一個成員
6八、Canvas和SVG的比較
canvas是一個標籤(canvas)+一個對象(getcontext),全部圖形圖像都靠ctx繪製
SVG幾十個標籤-每一個圖形對應一個標籤
canvas位圖技術,能夠保存爲.png,SVG矢量圖技術,不能保存爲位圖
canvas不能被搜索引擎爬蟲所訪問,SVG能夠
只能爲整個Canvas綁定監聽函數,SVG每一個圖形(標籤)均可以綁定事件監聽函數
6九、如何規避javascript多人開發函數重名問題
(1) 能夠開發前規定命名規範,根據不一樣開發人員開發的功能在函數前加前綴
(2) 將每一個開發人員的函數封裝到類中,調用的時候就調用類的函數,即便函數重名只要類名不重複便可
70、Cookie、Session、WebStorage的區別
cookie:用來保存客戶瀏覽器請求服務器頁面的請求信息,大小4KB
session:是一種服務器端的機制,服務器使用一種相似於散列表的結構來保存信息
WebStorage提供了localStorage、sessionStorage兩種API,大小都在5M
cookie數據存放在客戶的瀏覽器上,session數據放在服務器上
cookie不是很安全,別人能夠分析存放在本地的cookie
session會在必定時間內保存在服務器上。當訪問增多,會佔用服務器的性能
cookie:能夠經過expires設置失效時間,不設置默認關閉瀏覽器即失效
localStorage:除非手動清除,不然永久保存
sessionStorage:僅在當前會話時候生效,關閉頁面即失效
7一、什麼是柯里化函數
柯里化(Currying)就是把接收多個參數的函數轉換成一個單個參數的函數
而且返回接收餘下的參數。返回結果是一個新函數
函數柯里化的主要做用和特色是參數複用、提早返回和延遲執行
7二、如何理解防抖和節流
防抖:短期內連續觸發的事件,在某個時間期限內事件函數只執行一次
節流:若是短期內大量觸發同一事件,在函數執行一次以後,在指定的時間期限內再也不工做,直至過了這段時間才從新生效
7三、什麼是單例模式,什麼是工廠模式
單例模式:把描述同一個事物的屬性和方法放在一個內存空間下,起到分組的做用
這樣不一樣事物之間的屬性即便同名也不會衝突。單例模式實例化出來的對象是惟一的
工廠模式:把相同代碼封裝起來,實現批量生產目的的一種模式。減小冗餘代碼
7四、舉例幾種經常使用的Object方法
Object.assign()、Object.create()
Object.defineProperty、Object.prototype.hasOwnProperty
7五、js實現繼承的幾種方式
1)類式(call)繼承
2)拷貝繼承
3)原型繼承
4)寄生組合式繼承
5)es6中class繼承