JavaScript(面向?qū)ο?原型理解+繼承+作用域鏈和閉包+this使用總結(jié))
一俄认、面向?qū)ο?/h1>
1个少、什么是面向?qū)ο?/p>
? 面向?qū)ο缶褪前褬?gòu)成問題事物分解成多個(gè)對(duì)象,建立對(duì)象不是為了完成某個(gè)步驟眯杏,而是描述某個(gè)事物在這個(gè)解決問題的步驟中的行為夜焦。
1.面向?qū)ο笫且环N思維方法
2.面向?qū)ο笫且环N編程方法
3.面向?qū)ο蟛⒉恢会槍?duì)某一種編程語言
2、面向?qū)ο蠛兔嫦蜻^程的區(qū)別和聯(lián)系
1.面向過程過程側(cè)重整個(gè)問題的解決步驟岂贩,著眼局部或者具體
2.面向?qū)ο髠?cè)重具體的功能茫经,讓某個(gè)對(duì)象具有這樣的功能。更加側(cè)重于整體萎津。
各自的優(yōu)缺點(diǎn):
?
面向過程的優(yōu)點(diǎn):
流程化使得編程任務(wù)明確卸伞,在開發(fā)之前基本考慮實(shí)現(xiàn)的方法和最終結(jié)果;
效率高锉屈,面向過程強(qiáng)調(diào)代碼的短小精悍荤傲,善于結(jié)合數(shù)據(jù)結(jié)構(gòu)來開發(fā)高效率程序;
流程明確颈渊,具體步驟清楚遂黍,便于節(jié)點(diǎn)分析终佛。
面向過程的缺點(diǎn):
需要深入的思考,耗費(fèi)精力妓湘,代碼重用性低查蓉,擴(kuò)展能力差,維護(hù)起來難度比較高榜贴,
對(duì)復(fù)雜業(yè)務(wù)來說,面向過程的模塊難度較高妹田,耦合度也比較高唬党。
?
面向?qū)ο蟮膬?yōu)點(diǎn):
結(jié)構(gòu)清晰,程序便于模塊化鬼佣,結(jié)構(gòu)化驶拱,抽象化,更加符合人類的思維方式晶衷;
封裝性蓝纲,將事務(wù)高度抽象,從而便于流程中的行為分析晌纫,也便于操作和自仕懊浴;
容易擴(kuò)展锹漱,代碼重用率高箭养,可繼承,可覆蓋哥牍;
實(shí)現(xiàn)簡單毕泌,可有效地減少程序的維護(hù)工作量,軟件開發(fā)效率高嗅辣。
?
面向?qū)ο蟮娜秉c(diǎn)是:
效率低撼泛,面向?qū)ο笤诿嫦蜻^程的基礎(chǔ)上高度抽象,從而和代碼底層的直接交互非常少機(jī)會(huì)澡谭,從而不適合底層開發(fā)和游戲甚至多媒體開發(fā)愿题;
復(fù)雜性,對(duì)于事務(wù)開發(fā)而言译暂,事務(wù)本身是面向過程的抠忘,過度的封裝導(dǎo)致事務(wù)本身的復(fù)雜性提高。
3外永、面向?qū)ο蟮膶?shí)現(xiàn)方式
? 面向?qū)ο蟮膶?shí)現(xiàn)主流有兩種方式:基于類的面向?qū)ο蠛突谠偷拿嫦驅(qū)ο蟆?/p>
? 面向?qū)ο笕筇卣鳎?/p>
● 封裝
也就是把客觀事物封裝成抽象的類或具體的對(duì)象崎脉,并且類或?qū)ο罂梢园炎约旱臄?shù)據(jù)和方法只讓可信的類或者對(duì)象操作,對(duì)不可信的進(jìn)行信息隱藏伯顶。
● 繼承
可以讓某個(gè)類型的對(duì)象獲得另一個(gè)類型的對(duì)象的屬性的方法
● 多肽
不同實(shí)例的相同方法在不同情形有不同表現(xiàn)形式囚灼。多態(tài)機(jī)制使具有不同內(nèi)部結(jié)構(gòu)的對(duì)象可以共享相同的外部接口骆膝。
3.1 基于類的面向?qū)ο?/h1>
? 典型的語言:Java、C#
對(duì)象(object)依靠 類(class)來產(chǎn)生
3.2 基于原型的面向?qū)ο?/h1>
? 典型的語言:JavaScript
對(duì)象(object)則是依靠 構(gòu)造器(constructor)利用 原型(prototype)構(gòu)造出來的
4灶体、多種創(chuàng)建對(duì)象的方式
4.1 使用new Object()創(chuàng)建
4.2 工廠模式創(chuàng)建
? 工廠模式是軟件工程領(lǐng)域一種廣為人知的設(shè)計(jì)模式阅签,這種模式抽象了創(chuàng)建具體對(duì)象的過程,考慮到在 ECMAScript 中無法創(chuàng)建類蝎抽,開發(fā)人員就發(fā)明了一種函數(shù)政钟,用函數(shù)來封裝以特定接口創(chuàng)建對(duì)象的細(xì)節(jié)。
4.3 構(gòu)造函數(shù)模式創(chuàng)建
? 為了解決對(duì)象類型識(shí)別問題樟结,又提出了構(gòu)造函數(shù)模式养交。這種模式,其實(shí)在我們創(chuàng)建一些原生對(duì)象的時(shí)候瓢宦,比如Array碎连、Object都是調(diào)用的他們的構(gòu)造函數(shù)。
<script type="text/javascript">
function Person (name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.eat = function () {
alert(this.name + " Eat food");
}
}
var p1 = new Person("Jack", 20, "man");
p1.eat(); //Jack Eat food
var p1 = new Person("Mark", 30, "man");
p1.eat(); //Mark Eat food
alert(p1 instanceof Person);
</script>
5驮履、構(gòu)造函數(shù)與普通函數(shù)的關(guān)系
1.
他們都是函數(shù)鱼辙。構(gòu)造函數(shù)也是函數(shù),也可以像普通的函數(shù)一樣進(jìn)行調(diào)用玫镐。 做普通函數(shù)調(diào)用的時(shí)候倒戏,因?yàn)闆]有創(chuàng)建新的對(duì)象,所以this其實(shí)指向了window對(duì)象摘悴。
function Person(){
this.name = "Jack"; // 把name屬性添加到了window對(duì)象上面
alert(this === window); //如果不作為構(gòu)造方法調(diào)用峭梳,則 是true
}
Person(); // 把構(gòu)造函數(shù)當(dāng)做普通方法調(diào)用。這個(gè)時(shí)候內(nèi)部的this指向了weindow
alert(window.name); //Jack
function Human(){
this.name = "Mark";
alert(this instanceof window); // false
alert(this instanceof Human); //true
}
var h = new Human(); //當(dāng)做構(gòu)造函數(shù)來調(diào)用蹂喻,創(chuàng)建一個(gè)對(duì)象
alert(h.name);
2.
構(gòu)造函數(shù)和普通函數(shù)僅僅也僅僅是調(diào)用方式的不同葱椭。也就是說,隨便一個(gè)函數(shù)你如果用new 的方式去使用口四,那么他就是一個(gè)構(gòu)造函數(shù)孵运。
3.
為了區(qū)別,如果一個(gè)函數(shù)想作為構(gòu)造函數(shù)蔓彩,作為國際慣例治笨,最好把這個(gè)構(gòu)造函數(shù)的首字母大寫。
4赤嚼、閉包
<script type="text/javascript">
function createSumFunction(num1, num2){
return function () {
return num1 + num2;
};
}
var sumFun = createSumFunction(3, 4);
var sum = sumFun();
alert(sum);//7
</script>
在上面的代碼中旷赖,createSumFunction函數(shù)返回了一個(gè)匿名函數(shù),而這個(gè)匿名函數(shù)使用了createSumFunction函數(shù)中的局部變量(參數(shù))更卒,即使createSumFunction這個(gè)函數(shù)執(zhí)行結(jié)束了等孵,由于作用域鏈的存在,他的局部變量在匿名函數(shù)中仍然可以使用蹂空,這個(gè)匿名函數(shù)就是閉包俯萌。
? 閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)果录。
? 閉包是一種特殊的對(duì)象。它由兩部分構(gòu)成: 函數(shù)咐熙,以及創(chuàng)建該函數(shù)的環(huán)境 弱恒。環(huán)境由閉包創(chuàng)建時(shí)在作用域中的任何局部變量組成。在我們的例子中棋恼,sumFun 是一個(gè)閉包返弹,由 匿名 函數(shù)和閉包創(chuàng)建時(shí)存在的num1和num2 兩個(gè)局部變量組成。
5蘸泻、閉包的應(yīng)用
5.1 返回外部函數(shù)的局部變量
<script type="text/javascript">
function outer () {
var num = 5;
//定義一個(gè)內(nèi)部函數(shù)
function inner () {
//內(nèi)部函數(shù)的返回值是外部函數(shù)的一個(gè)局部變量
return num;
}
//把局部變量的值++
num++;
// 返回內(nèi)部函數(shù)
return inner;
}
var num = outer()(); // 6
alert(num);
</script>
說明:
1.
這例子中琉苇,雖然函數(shù)的聲明在num++之前,但是函數(shù)返回的時(shí)候num已經(jīng)++過了悦施,所以只是num自增之后的值。
2.
結(jié)論:閉包中使用的局部變量的值去团,一定是局部變量的最后的值抡诞。
5.2 使用函數(shù)自執(zhí)行和閉包封裝對(duì)象
封裝一個(gè)能夠增刪改查的對(duì)象
<script type="text/javascript">
var person = (function () {
//聲明一個(gè)對(duì)象,增刪改查均是針對(duì)這個(gè)對(duì)象
var personInfo = {
name : "李四",
age : 20
};
//返回一個(gè)對(duì)象土陪,這個(gè)對(duì)象中封裝了一些對(duì)personInfor操作的方法
return {
//根據(jù)給定的屬性獲取這個(gè)屬性的值
getInfo : function (property) {
return personInfo[property];
},
//修改一個(gè)屬性值
modifyInfo : function (property, newValue) {
personInfo[property] = newValue;
},
//添加新的屬性
addInfo : function (property, value) {
personInfo[property] = value;
},
//刪除指定的屬性
delInfo : function (property) {
delete personInfo[property];
}
}
})();
alert(person.getInfo("name"));
person.addInfo("sex", "男");
alert(person.getInfo("sex"));
</script>
五昼汗、this使用總結(jié)
1、this使用總結(jié)
<script>
/*
* 默認(rèn)綁定:
* 當(dāng)直接調(diào)用一個(gè)函數(shù)的時(shí)候鬼雀,就是默認(rèn)綁定
* 1顷窒、非嚴(yán)格模式下,默認(rèn)綁定到window上
*
* 隱式綁定:
* 當(dāng)使用 對(duì)象.方法() 這種方式調(diào)用源哩,稱之為隱式綁定
* this綁定到前面的那個(gè)對(duì)象上
*
* new 綁定:
* 使用new來調(diào)用構(gòu)造函數(shù)的方式
* this是綁定在新創(chuàng)建的那個(gè)對(duì)象上
*
* 顯示綁定:
* call鞋吉,apply:
* 都是一錘子買賣,僅僅這一次調(diào)用的時(shí)候使用了顯示綁定励烦,對(duì)原函數(shù)沒有如何的影響
*
* call和apply的區(qū)別:就是參數(shù)的傳遞方式
* call:一個(gè)一個(gè)的傳遞
* apply:把要傳遞的參數(shù)封裝到一個(gè)數(shù)組中去傳遞
*
* bind:固定綁定 es6新增
* 調(diào)用函數(shù)對(duì)象的bind方法谓着,返回一個(gè)固定this綁定的新的函數(shù)
* 對(duì)原來的函數(shù)沒有影響
*
*
*
* 優(yōu)先級(jí):bind > call,apply > new > 隱式
*/
?
?
//1、默認(rèn)綁定
function foo() {
console.log(this);//this指 obj 誰調(diào)用指向誰
}
?
?
//2坛掠、隱式綁定
var name = "Mark";
var obj = {
name : "Jack",
foo : foo,
foo1 : function () {
console.log(this.name);//this指 window
}
}
obj.foo();//{name: "Jack", foo: function, foo1: function}
var foo1 = obj.foo1;
foo1();//Mark
?
?
//3赊锚、new 綁定
function foo2() {
this.name = "Lucy";
console.log(this);//this 指向foo2 foo2 {name: "Lucy"}
}
var obj2 = new foo2();
console.log(obj2);//this 指向foo2 foo2 {name: "Lucy"}
?
var foo3 = obj.foo1;
foo3();//Mark
?
var obj3 = new foo;//foo {}
console.log(obj3);//foo {}
?
?
//4、顯示綁定
?
//call apply
function foo4(a,b) {
console.log(this.name,a,b);
}
foo4.call({name:"Jack"},10,20)//Jack 10 20
foo4.apply({name:"Mark"},[20,10])//Mark 20 10
?
//apply求max
var arr = [23,65,2,45,3,57,4567];
console.log(Math.max.apply(Math,arr)); //max = 4567
?
//定義Math 求和的方法
Math.sun = function () {
return Array.prototype.reduce.call(arguments,function (sun,ele) {
return sun + ele;
},0)
}
console.log(Math.sun.apply(Math,arr));//sum = 4762
?
//bind
var obj4 = {
name : "Jack"
}
function foo5() {
console.log(this.name);
}
var f = foo5.bind(obj4);//這種綁定方式優(yōu)先級(jí)最高
f();//Jack
?
var obj5 = {
name : "Mark",
foo6 : f
}
obj5.foo6()//Jack
</script>
2屉栓、綁定的丟失問題
<script>
/*
* 回調(diào)函數(shù)的this綁定丟失問題:this會(huì)綁定到window
*
* 定時(shí)器
*
*
* 顯示綁定丟失問題
* 顯示綁定傳入null舷蒲、undefined時(shí),this就成了默認(rèn)綁定
*
*/
?
//定時(shí)器綁定丟失
var name = "Jack";
var obj = {
name : "Mark",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向window
},1000)
}
}
obj.show();//Jack++
?
//解決方法一
var obj1 = {
name : "Mark",
show : function () {
var self = this;
setInterval(function () {
console.log(self.name);// 此時(shí)this指向obj1
},1000)
}
}
obj1.show();//Mark++
?
//解決方法二
var obj2 = {
name : "Joe",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向obj2
}.bind(this),1000)
}
}
obj2.show();//Mark++
?
//顯示綁定丟失
function foo() {
console.log(this.name);
}
var f = foo.bind(undefined);// 此時(shí)this指向window
f();//Jack
</script>
五友多、this使用總結(jié)
1牲平、this使用總結(jié)
<script>
/*
* 默認(rèn)綁定:
* 當(dāng)直接調(diào)用一個(gè)函數(shù)的時(shí)候,就是默認(rèn)綁定
* 1夷陋、非嚴(yán)格模式下欠拾,默認(rèn)綁定到window上
*
* 隱式綁定:
* 當(dāng)使用 對(duì)象.方法() 這種方式調(diào)用胰锌,稱之為隱式綁定
* this綁定到前面的那個(gè)對(duì)象上
*
* new 綁定:
* 使用new來調(diào)用構(gòu)造函數(shù)的方式
* this是綁定在新創(chuàng)建的那個(gè)對(duì)象上
*
* 顯示綁定:
* call,apply:
* 都是一錘子買賣藐窄,僅僅這一次調(diào)用的時(shí)候使用了顯示綁定资昧,對(duì)原函數(shù)沒有如何的影響
*
* call和apply的區(qū)別:就是參數(shù)的傳遞方式
* call:一個(gè)一個(gè)的傳遞
* apply:把要傳遞的參數(shù)封裝到一個(gè)數(shù)組中去傳遞
*
* bind:固定綁定 es6新增
* 調(diào)用函數(shù)對(duì)象的bind方法,返回一個(gè)固定this綁定的新的函數(shù)
* 對(duì)原來的函數(shù)沒有影響
*
*
*
* 優(yōu)先級(jí):bind > call,apply > new > 隱式
*/
?
?
//1荆忍、默認(rèn)綁定
function foo() {
console.log(this);//this指 obj 誰調(diào)用指向誰
}
?
?
//2格带、隱式綁定
var name = "Mark";
var obj = {
name : "Jack",
foo : foo,
foo1 : function () {
console.log(this.name);//this指 window
}
}
obj.foo();//{name: "Jack", foo: function, foo1: function}
var foo1 = obj.foo1;
foo1();//Mark
?
?
//3、new 綁定
function foo2() {
this.name = "Lucy";
console.log(this);//this 指向foo2 foo2 {name: "Lucy"}
}
var obj2 = new foo2();
console.log(obj2);//this 指向foo2 foo2 {name: "Lucy"}
?
var foo3 = obj.foo1;
foo3();//Mark
?
var obj3 = new foo;//foo {}
console.log(obj3);//foo {}
?
?
//4刹枉、顯示綁定
?
//call apply
function foo4(a,b) {
console.log(this.name,a,b);
}
foo4.call({name:"Jack"},10,20)//Jack 10 20
foo4.apply({name:"Mark"},[20,10])//Mark 20 10
?
//apply求max
var arr = [23,65,2,45,3,57,4567];
console.log(Math.max.apply(Math,arr)); //max = 4567
?
//定義Math 求和的方法
Math.sun = function () {
return Array.prototype.reduce.call(arguments,function (sun,ele) {
return sun + ele;
},0)
}
console.log(Math.sun.apply(Math,arr));//sum = 4762
?
//bind
var obj4 = {
name : "Jack"
}
function foo5() {
console.log(this.name);
}
var f = foo5.bind(obj4);//這種綁定方式優(yōu)先級(jí)最高
f();//Jack
?
var obj5 = {
name : "Mark",
foo6 : f
}
obj5.foo6()//Jack
</script>
2叽唱、綁定的丟失問題
<script>
/*
* 回調(diào)函數(shù)的this綁定丟失問題:this會(huì)綁定到window
*
* 定時(shí)器
*
*
* 顯示綁定丟失問題
* 顯示綁定傳入null、undefined時(shí)微宝,this就成了默認(rèn)綁定
*
*/
?
//定時(shí)器綁定丟失
var name = "Jack";
var obj = {
name : "Mark",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向window
},1000)
}
}
obj.show();//Jack++
?
//解決方法一
var obj1 = {
name : "Mark",
show : function () {
var self = this;
setInterval(function () {
console.log(self.name);// 此時(shí)this指向obj1
},1000)
}
}
obj1.show();//Mark++
?
//解決方法二
var obj2 = {
name : "Joe",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向obj2
}.bind(this),1000)
}
}
obj2.show();//Mark++
?
//顯示綁定丟失
function foo() {
console.log(this.name);
}
var f = foo.bind(undefined);// 此時(shí)this指向window
f();//Jack
</script>
五棺亭、this使用總結(jié)
1、this使用總結(jié)
<script>
/*
* 默認(rèn)綁定:
* 當(dāng)直接調(diào)用一個(gè)函數(shù)的時(shí)候蟋软,就是默認(rèn)綁定
* 1镶摘、非嚴(yán)格模式下,默認(rèn)綁定到window上
*
* 隱式綁定:
* 當(dāng)使用 對(duì)象.方法() 這種方式調(diào)用岳守,稱之為隱式綁定
* this綁定到前面的那個(gè)對(duì)象上
*
* new 綁定:
* 使用new來調(diào)用構(gòu)造函數(shù)的方式
* this是綁定在新創(chuàng)建的那個(gè)對(duì)象上
*
* 顯示綁定:
* call凄敢,apply:
* 都是一錘子買賣,僅僅這一次調(diào)用的時(shí)候使用了顯示綁定湿痢,對(duì)原函數(shù)沒有如何的影響
*
* call和apply的區(qū)別:就是參數(shù)的傳遞方式
* call:一個(gè)一個(gè)的傳遞
* apply:把要傳遞的參數(shù)封裝到一個(gè)數(shù)組中去傳遞
*
* bind:固定綁定 es6新增
* 調(diào)用函數(shù)對(duì)象的bind方法涝缝,返回一個(gè)固定this綁定的新的函數(shù)
* 對(duì)原來的函數(shù)沒有影響
*
*
*
* 優(yōu)先級(jí):bind > call,apply > new > 隱式
*/
?
?
//1、默認(rèn)綁定
function foo() {
console.log(this);//this指 obj 誰調(diào)用指向誰
}
?
?
//2譬重、隱式綁定
var name = "Mark";
var obj = {
name : "Jack",
foo : foo,
foo1 : function () {
console.log(this.name);//this指 window
}
}
obj.foo();//{name: "Jack", foo: function, foo1: function}
var foo1 = obj.foo1;
foo1();//Mark
?
?
//3拒逮、new 綁定
function foo2() {
this.name = "Lucy";
console.log(this);//this 指向foo2 foo2 {name: "Lucy"}
}
var obj2 = new foo2();
console.log(obj2);//this 指向foo2 foo2 {name: "Lucy"}
?
var foo3 = obj.foo1;
foo3();//Mark
?
var obj3 = new foo;//foo {}
console.log(obj3);//foo {}
?
?
//4、顯示綁定
?
//call apply
function foo4(a,b) {
console.log(this.name,a,b);
}
foo4.call({name:"Jack"},10,20)//Jack 10 20
foo4.apply({name:"Mark"},[20,10])//Mark 20 10
?
//apply求max
var arr = [23,65,2,45,3,57,4567];
console.log(Math.max.apply(Math,arr)); //max = 4567
?
//定義Math 求和的方法
Math.sun = function () {
return Array.prototype.reduce.call(arguments,function (sun,ele) {
return sun + ele;
},0)
}
console.log(Math.sun.apply(Math,arr));//sum = 4762
?
//bind
var obj4 = {
name : "Jack"
}
function foo5() {
console.log(this.name);
}
var f = foo5.bind(obj4);//這種綁定方式優(yōu)先級(jí)最高
f();//Jack
?
var obj5 = {
name : "Mark",
foo6 : f
}
obj5.foo6()//Jack
</script>
2害幅、綁定的丟失問題
<script>
/*
* 回調(diào)函數(shù)的this綁定丟失問題:this會(huì)綁定到window
*
* 定時(shí)器
*
*
* 顯示綁定丟失問題
* 顯示綁定傳入null消恍、undefined時(shí),this就成了默認(rèn)綁定
*
*/
?
//定時(shí)器綁定丟失
var name = "Jack";
var obj = {
name : "Mark",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向window
},1000)
}
}
obj.show();//Jack++
?
//解決方法一
var obj1 = {
name : "Mark",
show : function () {
var self = this;
setInterval(function () {
console.log(self.name);// 此時(shí)this指向obj1
},1000)
}
}
obj1.show();//Mark++
?
//解決方法二
var obj2 = {
name : "Joe",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向obj2
}.bind(this),1000)
}
}
obj2.show();//Mark++
?
//顯示綁定丟失
function foo() {
console.log(this.name);
}
var f = foo.bind(undefined);// 此時(shí)this指向window
f();//Jack
</script>
五以现、this使用總結(jié)
1狠怨、this使用總結(jié)
<script>
/*
* 默認(rèn)綁定:
* 當(dāng)直接調(diào)用一個(gè)函數(shù)的時(shí)候,就是默認(rèn)綁定
* 1邑遏、非嚴(yán)格模式下佣赖,默認(rèn)綁定到window上
*
* 隱式綁定:
* 當(dāng)使用 對(duì)象.方法() 這種方式調(diào)用,稱之為隱式綁定
* this綁定到前面的那個(gè)對(duì)象上
*
* new 綁定:
* 使用new來調(diào)用構(gòu)造函數(shù)的方式
* this是綁定在新創(chuàng)建的那個(gè)對(duì)象上
*
* 顯示綁定:
* call记盒,apply:
* 都是一錘子買賣憎蛤,僅僅這一次調(diào)用的時(shí)候使用了顯示綁定,對(duì)原函數(shù)沒有如何的影響
*
* call和apply的區(qū)別:就是參數(shù)的傳遞方式
* call:一個(gè)一個(gè)的傳遞
* apply:把要傳遞的參數(shù)封裝到一個(gè)數(shù)組中去傳遞
*
* bind:固定綁定 es6新增
* 調(diào)用函數(shù)對(duì)象的bind方法,返回一個(gè)固定this綁定的新的函數(shù)
* 對(duì)原來的函數(shù)沒有影響
*
*
*
* 優(yōu)先級(jí):bind > call,apply > new > 隱式
*/
?
?
# //1俩檬、默認(rèn)綁定
function foo() {
console.log(this);//this指 obj 誰調(diào)用指向誰
}
?
?
#//2萎胰、隱式綁定
var name = "Mark";
var obj = {
name : "Jack",
foo : foo,
foo1 : function () {
console.log(this.name);//this指 window
}
}
obj.foo();//{name: "Jack", foo: function, foo1: function}
var foo1 = obj.foo1;
foo1();//Mark
?
?
# //3、new 綁定
function foo2() {
this.name = "Lucy";
console.log(this);//this 指向foo2 foo2 {name: "Lucy"}
}
var obj2 = new foo2();
console.log(obj2);//this 指向foo2 foo2 {name: "Lucy"}
?
var foo3 = obj.foo1;
foo3();//Mark
?
var obj3 = new foo;//foo {}
console.log(obj3);//foo {}
?
?
# //4棚辽、顯示綁定
?
//call apply
function foo4(a,b) {
console.log(this.name,a,b);
}
foo4.call({name:"Jack"},10,20)//Jack 10 20
foo4.apply({name:"Mark"},[20,10])//Mark 20 10
?
//apply求max
var arr = [23,65,2,45,3,57,4567];
console.log(Math.max.apply(Math,arr)); //max = 4567
?
//定義Math 求和的方法
Math.sun = function () {
return Array.prototype.reduce.call(arguments,function (sun,ele) {
return sun + ele;
},0)
}
console.log(Math.sun.apply(Math,arr));//sum = 4762
?
//bind
var obj4 = {
name : "Jack"
}
function foo5() {
console.log(this.name);
}
var f = foo5.bind(obj4);//這種綁定方式優(yōu)先級(jí)最高
f();//Jack
?
var obj5 = {
name : "Mark",
foo6 : f
}
obj5.foo6()//Jack
</script>
2技竟、綁定的丟失問題
<script>
/*
* 回調(diào)函數(shù)的this綁定丟失問題:this會(huì)綁定到window
*
* 定時(shí)器
*
*
* 顯示綁定丟失問題
* 顯示綁定傳入null、undefined時(shí)屈藐,this就成了默認(rèn)綁定
*
*/
?
//定時(shí)器綁定丟失
var name = "Jack";
var obj = {
name : "Mark",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向window
},1000)
}
}
obj.show();//Jack++
?
//解決方法一
var obj1 = {
name : "Mark",
show : function () {
var self = this;
setInterval(function () {
console.log(self.name);// 此時(shí)this指向obj1
},1000)
}
}
obj1.show();//Mark++
?
//解決方法二
var obj2 = {
name : "Joe",
show : function () {
setInterval(function () {
console.log(this.name);// 此時(shí)this指向obj2
}.bind(this),1000)
}
}
obj2.show();//Mark++
?
//顯示綁定丟失
function foo() {
console.log(this.name);
}
var f = foo.bind(undefined);// 此時(shí)this指向window
f();//Jack
</script>
5.3 for循環(huán)典型問題
看下面的代碼
<body>
<input type="button" value="按鈕1" >
<input type="button" value="按鈕2" >
<input type="button" value="按鈕3" >
<script type="text/javascript">
var btns = document.getElementsByTagName("input");
for (var i = 0; i < 3; i++) {
btns[i].onclick = function () {
alert("我是第" + (i + 1) + "個(gè)按鈕");
};
}
</script>
</body>
發(fā)現(xiàn)在點(diǎn)擊三個(gè)按鈕的時(shí)候都是彈出 我是第4個(gè)按鈕榔组。 為什么呢?閉包導(dǎo)致的联逻! 每循環(huán)一次都會(huì)有一個(gè)匿名函數(shù)設(shè)置點(diǎn)擊事件搓扯,閉包總是保持的變量的最后一個(gè)值,所以點(diǎn)擊的時(shí)候包归,總是讀的是 i 的組后一個(gè)值4.
解決方案1:給每個(gè)按鈕添加一個(gè)屬性锨推,來保存 每次 i 的臨時(shí)值
<body>
<input type="button" value="按鈕1" >
<input type="button" value="按鈕2" >
<input type="button" value="按鈕3" >
<script type="text/javascript">
var btns = document.getElementsByTagName("input");
for (var i = 0; i < 3; i++) {
//把i的值綁定到按鈕的一個(gè)屬性上,那么以后i的值就和index的值沒有關(guān)系了公壤。
btns[i].index = i;
btns[i].onclick = function () {
alert("我是第" + (this.index + 1) + "個(gè)按鈕");
};
}
</script>
</body>
解決方案2:使用匿名函數(shù)的自執(zhí)行
<body>
<input type="button" value="按鈕1" >
<input type="button" value="按鈕2" >
<input type="button" value="按鈕3" >
<script type="text/javascript">
var btns = document.getElementsByTagName("input");
for (var i = 0; i < 3; i++) {
//因?yàn)槟涿瘮?shù)已經(jīng)執(zhí)行了爱态,所以會(huì)把 i 的值傳入到num中,注意是i的值境钟,所以num
(function (num) {
btns[i].onclick = function () {
alert("我是第" + (num + 1) + "個(gè)按鈕");
}
})(i);
}
</script>
</body>