JS作用域与new关键字——长期更新

时间:2022-04-22 17:02:08

关于作用域: 

首先要知道js的两点,一是变量提升,而是js只有词法作用域。下面三段代码可以很好诠释这个逻辑。

//************************************************************************** 
var a="aa";
function test(){
alert(a);//undefined,函数执行后,在函数环境内,var a会预解析,当弹出a时,首先先找本层环境内有无声明,发现有但是代码没有执行到赋值,所以结果是undefined。
var a="bb";//var a会预解析在函数开头,执行到这行才进行赋值
alert(a);//“bb”
}
test();
alert(a);//”aa” 找全局环境下的声明,找到了var a=”aa”

//**************************************************************************
var a="aa";
function test(){
alert(a);//“aa”,函数执行后,在函数环境内,没有找到本层环境关于a的声明,所以开始向上一层环境查找。
a=”bb”;//执行到这行开始改变全局a的量
}
test();
alert(a);//”bb” 全局环境的a在函数执行时已经被改变

//**************************************************************************
function test(){
b();//函数b会被预解析,因此可以调用,执行了输出1;
var a=1;
function b(){
console.log(1);
console.log(a);//undefined
var a=2;
}
}
test();

//先找本层环境有无声明,有的话,看是否进行了赋值;只有声明没有执行赋值,就是undefined.没有声明也没有赋值的话,就再向上一层查找,直到找到为止.如果所有的执行环境都没有找到,那么控制台就会报错变量找不到.

关于new关键字: 

js中提供多个內建对象(string、number、array、math、date等,但是前三个不建议使用,能不用就别用)和自定义对象。在创建对象时,一般使用new关键字。也有人建议用对象字面量来创建对象。对象字面量的形式好理解,今天说一说new关键字。依然就一段代码来说,原作者是:hebedich,来源:脚本之家。

function Animal(name){ 
this.name = name;
}
Animal.color = “black”;
Animal.prototype.say = function(){
console.log(“I’m ” + this.name);
};
var cat = new Animal(“cat”);

console.log(
cat.name, //cat
cat.height //undefined
);
cat.say(); //I’m cat

console.log(
Animal.name, //Animal
Animal.color //back
);
Animal.say(); //Animal.say is not a function

代码解读:1-3行创建了一个函数Animal,并在this上定义了属性:name,name是值是被执行的形参。 
第4行在Animal对象上定义了一个静态属性:color,并赋值black 
5-7行在Animal函数的原型对象prototype上定义了一个say方法,say方法输出了this的name值 
8行通过new关键字创建了一个新对象cat 
10-14行cat对象尝试访问name和color属性,并调用say方法 
16-20行Animal对象尝试访问name和color属性,并调用say方法

重点是第八行new Animal的代码,js引擎在执行这句代码时,做了很多工作,用伪代码来表示其工作流程 

var obj = {}; 
obj.proto = Animal.prototype;
var result = Animal.call(obj,”cat”);
return typeof result === ‘obj’? result : obj;

1、创建一个空对象 
2、把obj的proto指向Animal的原型对象prototype,此时即创建了原型链obj(cat)-Animal.prototype-Object.prototype-null 
3、在obj对象执行空间调用Animal函数并传入参数cat。相当于var result = obj.Animal(”cat”) 
4、返回值

我相信大家还有一个疑惑的地方也许跟我一样,为啥Animal.name的结果是Animal。什么鬼 
原来函数对象在产生时会内置name属性并将函数名作为赋值(仅函数对象) 
那为什么Animal.say不存在呢 
我们看下Animal的原型链:Animal-Function.prototype-object.prototype-null

js引擎总是这样,先在局部作用域查找属性或者方法,当找不到的时候沿着原型链进行查找,直到null。 
js中new关键字的主要作用是继承,而继承的方式则是原型链,上面的例子中,cat对象在产生时便继承了Animal中 定义的方法和属性,因此cat不是Animal的实例而是其子类。

js中使用new关键字和对象字面量的区别: 
使用new关键字以原型的方式将user对象暴露在window对象中 

//one 
var user = function(){
this.name=”“;
this.id=”“;
};
user.add = function(){
console.log(“add”);
};
user.delete = function(){
console.log(“delete”);
};
user.prototype = user;
window.user = new user();

不使用new关键字直接将user暴露在window对象中 
//two var user = { name:”“, id:”” }; user.add = function(){ console.log(“add”); }; user.delete = function(){ console.log(“delete”); }; window.user = user;//******************************************************************************************function Animal(nae){ this.nae = nae; } Animal.color = “red”var cat = new Animal(“cat”);console.log( Animal.color, //red Animal.name, //Aniaml cat.nae //cat );


ps:8/8重编辑