JS基礎(chǔ)
1.document load和document ready的區(qū)別
答:
1.load是當(dāng)頁面所有資源全部加載完成后(包括DOM文檔樹,css文件,js文件慎皱,圖片資源等)提陶,執(zhí)行一個(gè)函數(shù)
問題:如果圖片資源較多左驾,加載時(shí)間較長延刘,onload后等待執(zhí)行的函數(shù)需要等待較長時(shí)間,所以一些效果可能受到影響
2.$(document).ready()是當(dāng)DOM文檔樹加載完成后執(zhí)行一個(gè)函數(shù) (不包含圖片六敬,css等)所以會(huì)比load較快執(zhí)行
在原生的jS中不包括ready()這個(gè)方法碘赖,只有l(wèi)oad方法就是onload事件
2. JavaScript 中如何檢測一個(gè)變量是一個(gè) String 類型?
三種方法(typeof外构、constructor普泡、Object.prototype.toString.call())
①typeof
typeof('123') === "string" // true
typeof '123' === "string" // true
②constructor
'123'.constructor === String // true
③Object.prototype.toString.call()
Object.prototype.toString.call('123') === '[object String]' // true
3.請(qǐng)用 js 去除字符串空格?
replace 正則匹配方法审编、str.trim()方法撼班、JQ 方法:$.trim(str)
方法解析:
方法一:replace 正則匹配方法
去除字符串內(nèi)所有的空格:str = str.replace(/\s/g,"");
去除字符串內(nèi)兩頭的空格:str = str.replace(/^\s| \s * (美元符號(hào))/g,"");
去除字符串內(nèi)左側(cè)的空格:str = str.replace(/^\s/,"");
去除字符串內(nèi)右側(cè)的空格:str = str.replace(/(\s$)/g,"");
示例:
var str = " 6 6 ";
var str_1 = str.replace(/\s*/g, "");
console.log(str_1); //66
var str = " 6 6 ";
var str_1 = str.replace(/^\s*|\s*$/g, "");
console.log(str_1); //6 6//輸出左右側(cè)均無空格
var str = " 6 6 ";
var str_1 = str.replace(/^\s*/, "");
console.log(str_1); //6 6 //輸出右側(cè)有空格左側(cè)無空格
var str = " 6 6 ";
var str_1 = str.replace(/(\s*$)/g, "");
console.log(str_1); // 6 6//輸出左側(cè)有空格右側(cè)無空格
方法二:str.trim()方法
trim()方法是用來刪除字符串兩端的空白字符并返回,trim 方法并不影響原來的字符串本身垒酬,它返回的是一個(gè)新的字符串砰嘁。
缺陷:只能去除字符串兩端的空格,不能去除中間的空格
示例:
var str = " 6 6 ";
var str_1 = str.trim();
console.log(str_1); //6 6//輸出左右側(cè)均無空格
方法三:JQ 方法:
.trim() 函數(shù)用于去除字符串兩端的空白字符勘究。注意:$.trim()函數(shù)會(huì)移除字符串開始和末尾處的所有換行符矮湘,空格(包括連續(xù)的空格)和制表符。如果這些空白字符在字符串中間時(shí)口糕,它們將被保留缅阳,不會(huì)被移除。
示例:
var str = " 6 6 ";
var str_1 = $.trim(str);
console.log(str_1); //6 6//輸出左右側(cè)均無空格
4.js 是一門怎樣的語言景描,它有什么特點(diǎn)
1.腳本語言十办。
JavaScript 是一種解釋型的腳本語言,C、C++等語言先編譯后執(zhí)行,而 JavaScript 是在程序的運(yùn)行過程中逐行進(jìn)行解釋超棺。
2.基于對(duì)象向族。
JavaScript 是一種基于對(duì)象的腳本語言,它不僅可以創(chuàng)建對(duì)象,也能使用現(xiàn)有的對(duì)象。
3.簡單说搅。
JavaScript 語言中采用的是弱類型的變量類型,對(duì)使用的數(shù)據(jù)類型未做出嚴(yán)格的要求,是基于 Java 基本語句和控制的腳本語言,其設(shè)計(jì)簡單緊湊炸枣。
4.動(dòng)態(tài)性。
JavaScript 是一種采用事件驅(qū)動(dòng)的腳本語言,它不需要經(jīng)過 Web 服務(wù)器就可以對(duì)用戶的輸入做出響應(yīng)。
5.跨平臺(tái)性适肠。
JavaScript 腳本語言不依賴于操作系統(tǒng),僅需要瀏覽器的支持霍衫。
5.== 和 === 的不同
==是抽象相等運(yùn)算符,
===是嚴(yán)格相等運(yùn)算符侯养。
==運(yùn)算符是在進(jìn)行必要的類型轉(zhuǎn)換后敦跌,再比較。===運(yùn)算符不會(huì)進(jìn)行類型轉(zhuǎn)換逛揩,所以如果兩個(gè)值不是相同的類型柠傍,會(huì)直接返回false。使用==時(shí)辩稽,可能發(fā)生一些特別的事情惧笛,
例如:
1 == "1"; // true
1 == [1]; // true
1 == true; // true
0 == ""; // true
0 == "0"; // true
0 == false; // true
如果你對(duì)==和===的概念不是特別了解,建議大多數(shù)情況下使用===
6.怎樣添加逞泄、移除患整、移動(dòng)、復(fù)制喷众、創(chuàng)建和查找節(jié)點(diǎn)各谚?
1)創(chuàng)建新節(jié)點(diǎn)
createDocumentFragment() //創(chuàng)建一個(gè) DOM 片段
createElement() //創(chuàng)建一個(gè)具體的元素
createTextNode() //創(chuàng)建一個(gè)文本節(jié)點(diǎn)
2)添加、移除到千、替換昌渤、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替換
insertBefore() //插入
3)查找
getElementsByTagName() //通過標(biāo)簽名稱
getElementsByName() //通過元素的 Name 屬性的值
getElementById() //通過元素 Id,唯一性
7.事件委托是什么
利用事件冒泡的原理憔四,讓自己的所觸發(fā)的事件膀息,讓他的父元素代替執(zhí)行!
解析:
1了赵、那什么樣的事件可以用事件委托履婉,什么樣的事件不可以用呢?
適合用事件委托的事件:click斟览,mousedown毁腿,mouseup,keydown苛茂,keyup已烤,keypress。
值得注意的是妓羊,mouseover 和 mouseout 雖然也有事件冒泡胯究,但是處理它們的時(shí)候需要特別的注意,因?yàn)樾枰?jīng)常計(jì)算它們的位置躁绸,處理起來不太容易裕循。
不適合的就有很多了臣嚣,舉個(gè)例子,mousemove剥哑,每次都要計(jì)算它的位置硅则,非常不好把控,在不如說 focus株婴,blur 之類的怎虫,本身就沒用冒泡的特性,自然就不用事件委托了困介。
2大审、為什么要用事件委托
1.提高性能
?ul?
?li?蘋果?/li?
?li?香蕉?/li?
?li?鳳梨?/li?
?/ul?
// good
document.querySelector('ul').onclick = (event) =? {
let target = event.target
if (target.nodeName === 'LI') {
console.log(target.innerHTML)
}
}
// bad
document.querySelectorAll('li').forEach((e) =? {
e.onclick = function() {
console.log(this.innerHTML)
}
})
2.新添加的元素還會(huì)有之前的事件。
3座哩、事件冒泡與事件委托的對(duì)比
事件冒泡:box 內(nèi)部無論是什么元素徒扶,點(diǎn)擊后都會(huì)觸發(fā) box 的點(diǎn)擊事件
事件委托:可以對(duì) box 內(nèi)部的元素進(jìn)行篩選
4、事件委托怎么取索引根穷?
?ul id="ul"?
?li?aaaaaaaa?/li?
?li?事件委托了 點(diǎn)擊當(dāng)前酷愧,如何獲取 這個(gè)點(diǎn)擊的下標(biāo)?/li?
?li?cccccccc?/li?
?/ul?
?script?
window.onload = function () {
var oUl = document.getElementById("ul");
var aLi = oUl.getElementsByTagName("li");
oUl.onclick = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == "li") {
var that = target;
var index;
for (var i = 0; i ? aLi.length; i++)
if (aLi[i] === target) index = i;
if (index ?= 0) alert('我的下標(biāo)是第' + index + '個(gè)');
target.style.background = "red";
}
}
}
?/script?
拓展:
鍵盤事件:keydown/ keypress /keyup
鼠標(biāo)事件:mousedown/ mouseup /mousemove /mouseout /mouseover
8.javascript 對(duì)象的幾種創(chuàng)建方式
第一種:Object 構(gòu)造函數(shù)創(chuàng)建
var Person = new Object();
Person.name = "Nike";
Person.age = 29;
這行代碼創(chuàng)建了 Object 引用類型的一個(gè)新實(shí)例,然后把實(shí)例保存在變量 Person 中缠诅。
第二種:使用對(duì)象字面量表示法
var Person = {}; //相當(dāng)于 var Person = new Object();
var Person = {
name: 'Nike';
age: 29;
}
對(duì)象字面量是對(duì)象定義的一種簡寫形式,目的在于簡化創(chuàng)建包含大量屬性的對(duì)象的過程乍迄。也就是說管引,第一種和第二種方式創(chuàng)建對(duì)象的方法其實(shí)都是一樣的,只是寫法上的區(qū)別不同在介紹第三種的創(chuàng)建方法之前闯两,我們應(yīng)該要明白為什么還要用別的方法來創(chuàng)建對(duì)象褥伴,也就是第一種,第二種方法的缺點(diǎn)所在:它們都是用了同一個(gè)接口創(chuàng)建很多對(duì)象漾狼,會(huì)產(chǎn)生大量的重復(fù)代碼重慢,就是如果你有 100 個(gè)對(duì)象,那你要輸入 100 次很多相同的代碼逊躁。那我們有什么方法來避免過多的重復(fù)代碼呢似踱,就是把創(chuàng)建對(duì)象的過程封裝在函數(shù)體內(nèi),通過函數(shù)的調(diào)用直接生成對(duì)象稽煤。
第三種:使用工廠模式創(chuàng)建對(duì)象
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
};
return o;
}
var person1 = createPerson("Nike", 29, "teacher");
var person2 = createPerson("Arvin", 20, "student");
在使用工廠模式創(chuàng)建對(duì)象的時(shí)候核芽,我們都可以注意到,在 createPerson 函數(shù)中酵熙,返回的是一個(gè)對(duì)象轧简。那么我們就無法判斷返回的對(duì)象究竟是一個(gè)什么樣的類型。于是就出現(xiàn)了第四種創(chuàng)建對(duì)象的模式匾二。
第四種:使用構(gòu)造函數(shù)創(chuàng)建對(duì)象
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
};
}
var person1 = new Person("Nike", 29, "teacher");
var person2 = new Person("Arvin", 20, "student");
對(duì)比工廠模式哮独,我們可以發(fā)現(xiàn)以下區(qū)別:
1.沒有顯示地創(chuàng)建對(duì)象
2.直接將屬性和方法賦給了 this 對(duì)象
3.沒有 return 語句
4.終于可以識(shí)別的對(duì)象的類型拳芙。
對(duì)于檢測對(duì)象類型,我們應(yīng)該使用 instanceof 操作符皮璧,我們來進(jìn)行自主檢測:
alert(person1 instanceof Object); //ture
alert(person1 instanceof Person); //ture
alert(person2 instanceof Object); //ture
alert(person2 instanceof Object); //ture
同時(shí)我們也應(yīng)該明白舟扎,按照慣例,構(gòu)造函數(shù)始終要應(yīng)該以一個(gè)大寫字母開頭恶导,而非構(gòu)造函數(shù)則應(yīng)該以一個(gè)小寫字母開頭浆竭。那么構(gòu)造函數(shù)確實(shí)挺好用的,但是它也有它的缺點(diǎn):就是每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍惨寿,方法指的就是我們在對(duì)象里面定義的函數(shù)邦泄。如果方法的數(shù)量很多,就會(huì)占用很多不必要的內(nèi)存裂垦。于是出現(xiàn)了第五種創(chuàng)建對(duì)象的方法
第五種:原型創(chuàng)建對(duì)象模式
function Person() {}
Person.prototype.name = "Nike";
Person.prototype.age = 20;
Person.prototype.jbo = "teacher";
Person.prototype.sayName = function() {
alert(this.name);
};
var person1 = new Person();
person1.sayName();
使用原型創(chuàng)建對(duì)象的方式顺囊,可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法。如果是使用原型創(chuàng)建對(duì)象模式蕉拢,請(qǐng)看下面代碼:
function Person() {}
Person.prototype.name = "Nike";
Person.prototype.age = 20;
Person.prototype.jbo = "teacher";
Person.prototype.sayName = function() {
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name); //'Greg' --來自實(shí)例
alert(person2.name); //'Nike' --來自原型
當(dāng)為對(duì)象實(shí)例添加一個(gè)屬性時(shí)特碳,這個(gè)屬性就會(huì)屏蔽原型對(duì)象中保存的同名屬性。這時(shí)候我們就可以使用構(gòu)造函數(shù)模式與原型模式結(jié)合的方式晕换,構(gòu)造函數(shù)模式用于定義實(shí)例屬性午乓,而原型模式用于定義方法和共享的屬性
第六種:組合使用構(gòu)造函數(shù)模式和原型模式
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}
Person.prototype = {
constructor: Person,
sayName: function() {
alert(this.name);
};
}
var person1 = new Person('Nike', 20, 'teacher');
9.JavaScript 繼承的方式和優(yōu)缺點(diǎn)
六種方式
一、原型鏈繼承
缺點(diǎn):
1.引用類型的屬性被所有實(shí)例共享
2.在創(chuàng)建 Child 的實(shí)例時(shí)闸准,不能向 Parent 傳參
二益愈、借用構(gòu)造函數(shù)(經(jīng)典繼承)
優(yōu)點(diǎn):
1.避免了引用類型的屬性被所有實(shí)例共享
2.可以在 Child 中向 Parent 傳參
缺點(diǎn):
方法都在構(gòu)造函數(shù)中定義,每次創(chuàng)建實(shí)例都會(huì)創(chuàng)建一遍方法夷家。
三蒸其、組合繼承
優(yōu)點(diǎn):
融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn),是 JavaScript 中最常用的繼承模式库快。
四摸袁、原型式繼承
缺點(diǎn):
包含引用類型的屬性值始終都會(huì)共享相應(yīng)的值,這點(diǎn)跟原型鏈繼承一樣义屏。
五靠汁、寄生式繼承
缺點(diǎn):
跟借用構(gòu)造函數(shù)模式一樣,每次創(chuàng)建對(duì)象都會(huì)創(chuàng)建一遍方法闽铐。
六膀曾、寄生組合式繼承
優(yōu)點(diǎn):
1.這種方式的高效率體現(xiàn)它只調(diào)用了一次 Parent 構(gòu)造函數(shù),并且因此避免了在 Parent.prototype 上面創(chuàng)建不必要的阳啥、多余的屬性添谊。
2.與此同時(shí),原型鏈還能保持不變察迟;
3.因此斩狱,還能夠正常使用 instanceof 和 isPrototypeOf耳高。
開發(fā)人員普遍認(rèn)為寄生組合式繼承是引用類型最理想的繼承范式
10.復(fù)雜數(shù)據(jù)類型如何轉(zhuǎn)變?yōu)樽址?/h2>
首先,會(huì)調(diào)用 valueOf 方法所踊,如果方法的返回值是一個(gè)基本數(shù)據(jù)類型泌枪,就返回這個(gè)值,
如果調(diào)用 valueOf 方法之后的返回值仍舊是一個(gè)復(fù)雜數(shù)據(jù)類型秕岛,就會(huì)調(diào)用該對(duì)象的 toString 方法碌燕,
如果 toString 方法調(diào)用之后的返回值是一個(gè)基本數(shù)據(jù)類型,就返回這個(gè)值继薛,
如果 toString 方法調(diào)用之后的返回值是一個(gè)復(fù)雜數(shù)據(jù)類型修壕,就報(bào)一個(gè)錯(cuò)誤。
解析:
var obj = {
valueOf: function() {
return 1;
}
};
console.log(obj + ""); //'1'
var obj = {
valueOf: function() {
return [1, 2];
}
};
console.log(obj + ""); //'[object Object]';
var obj = {
valueOf: function() {
return [1, 2];
},
toString: function() {
return 1;
}
};
console.log(obj + ""); //'1';
var obj = {
valueOf: function() {
return [1, 2];
},
toString: function() {
return [1, 2, 3];
}
};
console.log(obj + "");
// 報(bào)錯(cuò) Uncaught TypeError: Cannot convert object to primitive value
拓展:
var arr = [
new Object(),
new Date(),
new RegExp(),
new String(),
new Number(),
new Boolean(),
new Function(),
new Array(), Math
]
console.log(arr.length) // 9
for (var i = 0; i ? arr.length; i++) {
arr[i].valueOf = function() {
return [1, 2, 3]
}
arr[i].toString = function() {
return 'toString'
}
console.log(arr[i] + '')
}
1遏考、若 return [1,2,3]處為 return "valueof"慈鸠,得到的返回值是 valueof toString 7valueof
說明:其他八種復(fù)雜數(shù)據(jù)類型是先調(diào)用 valueOf 方法,時(shí)間對(duì)象是先調(diào)用 toString 方法
2灌具、改成 return [1,2,3]青团,得到的返回值是 9toString
說明:執(zhí)行 valueof 后都來執(zhí)行 toString