1. bind方法
bind() 函數(shù)會(huì)創(chuàng)建一個(gè)新函數(shù)(稱為綁定函數(shù))
- bind是ES5新增的一個(gè)方法
- 傳參和call類似
- 不會(huì)執(zhí)行對(duì)應(yīng)的函數(shù),call或apply會(huì)自動(dòng)執(zhí)行對(duì)應(yīng)的函數(shù)
- 返回對(duì)函數(shù)的引用
- 語法
fun.bind(thisArg[, arg1[, arg2[, ...]]])
<script>
var obj = {
name: "阿馬"
}
function add(a, b) {
console.log(this);
console.log(a + b)
}
var new1 = add.bind(obj, 1, 2)
new1();
//返回的不是同一個(gè)函數(shù)
console.log(new1 === add);
</script>
2. querySelector和getxxxByxxx的區(qū)別
getXXXByXXX 獲取的是動(dòng)態(tài)集合,querySelector獲取的是靜態(tài)集合。
簡(jiǎn)單的說就是,動(dòng)態(tài)就是選出的元素會(huì)隨文檔改變,靜態(tài)的不會(huì),取出來之后就和文檔的改變無關(guān)了。
3. 函數(shù)的遞歸
前提:
arguments.callee打印出來的就是函數(shù)本身,它可以在函數(shù)遞歸調(diào)用的時(shí)候,派上用場(chǎng)
arguments.callee 打印出來的就是函數(shù)本身,它可以在函數(shù)遞歸調(diào)用的時(shí)候,派上用場(chǎng)
function fn(){
console.log(arguments.length);
console.log(arguments.callee);
}
fn();
能用遞歸的地方都可以不用。
函數(shù)的遞歸調(diào)用,就是函數(shù)在內(nèi)部自己調(diào)自己
函數(shù)的遞歸調(diào)用是一把雙刃劍,如果設(shè)計(jì)的好,可以幫我們簡(jiǎn)單的處理事情,如果設(shè)計(jì)不好就是災(zāi)難
- 函數(shù)的遞歸要想設(shè)計(jì)好必須有兩個(gè)條件
- 必須有一個(gè)明顯的結(jié)束條件,不能一直遞歸下去
- 每一次調(diào)用都要有一個(gè)趨近結(jié)束條件的趨勢(shì)
// 遞歸實(shí)現(xiàn)階乘
function f(n){
if(n == 1){
return 1
}
return n * f(n-1);
}
var a = f(5);
console.log(a); // 120
4. 終極原型鏈
任何的函數(shù)對(duì)象的prototype都和這個(gè)函數(shù)對(duì)象實(shí)例化的對(duì)象proto都指向同一個(gè)對(duì)象


5. 閉包
為什么要學(xué)習(xí)閉包?
先必須理解Javascript特殊的變量作用域。
變量的作用域無非就是兩種:全局變量和局部變量。
- 全局變量 可以在局部作用域內(nèi)訪問
- 局部變量 不可以在全局作用域內(nèi)訪問的
- 函數(shù)內(nèi)部聲明變量的時(shí)候,一定要使用var命令。如果不用的話,實(shí)際上聲明了一個(gè)全局變量
- 閉包的產(chǎn)生條件/使用步驟
- 在外部函數(shù)f1內(nèi) 嵌套一個(gè)內(nèi)部函數(shù)f2
- 內(nèi)部函數(shù)f2 引用外部函數(shù)f1的局部變量a
- 外部函數(shù)f1 返回內(nèi)部函數(shù)f2的函數(shù)體
- 內(nèi)部函數(shù)f2和外部函數(shù)f1都要執(zhí)行
function f1(){
var a = 1;
function f2(){
return a;
}
return f2;
}
// 返回的是就是f2的函數(shù)體
var result = f1();
var aaaa = result();
console.log(aaaa);
-
閉包到底是什么?
- 理解一: 閉包是嵌套的內(nèi)部函數(shù)(絕大部分人)
- 理解二: 閉包是包含外部函數(shù)的局部變量的對(duì)象(極少數(shù)人)
- 理解三: 所謂的閉包是一個(gè)引用關(guān)系,該引用關(guān)系存在于內(nèi)部函數(shù)中,引用的是外部函數(shù)的局部變量的對(duì)象(深入理解)
-
常見的閉包
- 將函數(shù)作為另一個(gè)函數(shù)的返回值
- 將內(nèi)部函數(shù)作為外部函數(shù)的返回值
-
閉包的作用 ( 企業(yè)開發(fā)中我們不允許使用全局變量 )
- 延長外部函數(shù)變量的生命周期
- 讓函數(shù)外部可以操作(讀寫)到函數(shù)內(nèi)部的數(shù)據(jù)(變量/函數(shù))/函數(shù)外部可以引用函數(shù)內(nèi)部的變量
- 注意: 瀏覽器為了性能,后期將外部函數(shù)中不被內(nèi)部函數(shù)使用的變量清除了
function buyLip(){
var money = 500;
function f2(){
money -= 100;
console.log(money);
}
return f2;
}
var result = buyLip();
result(); // 400
result(); // 300
- 閉包使用中的坑點(diǎn) ( ()()會(huì)重置初始化原始外部變量的值 )
function buyLip(){
var money = 500;
function f2(){
money -= 100;
console.log(money);
}
return f2;
}
buyLip()(); // 500
buyLip()(); // 500
-
閉包的缺點(diǎn)和解決(內(nèi)存泄漏和內(nèi)存溢出)
- 內(nèi)存泄漏 : 內(nèi)存無法釋放;
- 內(nèi)存溢出 : 內(nèi)存被撐爆;
- f = null; 解決方式;
function fn(){
var a = 0;
function fn1(){
a++;
console.log(a);
}
return fn1;
}
var f = fn();
f();
f();
f = null;//釋放閉包
6. 面向?qū)ο?/h1>
面向?qū)ο笕筇匦裕悍庋b、繼承、多態(tài)
-
原型繼承-方法繼承
- 讓父類的實(shí)例作為子類的原型,將子類的原型構(gòu)造器補(bǔ)充完整 (為了讓子類繼承方法)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>面向?qū)ο?原型繼承-方法繼承</title>
</head>
<body>
<script>
function Dog(){
}
Dog.prototype.eat = function(){
console.log('翔');
}
function Teddy(){
}
Teddy.prototype = new Dog();
Teddy.prototype.constructor = Teddy;
function ChaiQuan(){
}
ChaiQuan.prototype = new Dog();
ChaiQuan.prototype.constructor = ChaiQuan;
var t = new Teddy();
t.eat();
var c = new ChaiQuan();
c.eat();
</script>
</body>
</html>

-
構(gòu)造器(函數(shù))繼承-屬性繼承
- 在子類當(dāng)中去調(diào)用父類的構(gòu)造函數(shù)(為了讓子類繼承屬性)
-
組合繼承
- 原型繼承方法,借用構(gòu)造函數(shù)繼承屬性一起使用
- 方法重寫和方法重載(多態(tài)的表現(xiàn)形式)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//父類
function Dog(name,age){
this.name = name;
this.age = age;
}
//子類
function Teddy(name,age){
// this.name = name;
// this.age = age;
//借助父類的構(gòu)造函數(shù)實(shí)現(xiàn)屬性的繼承
Dog.call(this,name,age);
}
Dog.prototype.run = function(){
console.log('跑的很快~');
}
//為了讓子類去繼承父類原型當(dāng)中的方法
//我們需要用到原型繼承,原型繼承主要就是為了讓子類繼承方法使用的
//讓子類的原型變成父類的一個(gè)實(shí)例
//手動(dòng)給原型對(duì)象添加一個(gè)構(gòu)造器,因?yàn)樵蛯?duì)象里面都是有構(gòu)造器的,指向和自己匹配的構(gòu)造函數(shù)
Teddy.prototype = new Dog();
Teddy.prototype.constructor = Teddy;
//方法重寫和方法重載 是多態(tài)的兩個(gè)表現(xiàn)形式
//方法重寫;和父類同名方法功能不同,被稱作方法重寫
Teddy.prototype.run = function(flag){
//方法重載
if(typeof flag === 'number'){
console.log('跑的很慢~');
}else{
console.log('跑的很快~');
}
}
var d1 = new Dog('旺財(cái)',3);
d1.run();
var t1 = new Teddy('小黑',2);
t1.run(10);
console.log(t1);
</script>
</body>
</html>
7. web Workers
H5規(guī)范提供了js分線程的實(shí)現(xiàn), 取名為: Web Workers
-
相關(guān)API
Worker: 構(gòu)造函數(shù), 加載分線程執(zhí)行的js文件
Worker.prototype.onmessage: 用于接收另一個(gè)線程的回調(diào)函數(shù)
Worker.prototype.postMessage: 向另一個(gè)線程發(fā)送消息
每個(gè)線程可以向不同線程發(fā)送消息 也可以接收不同線程傳來的消息
-
主線程操作
發(fā)送消息: worker.postMessage(消息可以是任何數(shù)據(jù))
-
接受消息: worker.onmessage = function(e){
console.log(e.data)//接收到的消息或者數(shù)據(jù)在事件對(duì)象的data屬性當(dāng)中 }
-
子線程操作
發(fā)送消息: worker.postMessage(消息可以是任何數(shù)據(jù))
-
接受消息: worker.onmessage = function(e){
console.log(e.data)//接收到的消息或者數(shù)據(jù)在事件對(duì)象的data屬性當(dāng)中 }
-
不足
- worker內(nèi)代碼不能操作DOM
- 不能跨域加載JS
- 不是每個(gè)瀏覽器都支持這個(gè)新特性
-
計(jì)算得到fibonacci數(shù)列中第n個(gè)數(shù)的值
- 在主線程計(jì)算: 當(dāng)位數(shù)較大時(shí), 會(huì)阻塞主線程, 導(dǎo)致界面卡死
function fib(n){
if(n <= 2){
return 1;
}
return fib(n- 1) + fib(n - 2);
}
- js代碼-myThread.js :
function fib(n){
if(n <= 2){
return 1;
}
return fib(n- 1) + fib(n - 2);
}
self.onmessage = function(e){
e = e || window.event;
// console.log(e.data);//就 可以拿到主線程給我 發(fā)過來的消息內(nèi)容
var result = fib(e.data);
self.postMessage(result);//分線程接受到主線程的消息,然后開始計(jì)算,把計(jì)算后的記過發(fā)消息再給主線程
}
- html代碼 :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//第一步:實(shí)例化一個(gè)對(duì)象,初始化主線程和分線程關(guān)聯(lián)對(duì)象
var worker = new Worker('./myThread.js');
worker.postMessage(100);//主線程發(fā)送消息給分線程,消息內(nèi)容可以是任意類型
worker.onmessage = function(e){
e = e || window.event;
//等待接受分線程計(jì)算完的結(jié)果
console.log(e.data);
}
console.log('大哥 js Ending~');
</script>
</body>
</html>
面試題
// 當(dāng)發(fā)生連等的時(shí)候 那么屬性的優(yōu)先級(jí)更高
var a = { n: 1 };
var b = a;
a.x = {n:2}
a = {n:2}
a.x = a = { n: 2 };
console.log(a.x); // 報(bào)錯(cuò)
console.log(b.x); // {n:2}
var b1 = {
b2:[2,'atguigu',console.log],
b3:function () {
alert('hello')
}
}
console.log(b1, b1.b2, b1.b3); // {b2: Array(3), b3: ?} b2: (3) [2, 'atguigu', ?] b3: ? ({alert('hello')})
console.log(b1 instanceof Object, typeof b1); // true 'object'
console.log(b1.b2 instanceof Array, typeof b1.b2); // true 'object'
console.log(b1.b3 instanceof Function, typeof b1.b3); // true 'function'
console.log(typeof b1.b2[2]); // 'function'
console.log(typeof b1.b2[2]('atguigu')); // 'atguigu' undefined
b1.b2[2]('atguigu'); // 'atguigu'
var a = {};
var obj1 = {
m: 2,
};
var obj2 = {
n: 2,
};
var obj3 = function () {};
a[obj1] = 4;
a[obj2] = 5;
a.name = 'kobe';
a[obj3] = 6;
console.log(a[obj1]); // 5
console.log(a); // {[object Object]: 5, name: 'kobe', function () {}: 6}
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function () {
return function () {
return this.name;
};
},
};
console.log(object.getNameFunc()); // f () { return this.name }
console.log(object.getNameFunc()()); // The Window
var name2 = 'The Window';
var object2 = {
name2: 'My Object',
getNameFunc: function () {
var that = this;
return function () {
return that.name2;
};
},
};
console.log(object2.getNameFunc()); // f () {return that.name2;}
console.log(object2.getNameFunc()()); // My Object