1、with 語句用於設置代碼在特定對象中的作用域。
例如:
var obj = {
name: "obj"
}
var name = "window";
function func(){
var name = "func";
with(obj){
console.log(name);
}
}
func();
打印的結果:obj;
實際上:對於with語句而言,會將指定的對象添加到作用域鏈中。
var obj = {
// name: "obj"
}
var name = "window";
function func(){
var name = "func";
with(obj){
console.log(name);
}
}
func();
打印的結果:func;
2、理解with的作用,理解函數作用域鏈和this對象
例如:
({
x: 10,
foo: function () {
function bar() {
console.log(x);
console.log(y);
console.log(this.x);
}
with (this) {
var x = 20;
var y = 30;
bar.call(this);
}
}
}).foo();
分析:
with的特點:(請完全理解下面的with特點)
作用域鏈的頂部添加with傳入的對象,即:with內先查找和操作該對象的屬性,如果該對象沒有找到,再往作用域鏈的下一級查找,然後操作操作。(obj作用域——>函數1——>函數2——>...——>window全局作用域)
問題中,變量聲明提示和函數聲明提升後的實際代碼是:
({
x: 10,
foo: function () {
var x;//默認undefined,等會分析要用到
var y;//默認undefined
function bar() {
console.log(x);
console.log(y);
console.log(this.x);
}
with (this) {
x = 20;
y = 30;
bar.call(this);
}
}
}).foo();
var x; x變量的默認值undefined;
var y;y變量的默認值undefined;
等會分析會用到
當代碼走到with中時,this是外面的大對象。
(1)x =20
根據with的特點(上面提到的),先在this大對象中找x屬性(對象中叫屬性,函數叫變量),巧了,this大對象有x:10,將值改爲20;
(2)y =30
同樣的,在this大對象中找y屬性,沒有!再去foo函數中y變量,有!設置y爲30;
(3)bar.call(this)
大家要注意:call apply bind(ES5)都是隻改變this指向,this指向只與this對象相關的操作有關。與函數變量沒有一點關係!!!
執行bar函數,call修改this指向,指向大對象。
bar函數執行
(1)打印變量x。bar函數中沒有變量x,往上面的作用域找,foo函數中有變量x,x的值是undefined。(with改變的x是指大對象的x屬性)
(2)打印變量y。bar函數沒有變量y,往上找,foo函數中有變量y,值爲30。(with語句改變y的時候,先去大對象中找y屬性,沒有,再去foo函數中找到y變量,並將其修改爲30)
(3)打印this.x。打印大對象的x屬性,值爲20。
所以結果:
變量x:undefined
變量y:30
this.x:20