欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于this、let、var的题目(一)

程序员文章站 2022-07-14 21:36:52
...
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 则指向创建时的环境对象。

另一个重要的概念 varlet 的理解也至关重要,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] 两个方法
执行 obj.method(fn,1) 时传 fn 和 1 两个参数,执行到函数体内 执行 fn 和 argument[0] 两个方法,第一个方法 fn 中 this 指向全局对象 window,而
window.length 返回当前窗口中包含的框架数量(框架包括frame和iframe两种元素),所以如果没有框架数量的话就是 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 属性指向当前执行的函数
关于this、let、var的题目(一)
注意:现在在严格模式下,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
关于this、let、var的题目(一)

有朋友这么形容输出的
关于this、let、var的题目(一)
用 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

感谢大佬们发题