内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
Element类型用于表示XML或HTML元素,提供了对元素标签名、子节点及特性的访问;
Element类继承自Node接口;它继承了Node接口中的所有属性和方法,比如parentNode、childNode等;同时,它在Node接口的基础上扩展了自己的属性和方法;
Element类型的特征:
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属性:表示元素的标识符,与全局属性id对应;
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属性一样,可以返回元素的标签名,在HTML文档中返回大写,在XML中返回原生,因此在使用tagName时,最后使用toLowerCase()转换;
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类的基础上,并添加了一些属性,这些属性分别对应于每个HTML元素中都存在的标准特性:id、title、lang、dir、className;
这些属性都是可读可写的,并且也是动态的;
<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特性(属性):
每个元素都有若干个特性,这些特性的用途是给出相应元素或其内容的附加信息;DOM为Element对象定义了一些API来获取或设置这些XML或HTML属性(特性);
操作特性主要有三个方法:
getAttribute()、setAttribute()、removeAttribute();这些方法可以针对任何特性使用,包括那些以HTMLElement类型属性的形式定义的特性;
getAttribute(attributeName)方法:
返回元素上一个指定的特性值,如果指定的特性不存在,则返回null或 "";特性的名称不区分大小写;
如果取得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元素的标准特性),但要注意,根据HTML5的规范,自定义特性应该加上data-前缀以便验证;
console.log(mydiv.getAttribute("custom")); // customvalue
console.log(mydiv.getAttribute("data-name")); // wangwei
任何元素的所有特性,都可以通过DOM元素本身的属性来访问,不过,只有公认的(非自定义)特性才会以属性的形式添加到DOM对象中;但IE可以为自定义特性创建属性;
console.log(mydiv.id);
console.log(mydiv.className);
console.log(mydiv.myname); // undefined
console.log(mydiv.align); // left,认为align是公认的
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属性名不区分大小写,但Javascript属性名则大小写敏感;从HTML属性名转换到Javascript属性名应该采用小写,但是如果属性名包含不止一个单词,则采用小驼峰式,如:defaultCheded和tabIndex;
有些HTML属性名在Javascript中是保留字,对于这些属性,一般的规则是为该属性名加前缀”html”,如,HTML的for属性在Javascript中变为htmlFor属性,class属性比较特殊,它在Javascript中变成className属性;
表示HTML属性的值通常是字符串,但当属性为布尔值或数值时,Javascript中对应的属性也是布尔值或数值,而不是字符串;
<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特性,有关CSS编程,后面我们会讲到);
事件处理程序特性,类似于onclick等这样的事件处理程序,当在特性中使用时,onclick中包含的就是JS代码,使用getAttribute()会返回相应的代码的字符串,但在访问onclick属性时,会返回一个Javascript函数;
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)方法:
设置指定元素上的某个特性值,如果特性已经存在,则更新该值,否则,使用指定的名称和值添加一个新的特性;
该接受两个参数:要设置的特性名和值;
此方法可以操作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
通过该方法设置的特性名会被统一转换成小写形式,即“ID”最终会变成“id”;
mydiv.setAttribute("ID","myID"); // id
mydiv.setAttribute("CID","customID"); // cid
布尔特性只要出现在元素上就会被认为是 true,无论它的值是什么;一般来说,应该将 value 设置为空字符串,也有人使用这个属性的名称作为值,虽然不会出现什么问题,但不规范的;
var txtInput=document.getElementById("txtInput");
txtInput.setAttribute("readonly",true);// 会渲染成readonly="true"
txtInput.setAttribute("readonly",""); // 渲染成readonly
console.log(txtInput.readOnly); // true
因为所有特性都是属性,所以直接给属性赋值可以设置特性的值,但如果添加的是一个自定义的属性,该属性不会自动成为元素的特性;
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()方法设置class,但不能通过属性设置class,因为class是关键字,需要className进行属性设置;
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()需要一个特性参数,判断该元素是否包含有指定的特性,而hasAttributes()检测的是否有特性,具体是什么特性,则不是它所关心的了;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.hasAttribute("title"));
if(!mydiv.hasAttribute("align"))
mydiv.setAttribute("align","center");
console.log(mydiv.hasAttributes()); // true
当属性为布尔值时,hasAttribute()方法特别有用,比如HTML表单的disabled属性,只要判断它有没有这个属性即可,不用管它的值;
attributes属性:
返回该元素所有属性节点的一个实时集合,该集合是一个NamedNodeMap对象,是一个只读的类数组对象,只有Element类型拥有;该属性与NodeList类似,也是一个动态的集合;也可以使用索引方式访问,并且可以枚举;
元素的每个特性都由一个Attr节点表示,Attr对象是一个特殊的Node,不会像普通的Node一样去使用;Attr的name和value属性返回该属性的名字和值;
每个Attr节点都保存在NamedNodeMap对象中;此节点都有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对象:
表示一个无顺序的属性节点 Attr 对象的集合;其是类数组对象,同时也是动态的;
属性和方法:
length属性:返回映射(map)中对象的数量;
getNamedItem(name):返回给定名称name的属性节点;
item(pos):返回位于数字pos位置处的节点;(注:各个浏览器会返回不同的顺序);
setNamedItem(node):向列表中添加或替换特性节点;
removeNamedItem(name):从列表中移除特性为name的节点;与removeAttribute()相同,但其会返回被删除的特性(Attr)节点;
可以通过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结构序列化为XML或HTML字符串时,多数都会涉及遍历元素特性;
// 迭代元素的所有特性,构造成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循环
// 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));
创建Element元素:
document.createElement(tagName)方法:用于创建一个由标签名称tagName指定的HTML元素,如果用户代理无法识别tagName,则会生成一个未知 HTML 元素;
该方法只接受一个参数,即要创建元素的标签名;此标签名在HTML中不区分大小写,在XML(包括XHTML)中,是区分大小写的;
在创建新元素的同时,也为新元素设置了ownerDocument属性;同时还可以操作元素的特性,为它添加子节点,以及执行其他操作;
新创建的元素,必须添加到文档树中,才能显示出来,可以利用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的子节点:
元素可以有任意数目的子节点和后代节点,这些子节点可能是元素、文本、注释处处理指令;但HTML中的空白也会被解析为文本节点;因此在执行某项操作时,要先检查一下nodeType属性;
<!-- 结构 -->
<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);
// }
元素节点也支持getElementsByTagName() 方法,可以通过它获得某个特定的标签名的子节点或后代节点;
var myList=document.getElementById("myList");
var lis=myList.getElementsByTagName("li");
console.log(lis); // dom.html:23 HTMLCollection(3)
自定义Element的方法:
Element和HTMLDocument等类型都像String和Array一样是类,它们不是构造函数,但它们有原型对象,可以自定义方法扩展它;
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前端开发之Javascript-零点程序员-王唯
要说 js 的深浅拷贝,就不得不提 js 的两大数据类型:基本数据类型和引用类型。基本数据类型的变量名和值都存储在栈中,对于引用类型的变量名存储在栈中,而值存储在堆中。由于存储方式不同,所以导致了他们复制的时候方式不同。
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精准拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另外一个对象。
深拷贝是将一个对象从内存中完整的拷贝一份出来,从内存堆中存放一个新的对象。这是两个对象,所以修改其中一个,另外一个不会受影响。
深浅拷贝主要针对的是引用类型,简单数据类型不受影响。
相关笔试题
var person={
name:"前端人",
hobby:['学习','敲代码','潜水']
}
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=["内卷"]
console.info(person.hobby)
console.info(p1.hobby)
/*运行结果:
前端人
Web Person
["学习", "敲代码", "潜水"]
["内卷"]
*/
js 数据类型一共有 8 种,分为两大类:基本类型和引用类型。
它们的数据类型分别为:
基本类型:string、number、boolean、null、undefined、symbol、bigint
引用类型:object
相关面试题
// 注意:其他类型与数值进行相加时,其他类型的转为 number 类型
console.log( true+1 ) // 2
console.log( undefined +1 ) // NaN
console.log( null ) //object
console.log( undefined ) // undefined
共有 6 种方式,分别为:
它们的区别介绍:
1、async:为 <script>标签定义了 async 属性。async 和 html 解析是同步的,不是顺次执行 js 脚本,谁先加载完成先执行谁。
<script async type="text/javascript" src="demo1.js" ></script>
<script async type="text/javascript" src="demo2.js" ></script>
2、defer 会等到 html 解析完成之后再执行 js 代码,如果有多个脚本时,会按照顺序依次执行脚本。
<script defer type="text/javascript" src="demo1.js" ></script>
3、js 最后加载
把 js 外部引入的文件放置在页面的底部,让 js 最后加载,从而加快页面加载速度。
4、利用 setTimeout
5、动态创建 DOM 的方式
var element=document.createElement("script");
element.src="box.js";
document.body.appendChild(element);
这种方式通过操作动态加载 js 文件,不触发的时候不加载,减少页面文件大小,加快加载速度。
6、使用 jQuery 的 getScript 方法
$.getScript( "box.js",function(){//回调函数,成功获取文件后执行的函数
console.log("脚本加载完成")
});
相关面试题:
<!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 ,并进行一系列操作应该如何延迟加载 js 文件呢?
作用域通俗地讲,就是指一个变量的作用范围。分为全局作用域和函数作用域。
全局作用域
函数作用域(局部)
函数在被调用的时候会先进行预编译:
全局作用域预编译:
函数作用域预编译:
相关面试题:
<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>
// 运行结果:
/*
function a(){}
12
function c(){}
undefined
undefined
function (){}
function c(){}
*/
null 和 undefined 两个都表示无的值。
作者设计 js 的时候,借鉴的 java 语言先设计的 null 。null 使用的时候会被隐式转化成 0,不容易发现错误。
console.log( number(null) ) //0
undefined 是为了填补 null 的坑。所以后来又新增了 undefined 。
console.log( number(undefined) ) //NaN
实现 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.1、什么是闭包?
闭包就是函数嵌套函数,通过函数内的函数访问变量的规则,实现外部访问函数内的变量。
7.2、闭包的特点:
实例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、闭包优点:
防抖和节流就是闭包的经典应用。
7.4、闭包缺点:
8.1、什么是防抖函数?
当持续触发事件,一定时间内没有再触发事件,事件处理函数才会执行一次,如果在设定的时间到来之前又触发了事件,就会重新计时。
防抖函数常见的实际应用:使用 echart 的时候,浏览器 resize 时,需要重新绘制图表大小,还有典型的输入框搜索应用。
8.2、节流函数是什么?
当持续触发事件的时候,保证一段时间内只调用一次事件处理函数,一段时间内,只允许做一件事情。
防抖和节流主要是用来限制触发频率较高的事件,再不影响效果的前提条件下,降低事件触发频率,减小浏览器或服务器的压力,提升用户体验效果。
方法1: new set()
return Array.from(new Set(arr))
// 或
return [...new Set(arr)]
方法2:使用两次循环
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 实现
let arr1=[]
for(var i=0;i<arr.length;i++){
if( arr1.indexOf(arr[i])===-1 ){
arr1.push(arr[i])
}
}
return arr1
方法4:includes 实现
let arr1=[]
for(var i=0;i<arr.length;i++){
if( !arr1.includes(arr[i]) ){
arr1.push(arr[i])
}
}
return arr1
方法5:filter 实现
array.indexOf(item,start) start 表示开始检索的位置。
return arr.filter(( item, index )=>{
return arr.indexOf( item, 0 )==index
})
三者都是改变函数执行的上下文,即改变 this 指向。
它们之间的区别为:
使用场景:
1、需要改变某个函数的this指向时
2、当参数较少时可以使用call,参数较多可以使用apply以数组的方式传递
3、当需要重复调用时,可以使用bind新定义一个方法
方法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 )
该方法不够严谨。
方法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 )
slice 是用来截取字符串的,返回一个新数组,但不会影响原数组。
使用语法:
arr.slice( start , end )
截取 arr 数组,从 start 开始到 end 结束,第二个参数是可选参数,没有时从 start 开始截取到结尾。
如果 start 参数是负数时,就会从 arr.lengtn + start 开始截取到结束。
var arr=['a','b','c','d','e']
console.log( arr.slice(-3) ) // ["c", "d", "e"]
console.log(arr) //["a", "b", "c", "d", "e"]
splice 是一个更强大的方法,可以添加、删除、替换数组元素,返回的是被删除元素,它的操作会改变原数组。
使用语法:
splice( start, n, new )
从 start 开始,删除 n 个元素,然后把 new 添加到 start 元素之后。第三个参数为可选参数
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"]
==比较的是值,===除了比较值,还比较类型。
console.log( [1,2]=='1,2' ) // true
console.log( [1,2]==='1,2' ) //false
valueOf 方法返回 Math 对象的原始值,通常由 javascript 在后台自动调用,并不显示的出现在代码中。
console.log([1,2].valueOf()) //[1,2]
console.log('1,2'.valueOf()) //[1,2]
// 所以
console.log( [1,2]=='1,2' ) // true
不管是字符串和数字比较,还是布尔值和数字比较,都会使用 valueOf 隐式转换。
总结:==需要使用 valueOf() 进行隐式转换,所以性能差。===会避开一些不必要的麻烦。
大厂笔试题:
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()
/*
运行结果:
window name
p1 name
window name
p2 name
*/
这是一道关于 this 指向的面试题,接下来我们就说说 this 是如何指向的?
this 对象是运行时基于函数的执行环境绑定的:
第 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) //前端人
特点:
第 2 种:借用构造函数
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
特点:
还有组合式继承、ES6 的继承 和 寄生组合继承等等。每种继承方式都有各自的特点和缺点。
JavaScript 语言是一门弱类型语言,存在许多类型错误,因此 ES6 引入了严格模式概念。
如果不加 ‘use strict’ 常规模式下就是属于非严格模式。
严格模式
在 js 文件顶部添加 ‘use strict’ 就属于严格模式,严格模式也可以指定在函数内部。
<script>
'use strict'
//或者函数内部
(function(){
'use strict'
})()
</script>
严格模式,是为 js 定义来了一种不同的解析与执行模型,在严格模式下,ECMAScipt 3 中一些不解和不确定的行为将得到处理,而且会对不安全的操作会抛出异常。‘use strict’ 会告诉浏览器引擎可以切换到严格模式执行。
严格模式与非严格模式区别
严格模式 | 非严格模式 |
变量必须声明才能赋值 | 变量不进行声明,可直接赋值 |
不能使用 delete 字符删除变量或对象 | 可以使用 delete 删除 |
函数参数变量名不允许重复 | 变量名重复,获取最后最后那个值 |
普通函数内的 this 为 undefined | 普通函数内的 this 为 window |
不允许使用八进制 | 允许任意进制 |
eval 和 arguments 当做关键字,不能被赋值和用作变量名 | 可以使用 eval 、arguments 作为变量名 |
call、apply 传入 null undefined 保持原样不被转为window | 默认转为 window 对象 |
限制对调用栈的检测能力,访问 arguments.callee 会抛出异常 | arguments.callee 运行正常 |
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
阿里面试题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>
// 运行结果 4 1 3 5 2
// 如果已经了解事件运行机制,就可以跳过该问题了
事件循环机制,event-loop 。包含三部分:调用栈、消息队列、微任务队列。
事件循环开始的时候,会从全局一行一行的执行代码,遇到函数调用的时候,就会压入调用栈中,当函数执行完成之后,弹出调用栈。
// 如:代码会一行一行执行,函数全部调用完成之后清空调用栈
function f1(){
console.log(1)
}
function f2(){
f1()
console.log(2)
}
f2()
// 执行结果 1 2
如果遇到 fetch、setInterval、setTimeout 异步操作时,函数调用压入调用栈时,异步执行内容会被加入消息队列中,消息队列中的内容会等到调用栈清空之后才会执行。
// 如:
function f1(){
console.log(1)
}
function f2(){
setTimeout(()=>{
console.log(2)
},0)
f1()
console.log(3)
}
f2()
// 执行结果 :1 3 2
遇到 promise、async、await 异步操作时,执行内容会被加入微任务队列中,会在调用栈清空之后立即执行。
调用栈加入的微任务队列会立即执行。
如
let p=new Promise(resolve=>{
console.log('立即执行')
resolve(1) //在 then 调用中执行
})
微任务队列中内容优先执行,所以比消息队列中的内容执行得早。
了解这些知识后,再试一下最前面的那道面试题,应该就没什么问题了。
这个问题就留给读到最后,能够坚持学习的人,问问我们自己有什么是我们擅长的?在哪块领域是我们占据竞争优势的?
使用内置JavaScript的对象实例。
Document 对象
使用 document.write() 输出文本
使用 document.write() 输出 HTML
返回文档中锚的数目
返回文档中第一个锚的 innerHTML
返回文档中表单的数目
返回文档中第一个表单的名字
返回文档中的图像数
返回文档中第一个图像的ID
返回文档中的链接数
返回文档中的第一个链接的ID
返回文档中的所有cookies的名称/值对
返回加载的文档的服务器域名
返回文档的最后一次修改时间
返回加载的当前文档的URL
返回文档的标题
返回文档的完整的URL
打开输出流,向流中输入文本
write() 和 writeln()的不同
用指定的ID弹出一个元素的innerHTML
用指定的Name弹出元素的数量
用指定的tagname弹出元素的数量
更多的Document 对象的例子,在我们的JavaScript 参考手册。
Anchor 对象
返回和设置链接的charset属性
返回和设置链接的href属性
返回和设置链接的hreflang属性
返回一个锚的名字
返回当前的文件和链接的文档之间的关系
改变链接的target属性
返回一个链接的type属性的值
更多的Anchor 对象的例子,在我们的JavaScript 参考手册。
Area 对象
返回图像映射某个区域的替代文字
返回图像映射某个区域的坐标
返回一个区域的href属性的锚部分
返回的主机名:图像映射的某个区域的端口
返回图像映射的某个区域的hostname
返回图像映射的某个区域的port
返回图像映射的某个区域的href
返回图像映射的某个区域的pathname
返回图像映射的某个区域的protocol
返回一个区域的href属性的querystring部分
返回图像映射的某个区域的shape
返回图像映射的某个区域的target的值
更多的Area 对象的例子,在我们的JavaScript 参考手册。
Base 对象
返回页面上所有相对URL的基URL
返回页面上所有相对链接的基链接
更多的Base 对象对象的例子,在我们的JavaScript 参考手册。
Button 对象
当点击完button不可用
返回一个button的name
返回一个button的type
返回一个button的value
返回一个button所属表的ID
更多Button 对象实例在我们的JavaScript 参考手册。
Form 对象
返回一个表单中所有元素的value
返回一个表单acceptCharset属性的值
返回一个表单action属性的值
返回表单中的enctype属性的值
返回一个表单中元素的数量
返回发送表单数据的方法
返回一个表单的name
返回一个表单target属性的值
重置表单
提交表单
更多Button 对象实例在我们的JavaScript 参考手册。
Frame/IFrame 对象
对iframe排版
改变一个包含在iframe中的文档的背景颜色
返回一个iframe中的frameborder属性的值
删除iframe的frameborder
改变iframe的高度和宽度
返回一个iframe中的longdesc属性的值
返回一个iframe中的marginheight属性的值
返回一个iframe中的marginwidth属性的值
返回一个iframe中的name属性的值
返回和设置一个iframe中的scrolling属性的值
改变一个iframe的src
更多Frame/IFrame 对象实例在我们的JavaScript 参考手册。
Image 对象
对image排版
返回image的替代文本
给image加上border
改变image的高度和宽度
设置image的hspace和vspace属性
返回image的longdesc属性的值
创建一个链接指向一个低分辨率的image
返回image的name
改变image的src
返回一个客户端图像映射的usemap的值
更多Image 对象实例在我们的JavaScript 参考手册。
Event 对象
被按下的键盘键的keycode?
鼠标的坐标?
鼠标相对于屏幕的坐标?
shift键被按下了吗?
哪个事件发生了?
Option and Select 对象
禁用和启用下拉列表
获得有下拉列表的表单的ID
获得下拉列表的选项数量
将下拉列表变成多行列表
在下拉列表中选择多个选项
弹出下拉列表中被选中的选项
弹出下拉列表中被选中的选项的索引
改变下拉列表中被选中的选项的文本
删除下拉列表中的选项
Table, TableHeader, TableRow, TableData 对象
改变表格边框的宽度
改变表格的cellpadding和cellspacing
指定表格的frame
为表格指定规则
一个行的innerHTML
一个单元格的innerHTML
为表格创建一个标题
删除表格中的行
添加表格中的行
添加表格行中的单元格
单元格内容水平对齐
单元格内容垂直对齐
对单个单元格的内容水平对齐
对单个单元格的内容垂直对齐
改变单元格的内容
改变行的内容
如您还有不明白的可以在下面与我留言或是与我探讨QQ群308855039,我们一起飞!
*请认真填写需求信息,我们会在24小时内与您取得联系。