有元素可繼承:
visibility和cursor
內聯元素和塊級元素可繼承:
letter-spacing
word-spacing
white-space
line-height
color
font
font-family
font-size
font-style
font-variant
font-weight
text-decoration
text-transform
direction
塊級元素可繼承
:
text-indent和text-align
列表元素可繼承:
list-style
list-style-type
list-style-position
list-style-image
表格元素可繼承:
border-collapse
不可繼承:
display
margin
border
padding
background
height
min-height
max-height
width
min-width
max-width
overflow
position
left
right
top
bottom
z-index
float
clear
table-layout
vertical-align
page-break-after
page-bread-before
unicode-bidi
切圖網(qietu.com)專業從事web前端開發的公司,專注we前端開發,響應式布局,webapp手機端網頁制作,微信html5頁面制作,bootstrap布局等,關注用戶體驗。
現在用戶面前的WEB頁面,內容無非就是文字、圖片、視頻、音頻這四大方面。而這些內容要呈現在用戶眼前,最最基礎的一種互聯網語言,就是HTML(HyperText Markup Language)標記語言。所有千變萬化、眼花繚亂、酷炫精彩的內容,都離不開HTML標簽的汗馬功勞。下面小白就總結一下自學后的一些基礎的HTML知識點。
HTML中的標簽元素一般分為三大類,它們分別是:塊級元素、行內元素、行內塊級元素。下面總結一下這幾類元素的特點及應用。
01 塊級元素
特點:
① 獨占一行、從上到下排列
② 可直接控制寬度、高度及盒子模型的CSS屬性(width 、height、padding 等屬性值)
③ 在不單獨設置寬度的情況下,塊級元素的寬度(width屬性)繼承父元素
④ 在不單獨設置高度的情況下,塊級元素的高度(height屬性)靠自己的基因(它本身內容的高度)
塊級元素從我的理解來說,就是一個大框框,用來框住其它元素不要亂跑亂竄的,只能在一定范圍內活動。所以,它通常會用來進來大的結構搭建。
常用的塊級元素:
標題類 | <h1></h1> | <h2></h2> |
<h3></h3> | <h4></h4> | |
<h5></h5> | <h6></h6> | |
列表類 | <ol></ol> | <ul></ul> |
<li></li> | <dl></dl> | |
<dt></dt> | <dd></dd> | |
普通類 | <div></div> | <p></p> |
</hr> | <center></center> | |
<pre></pre> | ||
表格類 | <table></table> | |
表單類 | <form></form> |
02 行內元素
特點:
① 元素與元素之間會自動排列成一行,遇到空間不夠自動換行
② 默認高度和寬度(width、height)屬性與它們的內容有關,無內容那么它本身也就是虛無。
③ 行內元素不支持padding、margin的上下調動(它們就是緊挨著不離不棄、除非用外部手部強制拆散它們)
行內元素一般用來修飾點綴內容而用,語義化比較強,用來加強代碼的可讀性。
常用的行內元素:
<a></a> | <b></b> | <br></br> |
<span></span> | <strong></strong> | |
<i></i> | <em> </em> | <sub> </sub> |
<sup> </sup> |
03 行內塊元素
特點:
從這個名字就可以看出來,它是一個結合體,塊級元素和行內元素的結合體。它具備二者共有的一些特點,使用非常頻繁。
① 元素具有塊級元素的屬性(width、height等屬性),可以對其直接控制
② 雖然有寬和高,但是他并不會霸道地獨占一行,它具有行內元素的“親情屬性”,會自動排列挨在一起。
③ 行內塊元素支持padding、margin的上下調動
<img> </img> | <input /> | <select> </select> |
<textarea> </textarea> | <label> </label> | <button> </button> |
歡迎大佬提點指正
JavaScript 在編程語言界是個特殊種類,它和其他編程語言很不一樣,JavaScript 可以在運行的時候動態地改變某個變量的類型。
比如你永遠也沒法想到像isTimeout這樣一個變量可以存在多少種類型,除了布爾值true和false,它還可能是undefined、1和0、一個時間戳,甚至一個對象。
如果代碼跑異常,打開瀏覽器,開始斷點調試,發現InfoList這個變量第一次被賦值的時候是個數組:
[{name: 'test1', value: '11'}, {name: 'test2', value: '22'}]
過了一會竟然變成了一個對象:
{test1:'11', test2: '22'}
除了變量可以在運行時被賦值為任何類型以外,JavaScript 中也能實現繼承,但它不像 Java、C++、C# 這些編程語言一樣基于類來實現繼承,而是基于原型進行繼承。
這是因為 JavaScript 中有個特殊的存在:對象。每個對象還都擁有一個原型對象,并可以從中繼承方法和屬性。
提到對象和原型,有如下問題:
在 JavaScript 中,對象由一組或多組的屬性和值組成:
{
key1: value1,
key2: value2,
key3: value3,
}
在 JavaScript 中,對象的用途很是廣泛,因為它的值既可以是原始類型(number、string、boolean、null、undefined、bigint和symbol),還可以是對象和函數。
不管是對象,還是函數和數組,它們都是Object的實例,也就是說在 JavaScript 中,除了原始類型以外,其余都是對象。
這也就解答了問題1:JavaScript 的函數怎么也是個對象?
在 JavaScript 中,函數也是一種特殊的對象,它同樣擁有屬性和值。所有的函數會有一個特別的屬性prototype,該屬性的值是一個對象,這個對象便是我們常說的“原型對象”。
我們可以在控制臺打印一下這個屬性:
function Person(name) {
this.name = name;
}
console.log(Person.prototype);
打印結果顯示為:
可以看到,該原型對象有兩個屬性:constructor和proto。
到這里,我們仿佛看到疑惑 “2:proto和prototype到底是啥關系?”的答案要出現了。在 JavaScript 中,proto屬性指向對象的原型對象,對于函數來說,它的原型對象便是prototype。函數的原型對象prototype有以下特點:
我們可以用這樣一張圖來描述prototype、proto和constructor三個屬性的關系:
從這個圖中,我們可以找到這樣的關系:
對象之所以使用廣泛,是因為對象的屬性值可以為任意類型。因此,屬性的值同樣可以為另外一個對象,這意味著 JavaScript 可以這么做:通過將對象 A 的proto屬性賦值為對象 B,即:
A.__proto__ = B
此時使用A.proto便可以訪問 B 的屬性和方法。
這樣,JavaScript 可以在兩個對象之間創建一個關聯,使得一個對象可以訪問另一個對象的屬性和方法,從而實現了繼承;
以Person為例,當我們使用new Person()創建對象時,JavaScript 就會創建構造函數Person的實例,比如這里我們創建了一個叫“zhangsan”的Person:
var zhangsan = new Person("zhangsan");
上述這段代碼在運行時,JavaScript 引擎通過將Person的原型對象prototype賦值給實例對象zhangsan的proto屬性,實現了zhangsan對Person的繼承,即執行了以下代碼:
//JavaScript 引擎執行了以下代碼
var zhangsan = {};
zhangsan.__proto__ = Person.prototype;
Person.call(zhangsan, "zhangsan");
我們來打印一下zhangsan實例:
console.log(zhangsan)
結果如下圖所示:
可以看到,zhangsan作為Person的實例對象,它的proto指向了Person的原型對象,即Person.prototype。
這時,我們再補充下上圖中的關系:
從這幅圖中,我們可以清晰地看到構造函數和constructor屬性、原型對象(prototype)和proto、實例對象之間的關系,這是很多容易混淆。根據這張圖,我們可以得到以下的關系:
那么現在,關于proto和prototype的關系,我們可以得到這樣的答案:
所以一個對象可通過proto訪問原型對象上的屬性和方法,而該原型同樣也可通過proto訪問它的原型對象,這樣我們就在實例和原型之間構造了一條原型鏈。紅色線條所示:
當 JavaScript 試圖訪問一個對象的屬性時,會基于原型鏈進行查找。查找的過程是這樣的:
我們可以通過一個具體的例子,來表示基于原型鏈的對象屬性的訪問過程,在該例子中我們構建了一條對象的原型鏈,并進行屬性值的訪問:
var o = {a: 1, b: 2}; // 讓我們假設我們有一個對象 o, 其有自己的屬性 a 和 b:
o.__proto__ = {b: 3, c: 4}; // o 的原型 o.__proto__有屬性 b 和 c:
當我們在獲取屬性值的時候,就會觸發原型鏈的查找:
console.log(o.a); // o.a => 1
console.log(o.b); // o.b => 2
console.log(o.c); // o.c => o.__proto__.c => 4
console.log(o.d); // o.c => o.__proto__.d => o.__proto__.__proto__ == null => undefined
綜上,整個原型鏈如下:
{a:1, b:2} ---> {b:3, c:4} ---> null, // 這就是原型鏈的末尾,即 null
可以看到,當我們對對象進行屬性值的獲取時,會觸發該對象的原型鏈查找過程。
既然 JavaScript 中會通過遍歷原型鏈來訪問對象的屬性,那么我們可以通過原型鏈的方式進行繼承。
也就是說,可以通過原型鏈去訪問原型對象上的屬性和方法,我們不需要在創建對象的時候給該對象重新賦值/添加方法。比如,我們調用lily.toString()時,JavaScript 引擎會進行以下操作:
由于通過原型鏈進行屬性的查找,需要層層遍歷各個原型對象,此時可能會帶來性能問題:
因此,我們在設計對象的時候,需要注意代碼中原型鏈的長度。當原型鏈過長時,可以選擇進行分解,來避免可能帶來的性能問題。
除了通過原型鏈的方式實現 JavaScript 繼承,JavaScript 中實現繼承的方式還包括經典繼承(盜用構造函數)、組合繼承、原型式繼承、寄生式繼承,等等。
function Parent(name) {
// 私有屬性,不共享
this.name = name;
}
// 需要復用、共享的方法定義在父類原型上
Parent.prototype.speak = function() {
console.log("hello");
};
function Child(name) {
Parent.call(this, name);
}
// 繼承方法
Child.prototype = new Parent();
組合繼承模式通過將共享屬性定義在父類原型上、將私有屬性通過構造函數賦值的方式,實現了按需共享對象和方法,是 JavaScript 中最常用的繼承模式。
雖然在繼承的實現方式上有很多種,但實際上都離不開原型對象和原型鏈的內容,因此掌握proto和prototype、對象的繼承等這些知識,是我們實現各種繼承方式的前提條件。
關于 JavaScript 的原型和繼承,常常會在我們面試題中出現。隨著 ES6/ES7 等新語法糖的出現,可能更傾向于使用class/extends等語法來編寫代碼,原型繼承等概念逐漸變淡。
其次JavaScript 的設計在本質上依然沒有變化,依然是基于原型來實現繼承的。如果不了解這些內容,可能在我們遇到一些超出自己認知范圍的內容時,很容易束手無策。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。