国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

JavaScript函數(shù)的一些注意點(diǎn)

2019-11-08 01:18:55
字體:
供稿:網(wǎng)友

參考:廖雪峰老師的javascript教程

變量作用域

變量提升

Javascript的函數(shù)定義有個(gè)特點(diǎn),它會(huì)先掃描整個(gè)函數(shù)體的語句,把所有申明的變量“提升”到函數(shù)頂部

'use strict';function foo() { var x = 'Hello, ' + y; alert(x); var y = 'Bob';}foo();

雖然是strict模式,但語句var x = ‘Hello, ’ + y;并不報(bào)錯(cuò),原因是變量y在稍后申明了。但是alert顯示Hello, undefined,說明變量y的值為undefined。這正是因?yàn)镴avaScript引擎自動(dòng)提升了變量y的聲明,但不會(huì)提升變量y的賦值

全局作用域

不在任何函數(shù)內(nèi)定義的變量就具有全局作用域。實(shí)際上,JavaScript默認(rèn)有一個(gè)全局對象window,全局作用域的變量實(shí)際上被綁定到window的一個(gè)屬性

'use strict';var course = 'Learn JavaScript';alert(course); // 'Learn JavaScript'alert(window.course); // 'Learn JavaScript'

因此,直接訪問全局變量course和訪問window.course是完全一樣的。

由于函數(shù)定義有兩種方式,以變量方式var foo = function () {}定義的函數(shù)實(shí)際上也是一個(gè)全局變量,因此,頂層函數(shù)的定義也被視為一個(gè)全局變量,并綁定到window對象

我們每次直接調(diào)用的alert()函數(shù)其實(shí)也是window的一個(gè)變量

JavaScript實(shí)際上只有一個(gè)全局作用域。任何變量(函數(shù)也視為變量),如果沒有在當(dāng)前函數(shù)作用域中找到,就會(huì)繼續(xù)往上查找,最后如果在全局作用域中也沒有找到,則報(bào)ReferenceError錯(cuò)誤

名字空間

全局變量會(huì)綁定到window上,不同的JavaScript文件如果使用了相同的全局變量,或者定義了相同名字的頂層函數(shù),都會(huì)造成命名沖突,并且很難被發(fā)現(xiàn)。

減少?zèng)_突的一個(gè)方法是把自己的所有變量和函數(shù)全部綁定到一個(gè)全局變量中。例如:

// 唯一的全局變量MYAPP:var MYAPP = {};// 其他變量:MYAPP.name = 'myapp';MYAPP.version = 1.0;// 其他函數(shù):MYAPP.foo = function () { return 'foo';};

把自己的代碼全部放入唯一的名字空間MYAPP中,會(huì)大大減少全局變量沖突的可能。

許多著名的JavaScript庫都是這么干的:jQuery,YUI,underscore等等。

局部作用域

由于JavaScript的變量作用域?qū)嶋H上是函數(shù)內(nèi)部,我們在for循環(huán)等語句塊中是無法定義具有局部作用域的變量的:

'use strict';function foo() { for (var i=0; i<100; i++) { // } i += 100; // 仍然可以引用變量i}

為了解決塊級作用域,ES6引入了新的關(guān)鍵字let,用let替代var可以申明一個(gè)塊級作用域的變量:

'use strict';function foo() { var sum = 0; for (let i=0; i<100; i++) { sum += i; } i += 1; // SyntaxError}

常量

由于var和let申明的是變量,如果要申明一個(gè)常量,在ES6之前是不行的,我們通常用全部大寫的變量來表示“這是一個(gè)常量,不要修改它的值”

var PI = 3.14;

ES6標(biāo)準(zhǔn)引入了新的關(guān)鍵字const來定義常量,const與let都具有塊級作用域

'use strict';const PI = 3.14;PI = 3; // 某些瀏覽器不報(bào)錯(cuò),但是無效果!PI; // 3.14

方法 在一個(gè)對象中綁定函數(shù),稱為這個(gè)對象的方法

在JavaScript中,對象的定義是這樣的:

var xiaoming = { name: '小明', birth: 1990};

但是,如果我們給xiaoming綁定一個(gè)函數(shù),就可以做更多的事情。比如,寫個(gè)age()方法,返回xiaoming的年齡:

var xiaoming = { name: '小明', birth: 1990, age: function () { var y = new Date().getFullYear(); return y - this.birth; }};xiaoming.age; // function xiaoming.age()xiaoming.age(); // 今年調(diào)用是25,明年調(diào)用就變成26了

在一個(gè)方法內(nèi)部,this是一個(gè)特殊變量,它始終指向當(dāng)前對象,也就是xiaoming這個(gè)變量。所以,this.birth可以拿到xiaoming的birth屬性。

讓我們拆開寫:

function getAge() { var y = new Date().getFullYear(); return y - this.birth;}var xiaoming = { name: '小明', birth: 1990, age: getAge};xiaoming.age(); // 25, 正常結(jié)果getAge(); // NaN

單獨(dú)調(diào)用函數(shù)getAge()怎么返回了NaN?請注意,我們已經(jīng)進(jìn)入到了JavaScript的一個(gè)大坑里。

JavaScript的函數(shù)內(nèi)部如果調(diào)用了this,那么這個(gè)this到底指向誰?

答案是,視情況而定!

如果以對象的方法形式調(diào)用,比如xiaoming.age(),該函數(shù)的this指向被調(diào)用的對象,也就是xiaoming,這是符合我們預(yù)期的。

如果單獨(dú)調(diào)用函數(shù),比如getAge(),此時(shí),該函數(shù)的this指向全局對象,也就是window

更坑爹的是,如果這么寫:

var fn = xiaoming.age; // 先拿到xiaoming的age函數(shù)fn(); // NaN

也是不行的要保證this指向正確,必須用obj.xxx()的形式調(diào)用!

由于這是一個(gè)巨大的設(shè)計(jì)錯(cuò)誤,要想糾正可沒那么簡單。ECMA決定,在strict模式下讓函數(shù)的this指向undefined,因此,在strict模式下,你會(huì)得到一個(gè)錯(cuò)誤:

'use strict';var xiaoming = { name: '小明', birth: 1990, age: function () { var y = new Date().getFullYear(); return y - this.birth; }};var fn = xiaoming.age;fn(); // Uncaught TypeError: Cannot read 這個(gè)決定只是讓錯(cuò)誤及時(shí)暴露出來,并沒有解決this應(yīng)該指向的正確位置

有些時(shí)候,喜歡重構(gòu)的你把方法重構(gòu)了一下:

'use strict';var xiaoming = { name: '小明', birth: 1990, age: function () { function getAgeFromBirth() { var y = new Date().getFullYear(); return y - this.birth; } return getAgeFromBirth(); }};xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined

結(jié)果又報(bào)錯(cuò)了!原因是this指針只在age方法的函數(shù)內(nèi)指向xiaoming,在函數(shù)內(nèi)部定義的函數(shù),this又指向undefined了!(在非strict模式下,它重新指向全局對象window!

修復(fù)的辦法也不是沒有,我們用一個(gè)that變量首先捕獲this

'use strict';var xiaoming = { name: '小明', birth: 1990, age: function () { var that = this; // 在方法內(nèi)部一開始就捕獲this function getAgeFromBirth() { var y = new Date().getFullYear(); return y - that.birth; // 用that而不是this } return getAgeFromBirth(); }};xiaoming.age(); // 25

用var that = this;,你就可以放心地在方法內(nèi)部定義其他函數(shù),而不是把所有語句都堆到一個(gè)方法中。

apply

雖然在一個(gè)獨(dú)立的函數(shù)調(diào)用中,根據(jù)是否是strict模式,this指向undefined或window,不過,我們還是可以控制this的指向的!

要指定函數(shù)的this指向哪個(gè)對象,可以用函數(shù)本身的apply方法,它接收兩個(gè)參數(shù),第一個(gè)參數(shù)就是需要綁定的this變量,第二個(gè)參數(shù)是Array,表示函數(shù)本身的參數(shù)

(其實(shí)我個(gè)人決定就是告訴js調(diào)用函數(shù)的對象和參數(shù)而已)

用apply修復(fù)getAge()調(diào)用:

function getAge() { var y = new Date().getFullYear(); return y - this.birth;}var xiaoming = { name: '小明', birth: 1990, age: getAge};xiaoming.age(); // 25getAge.apply(xiaoming, []); // 25, this指向xiaoming, 參數(shù)為空

另一個(gè)與apply()類似的方法是call(),唯一區(qū)別是:

apply()把參數(shù)打包成Array再傳入;

call()把參數(shù)按順序傳入。

比如調(diào)用Math.max(3, 5, 4),分別用apply()和call()實(shí)現(xiàn)如下:

Math.max.apply(null, [3, 5, 4]); // 5Math.max.call(null, 3, 5, 4); // 5

對普通函數(shù)調(diào)用,我們通常把this綁定為null。

裝飾器

利用apply(),我們還可以動(dòng)態(tài)改變函數(shù)的行為。

JavaScript的所有對象都是動(dòng)態(tài)的,即使內(nèi)置的函數(shù),我們也可以重新指向新的函數(shù)

現(xiàn)在假定我們想統(tǒng)計(jì)一下代碼一共調(diào)用了多少次parseInt(),可以把所有的調(diào)用都找出來,然后手動(dòng)加上count += 1,不過這樣做太傻了。最佳方案是用我們自己的函數(shù)替換掉默認(rèn)的parseInt():

var count = 0;var oldParseInt = parseInt; // 保存原函數(shù)window.parseInt = function () { count += 1; return oldParseInt.apply(null, arguments); // 調(diào)用原函數(shù)};// 測試:parseInt('10');parseInt('20');parseInt('30');count; // 3
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 蓝田县| 德安县| 长白| 湟源县| 筠连县| 赣榆县| 屯门区| 柘荣县| 彭泽县| 桦南县| 大关县| 毕节市| 绥宁县| 南部县| 沁阳市| 怀柔区| 什邡市| 通榆县| 金山区| 屯昌县| 花莲市| 阳曲县| 曲阜市| 吐鲁番市| 筠连县| 汕头市| 江达县| 上栗县| 汉川市| 萝北县| 中阳县| 九龙城区| 普安县| 保定市| 利辛县| 青神县| 上饶县| 什邡市| 赣榆县| 深水埗区| 班玛县|