var name = 'World!';
(function() {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
複製代碼
答案:Goodbye Jackwindows
註釋bash
1.代碼執行前,先預解析。函數
2.var變量提高,提高到當前做用域最前面。ui
3.首先給全局的變量name賦值爲'World!',而後匿名函數自調用。this
4.把匿名函數裏的變量name提高到當前做用域最前面。spa
5.匿名函數裏的name聲明但未賦值,因此name爲undefined。typeof name === undefined爲true。prototype
6.因此執行結果爲Goodbye Jack。code
下面是預解析代碼過程對象
var name;
(function() {
var name; 變量聲明未賦值==>undefined
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
name = 'World!';
複製代碼
詞法做用域規則:函數的做用域在聲明的時候就已經決定了,與調用位置無關。原型鏈
var a = 10;
function aaa() {
alert(a);
}
function bbb() {
var a = 20;
aaa();
}
bbb();
複製代碼
答案:10。
分析:
1.預解析,把a的聲明和函數aaa() 和函數bbb() 聲明提高到當前做用域最前面。
2.給全局的a賦值爲10,而後調用bbb()。
3.函數執行前要預解析,將函數bbb裏的變量a提高到當前做用域,而後執行函數bbb。並給a賦值爲20.再調用函數aaa()。
4.由於函數aaa的做用域在聲明的時候就已經在全局了,因此aaa內部訪問變量a的時候,按照做用域鏈的查找規則,找到全局的a。並alert(a)爲10。
下面是預解析代碼過程
var a;
function aaa(){
alert(a);
}
function bbb(){
var a;
a = 20;
aaa();
}
a = 10;
bbb();
複製代碼
題目一:
var scope = 'global scope';
function checkScope() {
var scope = 'local scope';
function f() {
return scope;
}
return f;
}
var fn = checkScope();
var a = fn();
console.log(a);
複製代碼
答案:local scope
解析:
1.調用checkScope()函數。並將返回值賦值給fn,在checkScope做用域裏定義了一個變量scope,還有f函數。並把f函數返回賦值給fn。
fn = function() {
return scope;
}
複製代碼
2.調用fn函數,並將返回值賦值給a。因爲fn的函數做用域是在checkScope做用域內部,因此在調用函數fn時,訪問到的scope是checkScope函數做用域內的scope。
3.最終a的值爲local scope
題目二:
var scope = 'global scope';
function checkScope() {
var scope = 'local scope';
function f(scope) {
return scope;
}
return f;
}
var fn = checkScope();
var a = fn(123);
console.log(a)
複製代碼
答案:123
解析:
1.調用checkScope函數,並將返回值賦值給fn,在checkScope內部定義了一個scope變量,還有一個f函數。把f函數返回並賦值給fn。
fn = function(scope) {
return scope;
}
複製代碼
2.調用函數fn,並將返回值賦值給a,因爲fn的函數做用域在checkScope函數內部。因此調用fn函數時,進行參數傳遞。至關於在scope做用域內部聲明var scope = 123。雖然fn函數做用域是在checkScope函數內部。可是fn函數內部就有變量scope,因此訪問到的是自身scope。
3.因此a的值爲123.
題目三
var scope = 'global scope';
function checkScope() {
var scope = 'local scope';
function f() {
scope = 233;
return scope;
}
return f;
}
var fn = checkScope();
var a = fn();
console.log(a);
複製代碼
答案:233
解析:
1.調用函數checkScope,並把返回值賦值給fn。函數checkScope內部定義了一個變量scope,並聲明瞭f函數。將f返回並賦值給fn。
fn = function(){
scope = 233;
return scope;
}
複製代碼
2.調用fn函數,並賦值給a。fn函數做用域在checkScope函數內部。因此在調用fn函數時,訪問到的scope是checkScope函數做用域內的scope。
3.因此a的值爲233.
1.建立了一個空對象
2.讓this指向了這個空對象
3.執行構造函數裏的代碼
4.返回this指向的這個對象
題目一:
function A() {
console.log('A');
return 'aaa';
}
var obj1 = new A();
console.log(obj1);
複製代碼
答案:
A A{}
複製代碼
解析: 若是函數的返回值爲基本數據類型(string,number,boolean,null,undefined) 則JS引擎會忽略該返回值,並建立一個新對象。
題目二
function B() {
console.log('B');
return { b: 'bbb' };
}
var obj2 = new B();
console.log(obj2);
複製代碼
答案:
B { b: 'bbb' }
複製代碼
解析:若是函數的返回值爲引用類型,則實際返回值爲這個引用數據類型。
題目三
function C() {
console.log('C');
}
var obj3 = new C();
console.log(obj3);
複製代碼
答案:
C C{}
複製代碼
解析:若是函數沒有返回值,則返回this指向的對象。
題目四
function D() {
console.log('D');
return this;
}
var obj4 = new D();
console.log(obj4);
複製代碼
答案:
D D{}
複製代碼
解析:若是函數返回值是this,那麼與沒有返回值結果是同樣的。
題目五
function obj5() {
console.log('E');
}
new obj5();
複製代碼
答案:E
解析:由於沒有變量接收這個實例對象。因此new四步操做最後一步不執行。不返回this指向的新對象。因此打印E。
1.函數調用模式
2.方法調用模式
3.構造函數調用模式
4.上下文調用模式
複製代碼
題目一
var name = 'windowsName';
function a() {
var name = 'Cherry';
console.log(this.name);
console.log(this);
}
a();
複製代碼
答案:
windowsName window
複製代碼
解析:函數調用模式,this指向window
題目二
var name = 'windowsName';
var a = {
name: 'Cherry',
fn: function() {
console.log(this.name);
}
};
a.fn();
複製代碼
答案:Cherry
解析:方法調用模式,this指向的a
題目三
var name = 'windowsName';
var a = {
fn: function() {
console.log(this.name);
}
};
a.fn();
複製代碼
答案:undefined 解析: 方法調用模式。this指向的window.a ==> a.name =>undefined
題目三
var name = 'windowsName';
var a = {
name: 'Cherry',
fn: function() {
console.log(name);
console.log(this.name);
}
};
var f = a.fn;
f();
複製代碼
答案:windowsName windowsName
解析:函數調用模式。this指向的window。
題目四
var name = 'windowsName';
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name);
}
}
fn();
複製代碼
答案:windowsName
解析:函數調用模式,this指向的window。
什麼是實例?
實例就是由構造函數建立出來的對象
什麼是成員?
成員是屬性和方法的統稱
什麼是實例成員?
由構造函數建立出來的對象能直接訪問的屬性和方法,包括:對象自己,以及原型中的全部屬性和方法。
什麼是靜態成員?
由構造函數直接訪問到的屬性和方法。注意是直接訪問的屬性和方法,間接獲取就不是了。
function Person(name) {
this.name = name;
}
Person.age = 18;
Person.run = function() {
console.log('run');
};
Person.prototype.sayHi = function() {
console.log('hi');
};
var p = new Person('xf');
console.log(p.name);
p.sayHi();
// 實例對象不能夠訪問到構造函數上的成員
console.log(p.age);
// p.run();
console.log(Person.age);
Person.run();
複製代碼
答案:
xf hi undefined 18 run
複製代碼
function Foo() {
getName = function() {
console.log(1);
};
console.log(this);
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();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
複製代碼
答案:
2 4 window 1 1 2 Foo{} 3
複製代碼
解析:
先預解析代碼以下:
1.變量和函數聲明提高。併合寫爲表達式。
function Foo() {
getName = function() {
console.log(1);
};
console.log(this);
return this;
}
`var getName;
function getName() {
console.log(5);
}`
上面的寫下面表達式這種
var getName = function() {
console.log(5);
}
Foo.getName = function() {
console.log(2);
};
Foo.prototype.getName = function() {
console.log(3);
};
getName = function() {
console.log(4);
};
複製代碼
這個打印的4會覆蓋上面的表達式5
getName = function() {
console.log(4);
};
複製代碼
因此最後解析成下面這樣
function Foo() {
getName = function() {
console.log(1);
};
console.log(this);
return this;
}
var getName = function() {
console.log(4);
}
Foo.getName = function() {
console.log(2);
};
Foo.prototype.getName = function() {
console.log(3);
};
複製代碼
開始打印解析:
Foo.getName() ==> 構造函數.方法 =>由於構造函數直接訪問方法和屬性是靜態成員。因此打印的是
Foo.getName = function() {
console.log(2);
};
複製代碼
getName(); =>
var getName = function() {
console.log(4);
}
複製代碼
Foo().getName() ==> 先執行Foo()方法 因此會打印window,而後再調用getName() ,打印1,此處Foo()裏的
getName = function() {
console.log(1);
};
```會覆蓋外面的
複製代碼
var getName = function() {
console.log(4); }
因此會再打印一個1
此時代碼變成了
function Foo() {
getName = function() {
console.log(1);
};
console.log(this);
return this;
}
var getName = function() {
console.log(4); 改爲=>console.log(1);
}
Foo.getName = function() {
console.log(2);
};
Foo.prototype.getName = function() {
console.log(3);
};
getName(); => 打印1
new Foo.getName(); => new (Foo.getName)() ==> 2
new Foo().getName(); ==> (new Foo()).getName(); 調用實例的getName()方法,
沿着原型鏈查找。根據屬性查找原則。打印的是3.
複製代碼