整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          第42節(jié) Element元素節(jié)點-Javascrip

          第42節(jié) Element元素節(jié)點-Javascript-王唯

          內(nèi)容是《Web前端開發(fā)之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學(xué)習(xí)。

          Element類型用于表示XML或HTML元素,提供了對元素標(biāo)簽名、子節(jié)點及特性的訪問;

          Element類繼承自Node接口;它繼承了Node接口中的所有屬性和方法,比如parentNode、childNode等;同時,它在Node接口的基礎(chǔ)上擴展了自己的屬性和方法;

          Element類型的特征:

          • nodeType值為1;
          • nodeName的值為元素的標(biāo)簽名;
          • nodeValue的值為null;
          • parentNode可能是Document或Element;
          • 其子節(jié)點可能是Element、Text,Comment、ProcessingInstruction、CATASection或EntityReference;
          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.nodeType);  // 1
          console.log(mydiv.nodeName);  // DIV
          console.log(mydiv.nodeValue);  // null
          console.log(mydiv.parentNode);  // <body>
          console.log(mydiv.childNodes);  // NodeList

          Element的屬性:

          id屬性:表示元素的標(biāo)識符,與全局屬性id對應(yīng);

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.id);
          mydiv.id="yourdiv";
          console.log(mydiv.id);
          var yourdiv=document.getElementById("yourdiv");
          console.log(yourdiv.id);

          tagName屬性:與nodeName屬性一樣,可以返回元素的標(biāo)簽名,在HTML文檔中返回大寫,在XML中返回原生,因此在使用tagName時,最后使用toLowerCase()轉(zhuǎn)換;

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.tagName);  // DIV
          if(mydiv.tagName.toLowerCase()=="div"){
              //...
          }

          一般使用tagName,因為從字義上理解更加清晰;

          Element的子類型HTMLElement:

          HTMLElement類型直接繼承自Element,因此,HTML元素即屬于HTMLElement類也屬于Element類;

          所有HTML元素都由HTMLElement類型或其子類型表示,比如:HTMLDIVElement,就是具體的div元素的類型;

          HTMLElement類型在Element類的基礎(chǔ)上,并添加了一些屬性,這些屬性分別對應(yīng)于每個HTML元素中都存在的標(biāo)準(zhǔn)特性:id、title、lang、dir、className;

          這些屬性都是可讀可寫的,并且也是動態(tài)的;

          <div id="mydiv" name="mydiv" title="DIV" lang="en" dir="ltr" class="divclass">
          // …
          <script>
          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.id);
          console.log(mydiv.title);
          console.log(mydiv.lang);
          console.log(mydiv.dir);
          console.log(mydiv.className);
          mydiv.id="yourdiv";
          mydiv.title="你的DIV";
          mydiv.lang="fr";
          mydiv.dir="rtl";
          mydiv.className="reddiv";
          </script>

          Element特性(屬性):

          每個元素都有若干個特性,這些特性的用途是給出相應(yīng)元素或其內(nèi)容的附加信息;DOM為Element對象定義了一些API來獲取或設(shè)置這些XML或HTML屬性(特性);

          操作特性主要有三個方法:

          getAttribute()、setAttribute()、removeAttribute();這些方法可以針對任何特性使用,包括那些以HTMLElement類型屬性的形式定義的特性;

          getAttribute(attributeName)方法:

          返回元素上一個指定的特性值,如果指定的特性不存在,則返回null或 "";特性的名稱不區(qū)分大小寫;

          如果取得class,需要傳入class,而不是className;

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.getAttribute("id"));  // mydiv
          console.log(mydiv.getAttribute("class"));  // divclass
          console.log(mydiv.getAttribute("title"));  // null

          也可以取得自定義特性(即不是HTML元素的標(biāo)準(zhǔn)特性),但要注意,根據(jù)HTML5的規(guī)范,自定義特性應(yīng)該加上data-前綴以便驗證;

          console.log(mydiv.getAttribute("custom"));  // customvalue
          console.log(mydiv.getAttribute("data-name"));  // wangwei

          任何元素的所有特性,都可以通過DOM元素本身的屬性來訪問,不過,只有公認(rèn)的(非自定義)特性才會以屬性的形式添加到DOM對象中;但IE可以為自定義特性創(chuàng)建屬性;

          console.log(mydiv.id);
          console.log(mydiv.className);
          console.log(mydiv.myname);  // undefined
          console.log(mydiv.align);  // left,認(rèn)為align是公認(rèn)的
          var img=document.getElementById("myimg");
          var imgurl=img.src;
          console.log(img.id==="myimg");
          var f=document.forms[0];
          f.action="https://www.zeronetwork.cn/do.php";
          f.method="POST";

          HTML屬性名不區(qū)分大小寫,但Javascript屬性名則大小寫敏感;從HTML屬性名轉(zhuǎn)換到Javascript屬性名應(yīng)該采用小寫,但是如果屬性名包含不止一個單詞,則采用小駝峰式,如:defaultCheded和tabIndex;

          有些HTML屬性名在Javascript中是保留字,對于這些屬性,一般的規(guī)則是為該屬性名加前綴”html”,如,HTML的for屬性在Javascript中變?yōu)閔tmlFor屬性,class屬性比較特殊,它在Javascript中變成className屬性;

          表示HTML屬性的值通常是字符串,但當(dāng)屬性為布爾值或數(shù)值時,Javascript中對應(yīng)的屬性也是布爾值或數(shù)值,而不是字符串;

          <label id="lbInput" for="txtInput">文本框:</label>
          <input id="txtInput" tabindex="2" type="text" readonly />
          <script>
          var txtInput=document.getElementById("txtInput");
          console.log(txtInput.tabIndex);  // 1
          console.log(txtInput.readOnly);  // true
          var lbInput=document.getElementById("lbInput");
          console.log(lbInput.htmlFor);  // txtInput
          </script>

          style和事件處理程序特性:

          style:在通過getAttribute()訪問時,返回的style特性值中包含的是CSS文本;而通過屬性訪問它會返回一個CSSStyleDeclaration對象(由于style屬性是用于以編程方式訪問元素樣式的對象,因此并沒有直接映射到style特性,有關(guān)CSS編程,后面我們會講到);

          事件處理程序特性,類似于onclick等這樣的事件處理程序,當(dāng)在特性中使用時,onclick中包含的就是JS代碼,使用getAttribute()會返回相應(yīng)的代碼的字符串,但在訪問onclick屬性時,會返回一個Javascript函數(shù);

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.getAttribute("style")); // font-size: 14px;color:red;
          console.log(mydiv.style); // CSSStyleDeclaration or CSS2Properties
          console.log(mydiv.getAttribute("onclick"));  // alert('zeronetwork');
          console.log(mydiv.onclick); // function onclick(event)

          setAttribute(name, value)方法:

          設(shè)置指定元素上的某個特性值,如果特性已經(jīng)存在,則更新該值,否則,使用指定的名稱和值添加一個新的特性;

          該接受兩個參數(shù):要設(shè)置的特性名和值;

          此方法可以操作HTML特性也可以操作自定義特性;

          var mydiv=document.getElementById("mydiv");
          mydiv.setAttribute("id","outerdiv");
          mydiv.setAttribute("class","outerdivclass");
          mydiv.setAttribute("title","mydiv title");
          mydiv.setAttribute("style","border-bottom:1px solid;color:purple;");
          mydiv.setAttribute("custom","custom value");
          console.log(mydiv.title);  // mydiv title
          console.log(mydiv.custom);  // undefined

          通過該方法設(shè)置的特性名會被統(tǒng)一轉(zhuǎn)換成小寫形式,即“ID”最終會變成“id”;

          mydiv.setAttribute("ID","myID");  // id
          mydiv.setAttribute("CID","customID");  // cid

          布爾特性只要出現(xiàn)在元素上就會被認(rèn)為是 true,無論它的值是什么;一般來說,應(yīng)該將 value 設(shè)置為空字符串,也有人使用這個屬性的名稱作為值,雖然不會出現(xiàn)什么問題,但不規(guī)范的;

          var txtInput=document.getElementById("txtInput");
          txtInput.setAttribute("readonly",true);// 會渲染成readonly="true"
          txtInput.setAttribute("readonly",""); // 渲染成readonly
          console.log(txtInput.readOnly);  // true

          因為所有特性都是屬性,所以直接給屬性賦值可以設(shè)置特性的值,但如果添加的是一個自定義的屬性,該屬性不會自動成為元素的特性;

          mydiv.title="mydiv title";
          mydiv.style="border-bottom:1px solid;color:purple;";
          mydiv.custom="custom value";  // html中并沒有渲染custom
          console.log(mydiv.title);  // mydiv title
          console.log(mydiv.custom);  // custom value
          console.log(mydiv.getAttribute("title")); // mydiv title
          console.log(mydiv.getAttribute("custom")); // null

          可以通過setAttribute()方法設(shè)置class,但不能通過屬性設(shè)置class,因為class是關(guān)鍵字,需要className進行屬性設(shè)置;

          var mydiv=document.getElementById("mydiv");
          mydiv.setAttribute("class","att_class");
          // mydiv.class="att_class";  // 無效,class是保留字
          mydiv.className="att_class";
          console.log(mydiv.class);  // undefined
          console.log(mydiv.className);  // att_class

          removeAttribute(attrName)方法:

          用于從指定的元素徹底刪除元素的特性;

          此方法不僅會清除特性的值,而且也會從元素中完全刪除特性;

          此方法并不常用,但在序列化DOM元素時,可以通過它來確切地指定要包含哪些特性;

          var mydiv=document.getElementById("mydiv");
          mydiv.removeAttribute("class");
          mydiv.removeAttribute("style");
          mydiv.setAttribute("custom","custom_value");
          mydiv.removeAttribute("custom");
          mydiv.title="mydiv title";
          mydiv.removeAttribute("title");

          hasAttribute(attrName)方法和hasAttributes()方法:

          用于檢測特性是否存在;其中hasAttribute()需要一個特性參數(shù),判斷該元素是否包含有指定的特性,而hasAttributes()檢測的是否有特性,具體是什么特性,則不是它所關(guān)心的了;

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.hasAttribute("title"));
          if(!mydiv.hasAttribute("align"))
              mydiv.setAttribute("align","center");
          console.log(mydiv.hasAttributes());  // true

          當(dāng)屬性為布爾值時,hasAttribute()方法特別有用,比如HTML表單的disabled屬性,只要判斷它有沒有這個屬性即可,不用管它的值;

          attributes屬性:

          返回該元素所有屬性節(jié)點的一個實時集合,該集合是一個NamedNodeMap對象,是一個只讀的類數(shù)組對象,只有Element類型擁有;該屬性與NodeList類似,也是一個動態(tài)的集合;也可以使用索引方式訪問,并且可以枚舉;

          元素的每個特性都由一個Attr節(jié)點表示,Attr對象是一個特殊的Node,不會像普通的Node一樣去使用;Attr的name和value屬性返回該屬性的名字和值;

          每個Attr節(jié)點都保存在NamedNodeMap對象中;此節(jié)點都有nodeName、nodeValue等屬性,nodeName就是特性的名稱,nodeValue就是特性的值;

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.attributes);
          console.log(mydiv.attributes[1]);
          console.log(mydiv.attributes.title);
          console.log(mydiv.attributes.custom);
          mydiv.attributes.title="wangwei";  // 無效
          console.log(mydiv.attributes[1].nodeType);  // ATTRIBUTE_NODE
          console.log(mydiv.attributes[1].nodeName);
          console.log(mydiv.attributes[1].nodeValue);

          NamedNodeMap對象:

          表示一個無順序的屬性節(jié)點 Attr 對象的集合;其是類數(shù)組對象,同時也是動態(tài)的;

          屬性和方法:

          length屬性:返回映射(map)中對象的數(shù)量;

          getNamedItem(name):返回給定名稱name的屬性節(jié)點;

          item(pos):返回位于數(shù)字pos位置處的節(jié)點;(注:各個瀏覽器會返回不同的順序);

          setNamedItem(node):向列表中添加或替換特性節(jié)點;

          removeNamedItem(name):從列表中移除特性為name的節(jié)點;與removeAttribute()相同,但其會返回被刪除的特性(Attr)節(jié)點;

          可以通過attributes屬性使用方括號直接訪問特性;

          var mydiv=document.getElementById("mydiv");
          console.log(mydiv.attributes);
          console.log(mydiv.attributes.item(1));
          console.log(mydiv.attributes.getNamedItem("name"));
          console.log(mydiv.attributes[1]);
          console.log(mydiv.attributes["name"]);
          mydiv.attributes["id"].nodeValue="newID";
          mydiv.attributes.getNamedItem("name").nodeValue="newName";
          var deleteStyle=mydiv.attributes.removeNamedItem("style");
          console.log(deleteStyle);
          var yourdiv=document.getElementById("yourdiv");
          yourdiv.attributes.setNamedItem(deleteStyle);
          var attr=document.createAttribute("dir");
          attr.nodeValue="ltr";
          mydiv.attributes.setNamedItem(attr);

          使用attributes屬性較麻煩,因此使用getAttribute()、removeAttribute()和removeAttribute()方法比較常用;但在遍歷元素的特性時,attributes屬性比較方便;

          遍歷attributes屬性:

          在需要將DOM結(jié)構(gòu)序列化為XML或HTML字符串時,多數(shù)都會涉及遍歷元素特性;

          // 迭代元素的所有特性,構(gòu)造成name=”value” name=”value”這樣的字符串格式
          var mydiv=document.getElementById("mydiv");
          function outputAttributes(element){
              var pairs=new Array();
              for(var attr in element.attributes){
                  if(element.attributes[attr] instanceof Attr){
                      // console.log(attr + element.attributes[attr]);
                      var attrName=element.attributes[attr].nodeName;
                      var attrValue=element.attributes[attr].nodeValue;
                      // console.log(attrName);
                      pairs.push(attrName + "=\"" + attrValue + "\"");
                  }
              }
              // 或者使用for循環(huán)
              // for(var i=0,len=element.attributes.length; i<len; i++){
              //     var attrName=element.attributes[i].nodeName;
              //     var attrValue=element.attributes[i].nodeValue;
              //     // console.log(attrName);
              //     pairs.push(attrName + "=\"" + attrValue + "\"");
              // }
              return pairs.join(" ");
          }
          console.log(outputAttributes(mydiv));

          創(chuàng)建Element元素:

          document.createElement(tagName)方法:用于創(chuàng)建一個由標(biāo)簽名稱tagName指定的HTML元素,如果用戶代理無法識別tagName,則會生成一個未知 HTML 元素;

          該方法只接受一個參數(shù),即要創(chuàng)建元素的標(biāo)簽名;此標(biāo)簽名在HTML中不區(qū)分大小寫,在XML(包括XHTML)中,是區(qū)分大小寫的;

          在創(chuàng)建新元素的同時,也為新元素設(shè)置了ownerDocument屬性;同時還可以操作元素的特性,為它添加子節(jié)點,以及執(zhí)行其他操作;

          新創(chuàng)建的元素,必須添加到文檔樹中,才能顯示出來,可以利用appendChild,insertBefore()或replaceChild()方法;

          var div=document.createElement("div");
          div.innerHTML="<h2>零點程序員</h2>";
          div.id="outerDiv";
          div.className="outerDiv";
          div.setAttribute("style","color:green;");
          console.log(div.ownerDocument);
          document.body.appendChild(div);
          var h3=document.createElement("h3");
          h3.setAttribute("onclick","alert('this is zeronetwork');");
          h3.innerText="zeronetwork";
          div.insertBefore(h3, null);

          Element的子節(jié)點:

          元素可以有任意數(shù)目的子節(jié)點和后代節(jié)點,這些子節(jié)點可能是元素、文本、注釋處處理指令;但HTML中的空白也會被解析為文本節(jié)點;因此在執(zhí)行某項操作時,要先檢查一下nodeType屬性;

          <!-- 結(jié)構(gòu) -->
          <ul id="myList">
              <li>HTML</li>
              <li>CSS</li>
              <li>Javascript</li>
          </ul>
          <!-- 或者刪除空白 -->
          <ul id="myList"><li>HTML</li><li>CSS</li><li>Javascript</li></ul>
          // js代碼
          var myList=document.getElementById("myList");
          console.log(myList.childNodes.length);
          for(var i=0,len=myList.childNodes.length; i<len; i++){
              if(myList.childNodes[i].nodeType==Node.ELEMENT_NODE)
                  console.log(myList.childNodes[i].nodeName);
          }
          // 或者
          // for(var n in myList.childNodes){
          //     if(myList.childNodes[n].nodeType && myList.childNodes[n].nodeType==Node.ELEMENT_NODE)
          //         console.log(myList.childNodes[n].nodeName);
          // }

          元素節(jié)點也支持getElementsByTagName() 方法,可以通過它獲得某個特定的標(biāo)簽名的子節(jié)點或后代節(jié)點;

          var myList=document.getElementById("myList");
          var lis=myList.getElementsByTagName("li");
          console.log(lis);  // dom.html:23 HTMLCollection(3)

          自定義Element的方法:

          Element和HTMLDocument等類型都像String和Array一樣是類,它們不是構(gòu)造函數(shù),但它們有原型對象,可以自定義方法擴展它;

          Element.prototype.next=function(){
              if(this.nextElementSibling) return this.nextElementSibling;
              var sib=this.nextSibling;
              while(sib && sib.nodeType !==1) sib=sib.nextSibling;
              return sib;
          }
          console.log(document.getElementById("mydiv").next());

          Web前端開發(fā)之Javascript-零點程序員-王唯

          、深淺拷貝的區(qū)別有哪些?

          要說 js 的深淺拷貝,就不得不提 js 的兩大數(shù)據(jù)類型:基本數(shù)據(jù)類型和引用類型。基本數(shù)據(jù)類型的變量名和值都存儲在棧中,對于引用類型的變量名存儲在棧中,而值存儲在堆中。由于存儲方式不同,所以導(dǎo)致了他們復(fù)制的時候方式不同。

          淺拷貝是創(chuàng)建一個新對象,這個對象有著原始對象屬性值的一份精準(zhǔn)拷貝。如果屬性是基本類型,拷貝的就是基本類型的值,如果是引用類型,拷貝的就是內(nèi)存地址,所以如果其中一個對象改變了這個地址,就會影響到另外一個對象。

          深拷貝是將一個對象從內(nèi)存中完整的拷貝一份出來,從內(nèi)存堆中存放一個新的對象。這是兩個對象,所以修改其中一個,另外一個不會受影響。

          深淺拷貝主要針對的是引用類型,簡單數(shù)據(jù)類型不受影響。

          相關(guān)筆試題

          var person={
           name:"前端人",
           hobby:['學(xué)習(xí)','敲代碼','潛水']
          }
          function copy(source){
           var newObj=new Object()
           for(var i in source){
            if(source.hasOwnProperty(i)){
             newObj[i]=source[i]
             }
            }
           return newObj
          }
          var p1=copy(person);
          p1.name="Web Person"
          console.log(person.name)
          console.log(p1.name)
          p1.hobby=["內(nèi)卷"]
          console.info(person.hobby)
          console.info(p1.hobby)
          /*運行結(jié)果:
          前端人
           Web Person
          ["學(xué)習(xí)", "敲代碼", "潛水"]
          ["內(nèi)卷"]
          */

          2、js 數(shù)據(jù)類型有哪些?

          js 數(shù)據(jù)類型一共有 8 種,分為兩大類:基本類型和引用類型。

          它們的數(shù)據(jù)類型分別為:

          基本類型:string、number、boolean、null、undefined、symbol、bigint

          引用類型:object

          相關(guān)面試題

          // 注意:其他類型與數(shù)值進行相加時,其他類型的轉(zhuǎn)為 number 類型
          console.log( true+1 ) // 2
          console.log( undefined +1 ) // NaN
          
          console.log( null ) //object
          console.log( undefined ) // undefined

          3、延遲加載 js 的方式有哪些?有什么區(qū)別呢?

          共有 6 種方式,分別為:

          • async
          • defer
          • js 最后加載
          • 利用 setTimeout
          • 動態(tài)創(chuàng)建 DOM 的方式
          • 使用 jQuery 的 getScript 方法

          它們的區(qū)別介紹:

          1、async:為 <script>標(biāo)簽定義了 async 屬性。async 和 html 解析是同步的,不是順次執(zhí)行 js 腳本,誰先加載完成先執(zhí)行誰。

          <script  async type="text/javascript" src="demo1.js" ></script>
          <script  async type="text/javascript" src="demo2.js" ></script>

          2、defer 會等到 html 解析完成之后再執(zhí)行 js 代碼,如果有多個腳本時,會按照順序依次執(zhí)行腳本。

          <script  defer type="text/javascript" src="demo1.js" ></script>

          3、js 最后加載

          把 js 外部引入的文件放置在頁面的底部,讓 js 最后加載,從而加快頁面加載速度。

          4、利用 setTimeout

          5、動態(tài)創(chuàng)建 DOM 的方式

          var element=document.createElement("script");  
          element.src="box.js";  
          document.body.appendChild(element);

          這種方式通過操作動態(tài)加載 js 文件,不觸發(fā)的時候不加載,減少頁面文件大小,加快加載速度。

          6、使用 jQuery 的 getScript 方法

          $.getScript( "box.js",function(){//回調(diào)函數(shù),成功獲取文件后執(zhí)行的函數(shù)  
                console.log("腳本加載完成")  
          });

          相關(guān)面試題:

          <!doctype html>
          <html>
           <head>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <script type="text/javascript" src="box.js"></script>
           </head>
           <body>
            <div id="box"></div>
           </body>
          </html>
          
          //box.js 代碼如下
          console.log( document.getElementById('box') )  // null

          box.js 想正常獲取元素 box ,并進行一系列操作應(yīng)該如何延遲加載 js 文件呢?

          4、你對作用域的認(rèn)識有多少?

          作用域通俗地講,就是指一個變量的作用范圍。分為全局作用域和函數(shù)作用域。

          全局作用域

          • 頁面打開時被創(chuàng)建,頁面關(guān)閉時被銷毀。
          • 編寫在 script 標(biāo)簽下的變量和函數(shù),作用域為全局,頁面的任意位置都可以訪問
          • 有全局對象 window ,代表瀏覽器窗口,全局作用下的變量和函數(shù)作為 window 的屬性和方法

          函數(shù)作用域(局部)

          • 函數(shù)是被調(diào)用時創(chuàng)建的,執(zhí)行完畢之后銷毀。
          • 函數(shù)每調(diào)用一次,變量和函數(shù)就會重新創(chuàng)建一次,它們之間是相互獨立的
          • 在函數(shù)作用域內(nèi)可以訪問到全局變量或函數(shù),但是在函數(shù)外無法訪問函數(shù)作用域內(nèi)的變量
          • 函數(shù)作用域內(nèi)訪問變量,會在自身作用域內(nèi)尋找,若沒有則會向上一級作用域內(nèi)查找,一直到全局作用域。

          函數(shù)在被調(diào)用的時候會先進行預(yù)編譯:

          全局作用域預(yù)編譯:

          • 創(chuàng)建上下文 GO 對象。
          • 找變量聲明,將變量名作為 GO 對象的屬性名,值為 undefined
          • 找函數(shù)式聲明,將值賦予函數(shù)體

          函數(shù)作用域預(yù)編譯:

          • 創(chuàng)建上下文 AO 對象
          • 將形參和實參作為 AO 對象的屬性,賦值為 undefined
          • 實參和形參相統(tǒng)一
          • 在函數(shù)體內(nèi)找函數(shù)聲明,將值賦予函數(shù)體。

          相關(guān)面試題:

          <script type="text/javascript">
           function fn(a,c){
            console.log(a)
            var a=12
            console.log(a)
            console.log(c)
            function a(){ }
            if(false){
             var d=34
            }
            console.log(d)
            console.log(b)
            var b=function(){}
            console.log(b)
            function c(){}
            console.log(c)
           }
           fn(1,2)
          </script>
          // 運行結(jié)果:
          /*
          function a(){}
          12
          function c(){}
          undefined
          undefined
          function (){}
          function c(){}
          */

          5、null 和 undefined 的區(qū)別。

          null 和 undefined 兩個都表示無的值。

          作者設(shè)計 js 的時候,借鑒的 java 語言先設(shè)計的 null 。null 使用的時候會被隱式轉(zhuǎn)化成 0,不容易發(fā)現(xiàn)錯誤。

          console.log( number(null) ) //0

          undefined 是為了填補 null 的坑。所以后來又新增了 undefined 。

          console.log( number(undefined) ) //NaN

          6、new 操作符具體做了什么?

          • 創(chuàng)建了一個空對象。
          • 將空對象的原型指向于構(gòu)造函數(shù)的原型。
          • 將空對象作為構(gòu)造函數(shù)的上下文。
          • 對構(gòu)造函數(shù)有返回值的處理判斷。

          實現(xiàn) new 操作符的方法:

          function create( fn,...args ){
           var obj={}
           Object.setPrototypeOf( obj,fn.prototype )
           var resault=fn.apply(obj,args)
           return (resault instanceof Object) ? result : obj
          }

          7、為什么會有閉包?它解決了什么問題?

          7.1、什么是閉包?

          閉包就是函數(shù)嵌套函數(shù),通過函數(shù)內(nèi)的函數(shù)訪問變量的規(guī)則,實現(xiàn)外部訪問函數(shù)內(nèi)的變量。

          7.2、閉包的特點:

          • 函數(shù)嵌套函數(shù)。
          • 函數(shù)內(nèi)部可以引用函數(shù)外部的參數(shù)和變量。
          • 參數(shù)和變量不會被垃圾回收機制回收。

          實例3:閉包解決問題

          var liArr=document.getElementsByTagName('li')
          for(var i=0;i<liArr.length;i++){
           (function(i){
            liArr[i].onclick=function(){
             console.log('點擊元素',liArr[i])
            }
           })(i) 
          }

          7.3、閉包優(yōu)點:

          • 保護變量安全,實現(xiàn)封裝,防止變量聲明沖突和全局污染。
          • 在內(nèi)存當(dāng)中維持一個變量,可以做緩存。
          • 匿名函數(shù)自執(zhí)行函數(shù)可以減少內(nèi)存消耗。

          防抖和節(jié)流就是閉包的經(jīng)典應(yīng)用。

          7.4、閉包缺點:

          • 變量會駐留在內(nèi)存中,造成內(nèi)存損耗問題。解決辦法:把閉包函數(shù)設(shè)置為 null 。
          • 內(nèi)存泄漏

          8、防抖和節(jié)流,你了解多少?

          8.1、什么是防抖函數(shù)?

          當(dāng)持續(xù)觸發(fā)事件,一定時間內(nèi)沒有再觸發(fā)事件,事件處理函數(shù)才會執(zhí)行一次,如果在設(shè)定的時間到來之前又觸發(fā)了事件,就會重新計時。

          防抖函數(shù)常見的實際應(yīng)用:使用 echart 的時候,瀏覽器 resize 時,需要重新繪制圖表大小,還有典型的輸入框搜索應(yīng)用。

          8.2、節(jié)流函數(shù)是什么?

          當(dāng)持續(xù)觸發(fā)事件的時候,保證一段時間內(nèi)只調(diào)用一次事件處理函數(shù),一段時間內(nèi),只允許做一件事情。

          防抖和節(jié)流主要是用來限制觸發(fā)頻率較高的事件,再不影響效果的前提條件下,降低事件觸發(fā)頻率,減小瀏覽器或服務(wù)器的壓力,提升用戶體驗效果。

          9、數(shù)組去重有幾種方法?

          方法1: new set()

          return Array.from(new Set(arr))
          // 或
          return [...new Set(arr)]

          方法2:使用兩次循環(huán)

          for(var i=0,len=arr.length;i<len;i++){
           for(var j=i+1,len=arr.length;j<len;j++){
            if( arr[i]===arr[j] ){
             arr.splice(i,1)
             j--;
             len--
            }
           }
          }
          return arr

          方法3:indexOf 實現(xiàn)

          let arr1=[]
          for(var i=0;i<arr.length;i++){
           if( arr1.indexOf(arr[i])===-1 ){
            arr1.push(arr[i])
           }
          }
          return arr1

          方法4:includes 實現(xiàn)

          let arr1=[]
          for(var i=0;i<arr.length;i++){
           if( !arr1.includes(arr[i]) ){
            arr1.push(arr[i])
           }
          }
          return arr1

          方法5:filter 實現(xiàn)

          array.indexOf(item,start) start 表示開始檢索的位置。

          return arr.filter(( item, index )=>{
           return arr.indexOf( item, 0 )==index
          })

          10、call、bind 和 apply 的區(qū)別

          三者都是改變函數(shù)執(zhí)行的上下文,即改變 this 指向。

          它們之間的區(qū)別為:

          • call 和 apply 會立即執(zhí)行,bind 返回的是一個函數(shù),需調(diào)用后執(zhí)行。
          • 第二參數(shù)是傳入要執(zhí)行的方法中的參數(shù),call 和 bind 是獨立傳遞參數(shù),apply 是以數(shù)組傳遞參數(shù)的

          使用場景:
          1、需要改變某個函數(shù)的this指向時
          2、當(dāng)參數(shù)較少時可以使用call,參數(shù)較多可以使用apply以數(shù)組的方式傳遞
          3、當(dāng)需要重復(fù)調(diào)用時,可以使用bind新定義一個方法

          11、js 判斷變量是不是數(shù)組,你能寫出幾種方法?

          方法1:isArray

          var arr=[1,2,3]
          console.log(Array.isArray(arr))    

          方法2:instanceof

          var arr=[1,2,3]
          console.log( arr instanceof Array )
          console.log( arr instanceof Object )

          該方法不夠嚴(yán)謹(jǐn)。

          方法3:prototype

          console.log( Object.prototype.toString.call(arr).indexOf('Array')>-1 )

          方法4:isPrototypeOf

          console.log( Array.prototype.isPrototypeOf( arr ) )

          方法5:constructor

          console.log(arr.constructor.toString().indexOf('Array')>-1 )

          12、slice 是干嘛的? splice 是否會改變原數(shù)組?

          slice 是用來截取字符串的,返回一個新數(shù)組,但不會影響原數(shù)組。

          使用語法:

          arr.slice( start , end )

          截取 arr 數(shù)組,從 start 開始到 end 結(jié)束,第二個參數(shù)是可選參數(shù),沒有時從 start 開始截取到結(jié)尾。

          如果 start 參數(shù)是負數(shù)時,就會從 arr.lengtn + start 開始截取到結(jié)束。

          var arr=['a','b','c','d','e']
          console.log( arr.slice(-3) ) // ["c", "d", "e"]
          console.log(arr)  //["a", "b", "c", "d", "e"]

          splice 是一個更強大的方法,可以添加、刪除、替換數(shù)組元素,返回的是被刪除元素,它的操作會改變原數(shù)組。

          使用語法:

          splice( start, n, new )

          從 start 開始,刪除 n 個元素,然后把 new 添加到 start 元素之后。第三個參數(shù)為可選參數(shù)

          • n 為 0 且第三個參數(shù)不為空時,表示添加新元素到 start 之后。
          • n 不為 0 且第三個參數(shù)不為空時,表示把 start 之后的 n 個元素替換成 new 。
          • n 不為 0 且第三個參數(shù)為空時,表示刪除 start 后的 n 個元素。
          var arr=['a','b','c','d','e']
          var ar=arr.splice( 1, 1 ,'f','g')
          console.log('ar',ar)    // ["b"]
          console.log('arr',arr) //  ["a", "f", "g", "c", "d", "e"]

          13、==和===有什么不同?

          ==比較的是值,===除了比較值,還比較類型。

          console.log( [1,2]=='1,2'  )       // true
          console.log( [1,2]==='1,2'  )  //false

          valueOf 方法返回 Math 對象的原始值,通常由 javascript 在后臺自動調(diào)用,并不顯示的出現(xiàn)在代碼中。

          console.log([1,2].valueOf()) //[1,2]
          console.log('1,2'.valueOf()) //[1,2]
          // 所以
          console.log( [1,2]=='1,2'  )  // true

          不管是字符串和數(shù)字比較,還是布爾值和數(shù)字比較,都會使用 valueOf 隱式轉(zhuǎn)換。

          總結(jié):==需要使用 valueOf() 進行隱式轉(zhuǎn)換,所以性能差。===會避開一些不必要的麻煩。

          14、this 的指向

          大廠筆試題:

          var name='window name'
          var p1={
           name:'p1 name',
           showName:function(){
            console.info(this.name)
           }
          }
          var fn=p1.showName
          fn()
          p1.showName()
          var p2={
           name:'p2 name',
           showName:function(fun){
            fun()
           }
          }
          p2.showName(p1.showName)
          p2.showName=p1.showName
          p2.showName()
          /*
          運行結(jié)果:
          window name
           p1 name
           window name
           p2 name
          */

          這是一道關(guān)于 this 指向的面試題,接下來我們就說說 this 是如何指向的?

          this 對象是運行時基于函數(shù)的執(zhí)行環(huán)境綁定的:

          • 在全局函數(shù)中,this 等于 window 。
          • 函數(shù)上下文調(diào)用,嚴(yán)格模式下 this 為 undefined ,非嚴(yán)格模式下,this 指向 window 。
          • 當(dāng)函數(shù)被作為某個對象的方法被調(diào)用時,this 等于那個對象。如果使用 call apply 改變當(dāng)前 this 時,將會指向為傳遞過來的那個 this 。
          • 匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此 this 指向 window。
          • 構(gòu)造函數(shù)內(nèi)的 this 指向創(chuàng)建的實例對象。
          • dom 事件處理函數(shù),this 指向觸發(fā)該事件的元素。
          • setTimeout 和 setInterval 中的 this 指向全局變量 window

          15、js 中的繼承有哪些方式呢?

          第 1 種:原型鏈繼承

          function Parent(){
           this.name="前端人"
          }
          Parent.prototype.showName=function(){
           console.log(this.name)
          }
          function Child(){}
           //原型鏈繼承   
          Child.prototype=new Parent()
          var p=new Child()
          console.dir(p.name) //前端人

          特點:

          • 實例的是子類的實例,也是父類的實例。
          • 父類新增原型方法和屬性,子類都能訪問到。
          • 簡單,方便實現(xiàn)

          第 2 種:借用構(gòu)造函數(shù)

          function Animal (name) {
           this.name=name || 'Animal';
           this.sleep=function(){
            console.log(this.name + '正在睡覺!');
           }
          }
          Animal.prototype.eat=function(food) {
           console.log(this.name + '正在吃:' + food);
          };
          function Cat(name){
           Animal.call(this);
           this.name=name || 'Tom';
          }
          // Test Code
          var cat=new Cat();
          console.log(cat.name);
          console.log(cat.sleep());
          console.log(cat instanceof Animal); // false
          console.log(cat instanceof Cat); // true

          特點:

          • 創(chuàng)建子類時,可以向父類傳遞參數(shù)。
          • 可以實現(xiàn)多繼承,call 多個父類對象。
          • 解決方法1中,子類實例共享父類引用屬性的問題。

          還有組合式繼承、ES6 的繼承 和 寄生組合繼承等等。每種繼承方式都有各自的特點和缺點。

          16、嚴(yán)格模式與非嚴(yán)格模式的區(qū)別,你了解多少?

          JavaScript 語言是一門弱類型語言,存在許多類型錯誤,因此 ES6 引入了嚴(yán)格模式概念。

          如果不加 ‘use strict’ 常規(guī)模式下就是屬于非嚴(yán)格模式。

          嚴(yán)格模式

          在 js 文件頂部添加 ‘use strict’ 就屬于嚴(yán)格模式,嚴(yán)格模式也可以指定在函數(shù)內(nèi)部。

          <script>
           'use strict'  
           //或者函數(shù)內(nèi)部
           (function(){
            'use strict'
           })()
          </script>

          嚴(yán)格模式,是為 js 定義來了一種不同的解析與執(zhí)行模型,在嚴(yán)格模式下,ECMAScipt 3 中一些不解和不確定的行為將得到處理,而且會對不安全的操作會拋出異常。‘use strict’ 會告訴瀏覽器引擎可以切換到嚴(yán)格模式執(zhí)行。

          嚴(yán)格模式與非嚴(yán)格模式區(qū)別

          嚴(yán)格模式

          非嚴(yán)格模式

          變量必須聲明才能賦值

          變量不進行聲明,可直接賦值

          不能使用 delete 字符刪除變量或?qū)ο?/p>

          可以使用 delete 刪除

          函數(shù)參數(shù)變量名不允許重復(fù)

          變量名重復(fù),獲取最后最后那個值

          普通函數(shù)內(nèi)的 this 為 undefined

          普通函數(shù)內(nèi)的 this 為 window

          不允許使用八進制

          允許任意進制

          eval 和 arguments 當(dāng)做關(guān)鍵字,不能被賦值和用作變量名

          可以使用 eval 、arguments 作為變量名

          call、apply 傳入 null undefined 保持原樣不被轉(zhuǎn)為window

          默認(rèn)轉(zhuǎn)為 window 對象

          限制對調(diào)用棧的檢測能力,訪問 arguments.callee 會拋出異常

          arguments.callee 運行正常

          17、隱式轉(zhuǎn)化相關(guān)面試題

          console.log( '2'>10 ) //false
          console.log( '2'>'10' ) //true
          console.log( 'abc'>'b' ) //false
          console.log( 'abc'>'aab' ) //true
          console.log( undefined==null ) //true
          console.log( NaN==NaN )//false
          console.log( []==0 ) //true
          console.log( ![]==0 ) //true
          console.log( []==[] ) //false
          console.log( {}=={} ) //false
          console.log( {}==!{} ) //false

          18、事件循環(huán)機制相關(guān)面試題。

          阿里面試題1:

          <script type="text/javascript">
           var p=new Promise(resolve=>{
            console.log(4)
            resolve(5)
           })
           function f1(){
            console.log(1)
           }
           function f2(){
            setTimeout(()=>{
             console.log(2)
            },0)
            f1()
            console.log(3)
            p.then(res=>{
             console.log(res)
            })
           }
           f2()
          </script>
          // 運行結(jié)果 4 1 3 5 2
          // 如果已經(jīng)了解事件運行機制,就可以跳過該問題了

          事件循環(huán)機制,event-loop 。包含三部分:調(diào)用棧、消息隊列、微任務(wù)隊列。

          事件循環(huán)開始的時候,會從全局一行一行的執(zhí)行代碼,遇到函數(shù)調(diào)用的時候,就會壓入調(diào)用棧中,當(dāng)函數(shù)執(zhí)行完成之后,彈出調(diào)用棧。

          // 如:代碼會一行一行執(zhí)行,函數(shù)全部調(diào)用完成之后清空調(diào)用棧
          function f1(){
           console.log(1)
          }
          function f2(){
           f1()
           console.log(2)
          }
          f2()
          // 執(zhí)行結(jié)果 1 2

          如果遇到 fetch、setInterval、setTimeout 異步操作時,函數(shù)調(diào)用壓入調(diào)用棧時,異步執(zhí)行內(nèi)容會被加入消息隊列中,消息隊列中的內(nèi)容會等到調(diào)用棧清空之后才會執(zhí)行。

          // 如:
          function f1(){
           console.log(1)
          }
          function f2(){
           setTimeout(()=>{
            console.log(2)
           },0)
           f1()
           console.log(3)
          }
          f2()
          // 執(zhí)行結(jié)果 :1 3 2

          遇到 promise、async、await 異步操作時,執(zhí)行內(nèi)容會被加入微任務(wù)隊列中,會在調(diào)用棧清空之后立即執(zhí)行。

          調(diào)用棧加入的微任務(wù)隊列會立即執(zhí)行。

          如
          let p=new Promise(resolve=>{
           console.log('立即執(zhí)行')
           resolve(1) //在 then 調(diào)用中執(zhí)行
          })

          微任務(wù)隊列中內(nèi)容優(yōu)先執(zhí)行,所以比消息隊列中的內(nèi)容執(zhí)行得早。

          了解這些知識后,再試一下最前面的那道面試題,應(yīng)該就沒什么問題了。

          20、前端領(lǐng)域內(nèi),你比較擅長什么?

          這個問題就留給讀到最后,能夠堅持學(xué)習(xí)的人,問問我們自己有什么是我們擅長的?在哪塊領(lǐng)域是我們占據(jù)競爭優(yōu)勢的?

          使用內(nèi)置JavaScript的對象實例。

          Document 對象

          • 使用 document.write() 輸出文本

          • 使用 document.write() 輸出 HTML

          • 返回文檔中錨的數(shù)目

          • 返回文檔中第一個錨的 innerHTML

          • 返回文檔中表單的數(shù)目

          • 返回文檔中第一個表單的名字

          • 返回文檔中的圖像數(shù)

          • 返回文檔中第一個圖像的ID

          • 返回文檔中的鏈接數(shù)

          • 返回文檔中的第一個鏈接的ID

          • 返回文檔中的所有cookies的名稱/值對

          • 返回加載的文檔的服務(wù)器域名

          • 返回文檔的最后一次修改時間

          • 返回加載的當(dāng)前文檔的URL

          • 返回文檔的標(biāo)題

          • 返回文檔的完整的URL

          • 打開輸出流,向流中輸入文本

          • write() 和 writeln()的不同

          • 用指定的ID彈出一個元素的innerHTML

          • 用指定的Name彈出元素的數(shù)量

          • 用指定的tagname彈出元素的數(shù)量

          • 更多的Document 對象的例子,在我們的JavaScript 參考手冊。

          Anchor 對象

          • 返回和設(shè)置鏈接的charset屬性

          • 返回和設(shè)置鏈接的href屬性

          • 返回和設(shè)置鏈接的hreflang屬性

          • 返回一個錨的名字

          • 返回當(dāng)前的文件和鏈接的文檔之間的關(guān)系

          • 改變鏈接的target屬性

          • 返回一個鏈接的type屬性的值

          • 更多的Anchor 對象的例子,在我們的JavaScript 參考手冊。

          Area 對象

          • 返回圖像映射某個區(qū)域的替代文字

          • 返回圖像映射某個區(qū)域的坐標(biāo)

          • 返回一個區(qū)域的href屬性的錨部分

          • 返回的主機名:圖像映射的某個區(qū)域的端口

          • 返回圖像映射的某個區(qū)域的hostname

          • 返回圖像映射的某個區(qū)域的port

          • 返回圖像映射的某個區(qū)域的href

          • 返回圖像映射的某個區(qū)域的pathname

          • 返回圖像映射的某個區(qū)域的protocol

          • 返回一個區(qū)域的href屬性的querystring部分

          • 返回圖像映射的某個區(qū)域的shape

          • 返回圖像映射的某個區(qū)域的target的值

          • 更多的Area 對象的例子,在我們的JavaScript 參考手冊。

          Base 對象

          • 返回頁面上所有相對URL的基URL

          • 返回頁面上所有相對鏈接的基鏈接

          • 更多的Base 對象對象的例子,在我們的JavaScript 參考手冊。

          Button 對象

          • 當(dāng)點擊完button不可用

          • 返回一個button的name

          • 返回一個button的type

          • 返回一個button的value

          • 返回一個button所屬表的ID

          • 更多Button 對象實例在我們的JavaScript 參考手冊。

          Form 對象

          • 返回一個表單中所有元素的value

          • 返回一個表單acceptCharset屬性的值

          • 返回一個表單action屬性的值

          • 返回表單中的enctype屬性的值

          • 返回一個表單中元素的數(shù)量

          • 返回發(fā)送表單數(shù)據(jù)的方法

          • 返回一個表單的name

          • 返回一個表單target屬性的值

          • 重置表單

          • 提交表單

          • 更多Button 對象實例在我們的JavaScript 參考手冊。

          Frame/IFrame 對象

          • 對iframe排版

          • 改變一個包含在iframe中的文檔的背景顏色

          • 返回一個iframe中的frameborder屬性的值

          • 刪除iframe的frameborder

          • 改變iframe的高度和寬度

          • 返回一個iframe中的longdesc屬性的值

          • 返回一個iframe中的marginheight屬性的值

          • 返回一個iframe中的marginwidth屬性的值

          • 返回一個iframe中的name屬性的值

          • 返回和設(shè)置一個iframe中的scrolling屬性的值

          • 改變一個iframe的src

          • 更多Frame/IFrame 對象實例在我們的JavaScript 參考手冊。

          Image 對象

          • 對image排版

          • 返回image的替代文本

          • 給image加上border

          • 改變image的高度和寬度

          • 設(shè)置image的hspace和vspace屬性

          • 返回image的longdesc屬性的值

          • 創(chuàng)建一個鏈接指向一個低分辨率的image

          • 返回image的name

          • 改變image的src

          • 返回一個客戶端圖像映射的usemap的值

          • 更多Image 對象實例在我們的JavaScript 參考手冊。

          Event 對象

          • 被按下的鍵盤鍵的keycode?

          • 鼠標(biāo)的坐標(biāo)?

          • 鼠標(biāo)相對于屏幕的坐標(biāo)?

          • shift鍵被按下了嗎?

          • 哪個事件發(fā)生了?

          Option and Select 對象

          • 禁用和啟用下拉列表

          • 獲得有下拉列表的表單的ID

          • 獲得下拉列表的選項數(shù)量

          • 將下拉列表變成多行列表

          • 在下拉列表中選擇多個選項

          • 彈出下拉列表中被選中的選項

          • 彈出下拉列表中被選中的選項的索引

          • 改變下拉列表中被選中的選項的文本

          • 刪除下拉列表中的選項



          Table, TableHeader, TableRow, TableData 對象

          • 改變表格邊框的寬度

          • 改變表格的cellpadding和cellspacing

          • 指定表格的frame

          • 為表格指定規(guī)則

          • 一個行的innerHTML

          • 一個單元格的innerHTML

          • 為表格創(chuàng)建一個標(biāo)題

          • 刪除表格中的行

          • 添加表格中的行

          • 添加表格行中的單元格

          • 單元格內(nèi)容水平對齊

          • 單元格內(nèi)容垂直對齊

          • 對單個單元格的內(nèi)容水平對齊

          • 對單個單元格的內(nèi)容垂直對齊

          • 改變單元格的內(nèi)容

          • 改變行的內(nèi)容

          如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!


          主站蜘蛛池模板: 色天使亚洲综合一区二区| 无码国产精品一区二区免费I6| 亚洲Av永久无码精品一区二区| 国产在线一区视频| 久久精品一区二区东京热| 久久se精品动漫一区二区三区| 久久AAAA片一区二区| 四虎成人精品一区二区免费网站| 久久久不卡国产精品一区二区| 精品无码人妻一区二区免费蜜桃| 国产伦精品一区二区三区视频小说 | 精品国产AV一区二区三区| 精品中文字幕一区在线| 国产精品亚洲专区一区| 精品少妇人妻AV一区二区三区| 丝袜人妻一区二区三区网站| 精品国产区一区二区三区在线观看| 精品不卡一区中文字幕| 中文乱码精品一区二区三区 | 在线精品自拍亚洲第一区| 视频在线一区二区| 欧洲亚洲综合一区二区三区| 国产日本一区二区三区| 日韩AV无码久久一区二区| 91视频国产一区| 国产精品亚洲一区二区麻豆| 亚洲av无一区二区三区| 国产伦精品一区二区三区无广告| 精品国产免费观看一区 | 高清一区二区三区视频| 一区二区三区在线播放| 久久久久一区二区三区| 国产一区二区三区韩国女主播| 亚洲av无码片vr一区二区三区| 欧美av色香蕉一区二区蜜桃小说| 国产一区二区三区播放| 日韩爆乳一区二区无码| 无码喷水一区二区浪潮AV| 韩国福利一区二区三区高清视频| 亚洲电影国产一区| www亚洲精品少妇裸乳一区二区 |