函數(shù)的調(diào)用方式和 this 丟失
- 函數(shù)調(diào)用方式
- 普通函數(shù)方式調(diào)用 this - window
- 對(duì)象的方法 this - 對(duì)象
- 構(gòu)造函數(shù)方式 this - 內(nèi)部創(chuàng)建的新對(duì)象
- 函數(shù)上下文(call|apply) this - 第一個(gè)參數(shù)
- this 的指向發(fā)生了改變
函數(shù)的調(diào)用方式發(fā)生了改變
var name = 'window 的屬性';
function demo(){
console.log(this.name);
}
var obj = {
name:"張三",
demo:demo
}
demo();
obj.demo();
var div = document.getElementById('demoId');
console.log(div);
//var div2 = getId('demoId');
//console.log(div2);
//document.getElemenetById 方法內(nèi)部的實(shí)現(xiàn),在該方法內(nèi)部使用到了 this
//這個(gè) this 默認(rèn)指向的是document
//getId 在調(diào)用的時(shí)候使用普通函數(shù)的方式來進(jìn)行調(diào)用, this 指向的是 window
document.getId = document.getElemenetById;
var div3 = document.getId('demoId');
console.log(div3);
//console.log(document.getElemenetById.call(document,''demoId));
//getId('demo');
var getId = (function(){
return function(){
//return document.getElementById.call(document,arguments[0]);
return document.getElemenetById.apply(document,arguments);
}
})();
var div4 = getId('demoId');
console.log(div4);
圖書管理員面向?qū)ο?/h2>
//注意點(diǎn):在原型對(duì)象的方法中訪問該對(duì)象的其他方法,需要使用 this 前綴
function BookListManager(){
this.bookList = null;
}
BookListManager.prototype = {
constructor:BookListManager,
init:function(){
this.bookList = arr || [];
},
getBook:function(name){
for(var i in this.bookList){
if(this.bookList[i].name == name){
return this.bookList[i];
}
}
throw "要查找的對(duì)象不存在!"
},
updateBook:function(name,author){
//先找到這個(gè)對(duì)象
var book = this.getBook(name);
//修改對(duì)象
book.author = author;
},
addBook:function(obj){
this.bookList.push(obj);
},
removeBook:function(){
var book = this.getBook(name);
var index = this.bookList.indexOf(book);
if(index == -1){
throw '要?jiǎng)h除的對(duì)象不存在'
}
//刪除該對(duì)象
this.bookList.splice(index,1);
}
}
var jack = new BookListManager();
var tom = new BookListManager();
jack.init([{name:'古典文學(xué)研究',author:'古典'},{name:'莫言文集',author:'莫言'}]);
jack.addBook({name:'飛鳥集',author:'泰戈?duì)?});
console.log(jack.getBook('飛鳥集'));
jack.updateBook('飛鳥集','老太太');
jack.removeBook('飛鳥集');
console.log(jack.bookList);
嚴(yán)格模式的簡(jiǎn)單說明
- js 中有兩種開發(fā)模式,非嚴(yán)格模式(默認(rèn)) + 嚴(yán)格模式 ('use strict')
- 嚴(yán)格模式會(huì)進(jìn)行更嚴(yán)格的代碼檢查
- 以前可以的特性在嚴(yán)格模式下可能被禁止使用
- 以前可以使用的代碼方式,在嚴(yán)格模式下會(huì)直接報(bào)錯(cuò)
- 開啟嚴(yán)格模式
- 字符串命令 'use strict';
- 位置 當(dāng)前作用域的頂端
- 兼容性問題:
嚴(yán)格模式不存在兼容性問題,如果當(dāng)前的瀏覽器支持嚴(yán)格模式,那么再掃描到"use strict"命令的時(shí)候就會(huì)開啟嚴(yán)格模式檢查,如果不支持嚴(yán)格模式那么就直接忽略
- 使用建議
建議在寫代碼的時(shí)候全部開啟嚴(yán)格模式
嚴(yán)格模式使用注意
- 在嚴(yán)格模式下,所有的變量都必須使用 var 聲明
- 在嚴(yán)格模式下,禁止使用八進(jìn)制
- 在嚴(yán)格模式下,禁止使用 with
- 在嚴(yán)格模式下,不能刪除全局的變量
- 在嚴(yán)格模式下,不能在 if 語句中聲明函數(shù)
- 在嚴(yán)格模式下,函數(shù)的形參不能出現(xiàn)同名的情況
- 在嚴(yán)格模式下,不能使用 callee|caller
- 在嚴(yán)格模式下,不能使用 eval 和 arguments 作為標(biāo)識(shí)符(變量和函數(shù)名稱)
- 在嚴(yán)格模式下,修正了 this 的指向
- 在嚴(yán)格模式下,arguments 的表現(xiàn)不一致
- 在嚴(yán)格模式下,對(duì)象中不能出現(xiàn)同名的屬性
"use strict";
//01 在嚴(yán)格模式下,所有的變量都必須使用var聲明
// 在默認(rèn)情況下,如果不適用var聲明變量,那么該變量默認(rèn)會(huì)成為window的屬性(全局變量)
// var a = 10;
// b = 20;
// console.log(b);
//02 在嚴(yán)格模式下,禁止使用八進(jìn)制
// var num = 022; //數(shù)值以0開頭,以八進(jìn)制的方式來處理
// var num = 0x22;
// console.log(num);
//03 在嚴(yán)格模式下,禁止使用使用with
// var obj = {name:"張三",age:20};
// with (obj)
// {
// name = "李四";
// age = 99
// }
// console.log(obj);
//04 在嚴(yán)格模式下, 不能刪除全局的變量
// 在默認(rèn)情況下,可以刪除全局變量(不能刪除成功),靜默失敗
// var str = "string";
// console.log(delete str);
// console.log(str);
//05 在嚴(yán)格模式下,不能在if語句中聲明函數(shù)
// if (true)
// {
// function demo() {
// console.log("demo");
// }
//
// demo();
// }
//06 在嚴(yán)格模式下,函數(shù)的形參不能出現(xiàn)同名的情況
// function test(a,b,a) {
//// var a = 1;
//// var b = 2;
//// var a = 3;
// console.log(a + b + a); //6 ? 8 ? 4 后面的會(huì)把前面的覆蓋
// }
//
// test(1,2,3);
//07 在嚴(yán)格模式下,不能使用arguments.callee|caller
//caller 指向的函數(shù)的調(diào)用者 注意點(diǎn):window調(diào)用該函數(shù),指向的是null
//arguments.callee 常用在遞歸調(diào)用中,指向的是函數(shù)自己
// function f1() {
// f2();
// }
// function f2() {
// console.log(f2.caller);
// }
// f1();
// f2();
// console.log((function (n) {
// if (n == 1) {
// return 1;
// }
//
// return arguments.callee(n - 1) + n;
//})(11));
//08 在嚴(yán)格模式下, 不能使用eval和arguments作為標(biāo)識(shí)符(變量和函數(shù)的名稱)
// var eval = "測(cè)試字符串";
// console.log(eval);
// var arguments ="....";
// console.log(arguments);
//09 在嚴(yán)格模式下,修正了this的指向
// 默認(rèn)情況下,this指向的是window,嚴(yán)格模式指向的undefined
// function func() {
// console.log(this);
// }
//
// func();
// var o = {};
// func.call(null); //嚴(yán)格模式下,指向的是null
//10 在嚴(yán)格模式下,arguments的表現(xiàn)不一致
//在默認(rèn)情況下,如果函數(shù)內(nèi)部形參被重新設(shè)置,那么arguments也會(huì)跟著改變
//在嚴(yán)格模式情況下,如果函數(shù)內(nèi)部形參被重新設(shè)置,那么arguments不會(huì)被改變,他們是相互獨(dú)立的
//值類型的數(shù)據(jù)作為函數(shù)的參數(shù)
function demo(str) {
console.log(str);
console.log(arguments[0]);
//重新設(shè)置形參的值
str = "hahahaha";
console.log(str);
console.log(arguments[0]);
}
demo("123456");
//引用類型的數(shù)據(jù)作為函數(shù)參數(shù)
function demo(obj) {
console.log(obj);
console.log(arguments[0]);
//重新設(shè)置形參的值
obj = {age:20};
console.log(obj);
console.log(arguments[0]);
}
demo({name:"張三"});
嚴(yán)格模式的書寫格式
//"use strict";
//"use strict" 正確
//'use strict'; 正確
//'use strict' 正確
//use strict; 錯(cuò)誤
//"use Strict"; 錯(cuò)誤
//"use strict"; 錯(cuò)誤
//"use strict "; 錯(cuò)誤
//" use strict"; 錯(cuò)誤
嚴(yán)格模式的作用范圍
- 位置:當(dāng)前作用域的最上面
- js 中的作用域:
- script 標(biāo)簽 全局作用域
- 函數(shù)內(nèi)部 局部作用域
// "use strict"; //位置01 對(duì)整個(gè)作用域中的代碼都有用
function demo01() {
// "use strict"; //位置02 僅僅對(duì)當(dāng)前的函數(shù)有用,函數(shù)后面的代碼不受影響
a = 10;
console.log(a);
}
function demo02() {
// "use strict"; //位置03 僅僅對(duì)當(dāng)前的函數(shù)有用
b = 20;
console.log(b);
}
demo01();
demo02();
作用域說明
- 作用域
概念:變量或者是函數(shù)起作用的范圍
- js 的作用域
- js 本身沒有塊級(jí)作用域(try-catch 除外)
- js 中只有函數(shù)可以創(chuàng)建作用域
- js 本身是此法作用域 (with|eval 除外)
- 詞法作用域:
當(dāng)代碼寫好之后,某個(gè)變量的作用域就已經(jīng)確定了
- 動(dòng)態(tài)作用域:
變量的作用域在代碼運(yùn)行之前是不確定的,只有在代碼執(zhí)行的時(shí)候才能根據(jù)當(dāng)前的上下文來確定
- 詞法作用域的訪問規(guī)則:
- 單向性的(單向鏡),內(nèi)部的作用域可以訪問外層的作用域空間,反過來卻不行
- 在訪問變量的時(shí)候,先在當(dāng)前作用于中查找,如果找不到那么就在上一級(jí)作用域中查找,重復(fù)這個(gè)過程
- 在分析輸出的時(shí)候,需要考慮到變量和函數(shù)聲明的提升
var a = "test-A";
function f1() {
var b = "test-B";
}
function f2() {
var c = "test-C";
}
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log(i,"_____"); //? 10
try
{
//可能出錯(cuò)的代碼
a();
}catch (error){
//如果出錯(cuò)了,那么就執(zhí)行此處的代碼
console.log(error);
}
// console.log(error);
var demo = "測(cè)試的字符串01";
function f1() {
var demo = "demo";
var test = 10;
f2();
}
function f2() {
console.log(demo);
console.log(test);
}
// f2(); //測(cè)試的字符串
f1(); //demo
變量和函數(shù)的提升
- js 代碼的執(zhí)行
編譯語言
解釋語言(js)
- 預(yù)先解析階段
變量和函數(shù)聲明的提升
- 具體的執(zhí)行代碼
- js 變量和函數(shù)聲明提升的注意點(diǎn)
- 變量和變量同名 后面的變量會(huì)把前面的變量覆蓋
- 函數(shù)和函數(shù)同名 覆蓋
- 變量和函數(shù)同名 函數(shù)聲明會(huì)正常的提升,而變量的聲明可以認(rèn)為被忽略了
只會(huì)提升到當(dāng)前作用域的最頂端
console.log("_____");
console.log(a); //und
var a = "test-A";
console.log(a); //Test-A
var a = "demo-A";
console.log(a); //demo-A
//模擬變量聲明的提升
// var a;
// console.log("_____");
// console.log(a); //und
// a = "test-A";
// console.log(a); //Test-A
// a = "demo-A";
// console.log(a); //demo-A
</script>
<script>
f1(); //Demo
function f1() {
console.log("Test");
}
f1(); //Demo
function f1() {
console.log("Demo");
}
f1(); //Demo
//模擬提升
// function f1() {
// console.log("Demo");
// }
// f1(); //Demo
// f1(); //Demo
// f1();
</script>
<!--<script>-->
<!--console.log(a); //函數(shù)-->
<!--var a = "test-A";-->
<!--function a() {-->
<!--console.log("demo-A");-->
<!--}-->
<!--console.log(a); //函數(shù)-->
<!--//模擬-->
<!--var a;-->
<!--function a() {-->
<!--console.log("demo-A");-->
<!--}-->
<!---->
<!--console.log(a); //函數(shù)-->
<!--a = "test-A";-->
<!--console.log(a); //test-A-->
<!--</script>-->
<script>
console.log(a);
var a = "test-A";
function a() {
console.log("demo-A");
}
// 不管函數(shù)在前面還是變量在前面,打印出來的結(jié)果都是函數(shù)
</script>
思考:
<script>
var demoA ="10";
function foo() {
console.log(demoA); //10 undefined(正確)
var demoA = "20";
console.log(demoA); //20
}
function func() {
console.log(demoA); //10
demoA = "30";
console.log(demoA); //30
}
foo();
func();
console.log(demoA); //30
變量提升是分作用域的
- 在代碼執(zhí)行之前,會(huì)把所有的變量和函數(shù)生命進(jìn)行提升
- 在提升的時(shí)候,變量和函數(shù)聲明的提升是分作用域的,只能提升到當(dāng)前作用域的頂端
- 內(nèi)層作用域中的變量聲明并不會(huì)覆蓋外層作用域中的同名變量
console.log(demo);
var a = "第一個(gè)a";
function demo() {
console.log(a); //? undefined
a = "張三";
console.log(a); //張三
var a = "哈哈哈";
console.log(a); //哈哈哈
}
console.log(a);
demo();
console.log(a); //第一個(gè)a(正確) ? 張三 ?哈哈哈
</script>
<script>
var b = 10;
function test() {
console.log(b);
var b = 20;
}
console.log(b); //10
test(); //und
console.log(b);
</script>
函數(shù)表達(dá)式的提升
- 函數(shù)表達(dá)式提升,在提升的時(shí)候僅僅只會(huì)把聲明部分(var func02)提升到當(dāng)前作用域的頂端
<script>
console.log(func01);;
function func01() {
console.log("func01");
}
</script>
<script>
// var func02;
console.log(func02);;
var func02 = function () {
console.log("func02");
}
</script>
筆試題練習(xí)
<script>
function foo() {
var num = 123;
console.log(num); //123
}
foo();
//console.log(num); //報(bào)錯(cuò)
</script>
<script>
var scope = "global";
foo();
function foo() {
console.log(scope); //?global
scope = "local";
console.log(scope); //?local
}
console.log(scope); //local
</script>
in:檢查對(duì)象中是否存在指定的屬性
<!--<script>-->
<!--function f1(){-->
<!--var a;-->
<!--if("a" in window){-->
<!--a = 10;-->
<!--}-->
<!--console.log(a); //? 10 ? undefined ?報(bào)錯(cuò)-->
<!--}-->
<!--f1();-->
<!--</script>-->
<!--<script>-->
<!--if("a" in window){-->
<!--var a = 10;-->
<!--}-->
<!--console.log(a); //? 10 -->
<!--</script>-->
<!--<script>-->
<!--if(!"a" in window){-->
<!--var a = 10;-->
<!--}-->
<!--console.log(a); //?-->
<!--</script>-->
<script>
if("a" in window){
a = 10;
}
console.log(a); //? 報(bào)錯(cuò)
</script>
<script>
var foo = 1;
function bar() {
var foo;
if(!foo)
{
foo = 10;
}
console.log(foo); //?
}
bar();
// undefined == null; 相等
// undefined == false; 不相等
// !undefined
console.log(undefined === null); //true
console.log(!undefined == true);
</script>
function Foo() {
getName = function(){
console.log("1");
};
return this;
}
Foo.getName = function() {
console.log("2");};
Foo.prototype.getName = function(){
console.log("3");};
var getName = function() {
console.log("4");
};
function getName(){
console.log("5");
}
Foo.getName(); // ? 2
getName(); // ? 4
Foo().getName(); // ? (1) ? 3 ? 2 ? 4
getName(); // ? (1)
new Foo.getName(); // ? 2
new Foo().getName(); // ? 3
new new Foo().getName(); // ? 3
作用域鏈
- 有多少個(gè)作用域 (函數(shù)的個(gè)數(shù) + 1)
- 相同作用域可以相互訪問
- 作用域鏈:
在 js 中函數(shù)可以創(chuàng)建作用域,在函數(shù)內(nèi)部又可以聲明函數(shù),在函數(shù)的函數(shù)內(nèi)部又可以聲明函數(shù),每個(gè)函數(shù)都會(huì)創(chuàng)建一個(gè)作用域,這樣就會(huì)形成一個(gè)作用域鏈
- 在訪問變量的時(shí)候,總是先在自己的作用域中查找
- 如果沒有那么就向上一級(jí)作用域查找,如果找到那么就直接使用,如果沒有找到那么就繼續(xù)重復(fù)這個(gè)過程
- 直到最外層的全局作用域,如果還沒有找到那么就報(bào)錯(cuò)
var a = "a";
//f1--->全局作用域
function f1() {
var b = "b";
var a = "f1-a"
//f2-->f1--->全局作用域
function f2() {
var c = "c";
var b = "f2--b";
//f3-->f2-->f1--->全局作用域
function f3() {
var d = "d";
//f4-->f3-->f2-->f1--->全局作用域
function f4() {
console.log(a, b, c, d,e);
}
f4();
}
f3();
}
f2();
}
f1();
作用域鏈繪圖
首先先找出全局變量(包含函數(shù)) a f1 f2 f3
畫出他們的圖形,并且連線(有箭頭),箭頭的方向表示的是是否可以訪問(同一級(jí)作用域可以互相訪問)
-
以上畫出0級(jí)作用域鏈 var a = "test-a";
function f1() {
var b = "test-b";
function f4() {
function f5() {
var c = "test-c";
var d = "test-d"
}
}
}
function f2() {
var e = "test-e";
//注意點(diǎn):在原型對(duì)象的方法中訪問該對(duì)象的其他方法,需要使用 this 前綴
function BookListManager(){
this.bookList = null;
}
BookListManager.prototype = {
constructor:BookListManager,
init:function(){
this.bookList = arr || [];
},
getBook:function(name){
for(var i in this.bookList){
if(this.bookList[i].name == name){
return this.bookList[i];
}
}
throw "要查找的對(duì)象不存在!"
},
updateBook:function(name,author){
//先找到這個(gè)對(duì)象
var book = this.getBook(name);
//修改對(duì)象
book.author = author;
},
addBook:function(obj){
this.bookList.push(obj);
},
removeBook:function(){
var book = this.getBook(name);
var index = this.bookList.indexOf(book);
if(index == -1){
throw '要?jiǎng)h除的對(duì)象不存在'
}
//刪除該對(duì)象
this.bookList.splice(index,1);
}
}
var jack = new BookListManager();
var tom = new BookListManager();
jack.init([{name:'古典文學(xué)研究',author:'古典'},{name:'莫言文集',author:'莫言'}]);
jack.addBook({name:'飛鳥集',author:'泰戈?duì)?});
console.log(jack.getBook('飛鳥集'));
jack.updateBook('飛鳥集','老太太');
jack.removeBook('飛鳥集');
console.log(jack.bookList);
嚴(yán)格模式不存在兼容性問題,如果當(dāng)前的瀏覽器支持嚴(yán)格模式,那么再掃描到"use strict"命令的時(shí)候就會(huì)開啟嚴(yán)格模式檢查,如果不支持嚴(yán)格模式那么就直接忽略
建議在寫代碼的時(shí)候全部開啟嚴(yán)格模式
"use strict";
//01 在嚴(yán)格模式下,所有的變量都必須使用var聲明
// 在默認(rèn)情況下,如果不適用var聲明變量,那么該變量默認(rèn)會(huì)成為window的屬性(全局變量)
// var a = 10;
// b = 20;
// console.log(b);
//02 在嚴(yán)格模式下,禁止使用八進(jìn)制
// var num = 022; //數(shù)值以0開頭,以八進(jìn)制的方式來處理
// var num = 0x22;
// console.log(num);
//03 在嚴(yán)格模式下,禁止使用使用with
// var obj = {name:"張三",age:20};
// with (obj)
// {
// name = "李四";
// age = 99
// }
// console.log(obj);
//04 在嚴(yán)格模式下, 不能刪除全局的變量
// 在默認(rèn)情況下,可以刪除全局變量(不能刪除成功),靜默失敗
// var str = "string";
// console.log(delete str);
// console.log(str);
//05 在嚴(yán)格模式下,不能在if語句中聲明函數(shù)
// if (true)
// {
// function demo() {
// console.log("demo");
// }
//
// demo();
// }
//06 在嚴(yán)格模式下,函數(shù)的形參不能出現(xiàn)同名的情況
// function test(a,b,a) {
//// var a = 1;
//// var b = 2;
//// var a = 3;
// console.log(a + b + a); //6 ? 8 ? 4 后面的會(huì)把前面的覆蓋
// }
//
// test(1,2,3);
//07 在嚴(yán)格模式下,不能使用arguments.callee|caller
//caller 指向的函數(shù)的調(diào)用者 注意點(diǎn):window調(diào)用該函數(shù),指向的是null
//arguments.callee 常用在遞歸調(diào)用中,指向的是函數(shù)自己
// function f1() {
// f2();
// }
// function f2() {
// console.log(f2.caller);
// }
// f1();
// f2();
// console.log((function (n) {
// if (n == 1) {
// return 1;
// }
//
// return arguments.callee(n - 1) + n;
//})(11));
//08 在嚴(yán)格模式下, 不能使用eval和arguments作為標(biāo)識(shí)符(變量和函數(shù)的名稱)
// var eval = "測(cè)試字符串";
// console.log(eval);
// var arguments ="....";
// console.log(arguments);
//09 在嚴(yán)格模式下,修正了this的指向
// 默認(rèn)情況下,this指向的是window,嚴(yán)格模式指向的undefined
// function func() {
// console.log(this);
// }
//
// func();
// var o = {};
// func.call(null); //嚴(yán)格模式下,指向的是null
//10 在嚴(yán)格模式下,arguments的表現(xiàn)不一致
//在默認(rèn)情況下,如果函數(shù)內(nèi)部形參被重新設(shè)置,那么arguments也會(huì)跟著改變
//在嚴(yán)格模式情況下,如果函數(shù)內(nèi)部形參被重新設(shè)置,那么arguments不會(huì)被改變,他們是相互獨(dú)立的
//值類型的數(shù)據(jù)作為函數(shù)的參數(shù)
function demo(str) {
console.log(str);
console.log(arguments[0]);
//重新設(shè)置形參的值
str = "hahahaha";
console.log(str);
console.log(arguments[0]);
}
demo("123456");
//引用類型的數(shù)據(jù)作為函數(shù)參數(shù)
function demo(obj) {
console.log(obj);
console.log(arguments[0]);
//重新設(shè)置形參的值
obj = {age:20};
console.log(obj);
console.log(arguments[0]);
}
demo({name:"張三"});
//"use strict";
//"use strict" 正確
//'use strict'; 正確
//'use strict' 正確
//use strict; 錯(cuò)誤
//"use Strict"; 錯(cuò)誤
//"use strict"; 錯(cuò)誤
//"use strict "; 錯(cuò)誤
//" use strict"; 錯(cuò)誤
// "use strict"; //位置01 對(duì)整個(gè)作用域中的代碼都有用
function demo01() {
// "use strict"; //位置02 僅僅對(duì)當(dāng)前的函數(shù)有用,函數(shù)后面的代碼不受影響
a = 10;
console.log(a);
}
function demo02() {
// "use strict"; //位置03 僅僅對(duì)當(dāng)前的函數(shù)有用
b = 20;
console.log(b);
}
demo01();
demo02();
概念:變量或者是函數(shù)起作用的范圍
當(dāng)代碼寫好之后,某個(gè)變量的作用域就已經(jīng)確定了
變量的作用域在代碼運(yùn)行之前是不確定的,只有在代碼執(zhí)行的時(shí)候才能根據(jù)當(dāng)前的上下文來確定
var a = "test-A";
function f1() {
var b = "test-B";
}
function f2() {
var c = "test-C";
}
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log(i,"_____"); //? 10
try
{
//可能出錯(cuò)的代碼
a();
}catch (error){
//如果出錯(cuò)了,那么就執(zhí)行此處的代碼
console.log(error);
}
// console.log(error);
var demo = "測(cè)試的字符串01";
function f1() {
var demo = "demo";
var test = 10;
f2();
}
function f2() {
console.log(demo);
console.log(test);
}
// f2(); //測(cè)試的字符串
f1(); //demo
編譯語言
解釋語言(js)
變量和函數(shù)聲明的提升
只會(huì)提升到當(dāng)前作用域的最頂端
console.log("_____");
console.log(a); //und
var a = "test-A";
console.log(a); //Test-A
var a = "demo-A";
console.log(a); //demo-A
//模擬變量聲明的提升
// var a;
// console.log("_____");
// console.log(a); //und
// a = "test-A";
// console.log(a); //Test-A
// a = "demo-A";
// console.log(a); //demo-A
</script>
<script>
f1(); //Demo
function f1() {
console.log("Test");
}
f1(); //Demo
function f1() {
console.log("Demo");
}
f1(); //Demo
//模擬提升
// function f1() {
// console.log("Demo");
// }
// f1(); //Demo
// f1(); //Demo
// f1();
</script>
<!--<script>-->
<!--console.log(a); //函數(shù)-->
<!--var a = "test-A";-->
<!--function a() {-->
<!--console.log("demo-A");-->
<!--}-->
<!--console.log(a); //函數(shù)-->
<!--//模擬-->
<!--var a;-->
<!--function a() {-->
<!--console.log("demo-A");-->
<!--}-->
<!---->
<!--console.log(a); //函數(shù)-->
<!--a = "test-A";-->
<!--console.log(a); //test-A-->
<!--</script>-->
<script>
console.log(a);
var a = "test-A";
function a() {
console.log("demo-A");
}
// 不管函數(shù)在前面還是變量在前面,打印出來的結(jié)果都是函數(shù)
</script>
思考:
<script>
var demoA ="10";
function foo() {
console.log(demoA); //10 undefined(正確)
var demoA = "20";
console.log(demoA); //20
}
function func() {
console.log(demoA); //10
demoA = "30";
console.log(demoA); //30
}
foo();
func();
console.log(demoA); //30
console.log(demo);
var a = "第一個(gè)a";
function demo() {
console.log(a); //? undefined
a = "張三";
console.log(a); //張三
var a = "哈哈哈";
console.log(a); //哈哈哈
}
console.log(a);
demo();
console.log(a); //第一個(gè)a(正確) ? 張三 ?哈哈哈
</script>
<script>
var b = 10;
function test() {
console.log(b);
var b = 20;
}
console.log(b); //10
test(); //und
console.log(b);
</script>
<script>
console.log(func01);;
function func01() {
console.log("func01");
}
</script>
<script>
// var func02;
console.log(func02);;
var func02 = function () {
console.log("func02");
}
</script>
<script>
function foo() {
var num = 123;
console.log(num); //123
}
foo();
//console.log(num); //報(bào)錯(cuò)
</script>
<script>
var scope = "global";
foo();
function foo() {
console.log(scope); //?global
scope = "local";
console.log(scope); //?local
}
console.log(scope); //local
</script>
in:檢查對(duì)象中是否存在指定的屬性
<!--<script>-->
<!--function f1(){-->
<!--var a;-->
<!--if("a" in window){-->
<!--a = 10;-->
<!--}-->
<!--console.log(a); //? 10 ? undefined ?報(bào)錯(cuò)-->
<!--}-->
<!--f1();-->
<!--</script>-->
<!--<script>-->
<!--if("a" in window){-->
<!--var a = 10;-->
<!--}-->
<!--console.log(a); //? 10 -->
<!--</script>-->
<!--<script>-->
<!--if(!"a" in window){-->
<!--var a = 10;-->
<!--}-->
<!--console.log(a); //?-->
<!--</script>-->
<script>
if("a" in window){
a = 10;
}
console.log(a); //? 報(bào)錯(cuò)
</script>
<script>
var foo = 1;
function bar() {
var foo;
if(!foo)
{
foo = 10;
}
console.log(foo); //?
}
bar();
// undefined == null; 相等
// undefined == false; 不相等
// !undefined
console.log(undefined === null); //true
console.log(!undefined == true);
</script>
function Foo() {
getName = function(){
console.log("1");
};
return this;
}
Foo.getName = function() {
console.log("2");};
Foo.prototype.getName = function(){
console.log("3");};
var getName = function() {
console.log("4");
};
function getName(){
console.log("5");
}
Foo.getName(); // ? 2
getName(); // ? 4
Foo().getName(); // ? (1) ? 3 ? 2 ? 4
getName(); // ? (1)
new Foo.getName(); // ? 2
new Foo().getName(); // ? 3
new new Foo().getName(); // ? 3
在 js 中函數(shù)可以創(chuàng)建作用域,在函數(shù)內(nèi)部又可以聲明函數(shù),在函數(shù)的函數(shù)內(nèi)部又可以聲明函數(shù),每個(gè)函數(shù)都會(huì)創(chuàng)建一個(gè)作用域,這樣就會(huì)形成一個(gè)作用域鏈
var a = "a";
//f1--->全局作用域
function f1() {
var b = "b";
var a = "f1-a"
//f2-->f1--->全局作用域
function f2() {
var c = "c";
var b = "f2--b";
//f3-->f2-->f1--->全局作用域
function f3() {
var d = "d";
//f4-->f3-->f2-->f1--->全局作用域
function f4() {
console.log(a, b, c, d,e);
}
f4();
}
f3();
}
f2();
}
f1();
首先先找出全局變量(包含函數(shù)) a f1 f2 f3
畫出他們的圖形,并且連線(有箭頭),箭頭的方向表示的是是否可以訪問(同一級(jí)作用域可以互相訪問)
以上畫出0級(jí)作用域鏈 var a = "test-a";
function f1() {
var b = "test-b";
function f4() {
function f5() {
var c = "test-c";
var d = "test-d"
}
}
}
function f2() {
var e = "test-e";
// f4();
}
function f3() {
}
f2();