关于this、let、var的题目(一)
let length = 10
function fn(){
console.log(this.length);
}
let obj = {
length:5,
method(fn){
fn();
arguments[0]();
}
};
obj.method(fn,1) //输出是什么
温习下概念,this 是当前执行代码的环境对象,在全局执行环境中(无论是否严格模式)指向全局对象,而在函数内部,它的值取决于函数被调用的方式,而严格模式下如果未被执行环境(execution context)定义就保持 undefined
,可以通过 call 或者 apply 指定 this 来调用函数/方法,也可以 es5 bind 直接指定 this 返回具有相同函数体和作用域的函数方便调用,在 es6 中箭头函数中的 this 则指向创建时的环境对象。
另一个重要的概念 var 和 let 的理解也至关重要,var 用来声明变量并可选将其初始化为一个值,它的作用域是它当前的执行上下文,在实际使用时需要注意变量声明提升,但是值不会提升作用域顶部,而是执行时到赋值语句才会分配变量的值。
在全局作用域内声明一个变量会将变量添加到全局对象(JavaScript 标准内置对象),例如在浏览器环境中
var length = 10;
console.log(length, this.length, window.length);
// 10, 10, 10
如果我们只声明了 length 并未赋值,此时输出的结果很迷
var length;
console.log(length, this.length, window.length);
// 0, 0, 0
实际上呢,该属性已经在浏览器环境的全局对象中,只是你重新声明了,并没有赋值,所以全局对象 window 的属性 length 对应着原来的那个值,想通这一点就简单多了。
let 语句用于声明块级作用域的本地变量,并可选初始化赋值,它所声明的作用域被限制在 块 级中的变量、语句或者表达式,只有在编译时才会初始化。
在 let 声明的变量只在其声明的块或者子块中可用,不能重复声明(会导致 SyntaxError),而且不会变量提升,在使用时一定要先声明变量才能使用。按照 let 的定义可知,在全局作用域中用 let 声明变量是不会像 var 一样将变量添加为全局对象的属性,所以
console.log(length, this.length, window.length);
// 0, 0, 0
let length = 10;
console.log(length, this.length, window.length);
// 10, 0, 0
现在还回到原来的题目中,obj.method定义接收一个参数 fn,函数内部执行 fn 和 arguments[0] 两个方法 window.length 返回当前窗口中包含的框架数量(框架包括frame和iframe两种元素)
执行 obj.method(fn,1) 时传 fn 和 1 两个参数,执行到函数体内 执行 fn 和 argument[0] 两个方法,第一个方法 fn 中 this 指向全局对象 window,而,所以如果没有框架数量的话就是 0;
在全局作用域中直接执行函数 fn, this直接指向全局对象,获取到 window.length 为 0
function fn(){
console.log(this.length);
}
fn();
// 0
关于对象 obj 的方法 method 接收一个参数,这个参数作为回调函数,运行,写成下面的样子就看着舒服了
let obj = {
length : 5,
method(callback){
callback();
arguments[0]();
}
}
// 有声音说,一定要检查callback的类型,下次再说吧
先理解一个概念,javascript 支持将函数作为参数传递,回调函数变量指向的函数对象都未与任何上下文绑定,所有未与明确上下文绑定的变量都是*变量,浏览器中所有的*变量的上下文都是 window 对象。
obj 的属性 method 接收一个函数对象作为回调函数,执行时函数内部 this 指向 obj 对象,但是 method 方法内部 callback 执行时并未绑定任何上下文,所以它内部的 this 指向 window 对象
let length = 10;
function fn(){
console.log(this == window);
}
let obj = {
method(callback){
callback();
}
}
obj.method(fn);
// true
通过 window.length 很容易得到结果 0
let length = 10;
function fn(){
console.log(this.length);
}
let obj = {
length: 5,
method(callback){
callback();
}
}
obj.method(fn);
// 0
arguments[0] 中 arguments 对象是所有(非箭头)函数中都可用的局部变量,是传递给函数的参数的类数组对象,this 指向arguments,而函数传入几个参数就是arguments的长度,就输出几个参数的长度。
let length = 10;
function fn(){
// console.log(this.length);
}
let obj = {
length: 5,
method(callback){
callback();
console.log(arguments);
}
}
obj.method(fn, 1);
可以清晰的看到 arguments 的 callee 属性指向当前执行的函数
注意:现在在严格模式下,arguments对象已与过往不同。arguments[@@iterator]不再与函数的实际形参之间共享,同时caller属性也被移除(es5以后)。
传递进来的 fn 函数是类数组对象 arguments 的一个方法,当 arguments[0] 执行时,按照谁调用函数 this 指向谁的原则下,this 指向调用的对象 arguments
let length = 10;
function fn(){
return this;
}
let obj = {
length: 5,
method(callback){
callback();
console.log(arguments == arguments[0]());
}
}
obj.method(fn, 1);
// true
那么此时 arguments 的长度是2,最后输出 this 的 length 便是2
有朋友这么形容输出的
用 call 或者 apply 将 this 绑定至指定对象来调用函数,结果很喜人
let length = 10;
function fn(){
console.log(this.length);
}
let obj = {
length: 5,
method(callback){
callback.call(obj);
arguments[0].call(obj);
}
}
obj.method(fn, 1);
// 5
// 5
感谢大佬们发题