前端笔试题网易之一-js函数体内的名称解析问题
2014-04-08 15:35
253 查看
这是师姐去年去网易面试时遇到的一个问题。
function A(){
alert(a);
var a=10;
alert(this.a);
}
A();//undefined undefined
new A();//undefined undefined
为什么两个都是undefined?
我认为这是涉及打了函数体内的变量名称解析的问题。
首先看第一个A();这个是在全局作用域中调用A函数,和普通的函数调用一样,此时的函数A作为了全局变量window对象的方法被调用,所以此时this指向的是window,由于window对象中没有一个名称为a的属性,所以alert(this.a)为undefined。为什么第一个alert(a)也为undefined,是因为在调用A函数之前,读取A函数的方法体,发现声明了变量a,于是将a放到了作用域的前端(但是没有初始化a,等到执行var a=10;这句语句时,才初始化a,这就是变量声明提升),所以第一个alert为undefined。
如果我在window全局变量中放入一个属性a,那么,this.a就只向了window全局变量中a,alert 20.
var a=20;
function A(){
alert(a);
var a=10;
alert(this.a);
}
A();//undefined 20
总结:在一个函数体内直接调用变量名alert(a)和alert(this.a)是不一样的,前者是在作用域链中搜寻对应的变量,而通过this.属性进行访问变量,该函数被作为哪个对象的方法被调用,就在this就指向该对象,就在该对象中搜索该属性(准确的说是在该对象的原型链中搜索该属性,下面会细讲),也就是说this.属性 的值和作用域没有关系,由于js中没有类域的概念(在java中在一个类中声明的实例变量a,那么在这个类中this.a 和a 是一样的),所以想要访问当前对象的属性,必须通过this.属性
,否则访问的都只是函数的作用域中的变量。如下面的例子:
var a=20;
function A(){
alert(a);
var a=10;
alert(this.a);//通过this.属性或方法,是在原型链上进行解析的
}
//A();
var o={
a:1000
};
o.A=A;
o.A();//undefined 1000
看第二个语句 new A();在js中执行一个new方法时(实际上要进行四个步骤的操作,详见我的下一篇文章《new一个对象,需要几步?》):首先需要创建一个对象,然后将构造函数的作用域复制给该对象,此时的this实际就执向了该对象,然后再执行构造函数,最后返回这个对象。为了更加明确的说明this的指向以及this.属性的查找,我换了一个使用了继承的例子。
alert(this.a);//1000,该a位于B的原型中。
alert(this.a);//1000 a位于父类的父类Object的原型中。所以说构造函数中的this.属性的查找是沿着原型链进行的。其实不仅是构造函数,一切普通函数中的this.属性的查找都是沿着原型链进行的。而alert(a);依旧是undefined,是沿着作用域查找的。
function A(){
alert(a);
var a=10;
alert(this.a);
}
A();//undefined undefined
new A();//undefined undefined
为什么两个都是undefined?
我认为这是涉及打了函数体内的变量名称解析的问题。
首先看第一个A();这个是在全局作用域中调用A函数,和普通的函数调用一样,此时的函数A作为了全局变量window对象的方法被调用,所以此时this指向的是window,由于window对象中没有一个名称为a的属性,所以alert(this.a)为undefined。为什么第一个alert(a)也为undefined,是因为在调用A函数之前,读取A函数的方法体,发现声明了变量a,于是将a放到了作用域的前端(但是没有初始化a,等到执行var a=10;这句语句时,才初始化a,这就是变量声明提升),所以第一个alert为undefined。
如果我在window全局变量中放入一个属性a,那么,this.a就只向了window全局变量中a,alert 20.
var a=20;
function A(){
alert(a);
var a=10;
alert(this.a);
}
A();//undefined 20
总结:在一个函数体内直接调用变量名alert(a)和alert(this.a)是不一样的,前者是在作用域链中搜寻对应的变量,而通过this.属性进行访问变量,该函数被作为哪个对象的方法被调用,就在this就指向该对象,就在该对象中搜索该属性(准确的说是在该对象的原型链中搜索该属性,下面会细讲),也就是说this.属性 的值和作用域没有关系,由于js中没有类域的概念(在java中在一个类中声明的实例变量a,那么在这个类中this.a 和a 是一样的),所以想要访问当前对象的属性,必须通过this.属性
,否则访问的都只是函数的作用域中的变量。如下面的例子:
var a=20;
function A(){
alert(a);
var a=10;
alert(this.a);//通过this.属性或方法,是在原型链上进行解析的
}
//A();
var o={
a:1000
};
o.A=A;
o.A();//undefined 1000
看第二个语句 new A();在js中执行一个new方法时(实际上要进行四个步骤的操作,详见我的下一篇文章《new一个对象,需要几步?》):首先需要创建一个对象,然后将构造函数的作用域复制给该对象,此时的this实际就执向了该对象,然后再执行构造函数,最后返回这个对象。为了更加明确的说明this的指向以及this.属性的查找,我换了一个使用了继承的例子。
alert(this.a);//1000,该a位于B的原型中。
alert(this.a);//1000 a位于父类的父类Object的原型中。所以说构造函数中的this.属性的查找是沿着原型链进行的。其实不仅是构造函数,一切普通函数中的this.属性的查找都是沿着原型链进行的。而alert(a);依旧是undefined,是沿着作用域查找的。
相关文章推荐
- Web前端面试笔试题2——JS(1):函数调用(局部变量/全局变量)
- js在ThinkPHP框架中使用{:U()}函数链接 传参解析不正确问题
- js dwz框架 多页面id,函数名称冲突问题
- js拼接字符串函数名称中带参数引号问题
- js拼接字符串函数名称中带参数引号问题
- js中三种函数的效率、解析顺序、作用域问题解决
- web前端关于html转义符的常用js函数
- 前端 js不知道key的情况下解析json
- 前端面试之js相关问题(一)
- web前端 js中函数的两种常见写法
- Jquery 解析 JSON html js 双引号 的问题
- 程序中和有js函数的网页交互,线程中调用 get_Script 就会错误的解决方法,由于COM的线程安全问题
- PHP问题:js中的encodeURIcomponent 函数在php如何实现?
- 无法将“Update-Database”项识别为 cmdlet、函数、脚本文件或可运行程序的名称的问题
- 前端初级开发笔试题——用js编写一个时钟实例
- ajaxfileupload_v.js 解决js版本不兼容,多文件上传不解析json的问题
- js经典面试问题:如何让for循环中的setTimeout()函数像预想中一样工作?
- js经典面试问题:如何让for循环中的setTimeout()函数像预想中一样工作?
- js中apply和Math.max()函数的问题?
- js 函数的参数长度问题