js中this指针、var、作用域、解析与执行过程
this指针
内容来自 https://www.cnblogs.com/pssp/p/5216085.html,这里摘录了这位前辈的部分内容。
this在面向对象中一般指向的是对象本身,在js中函数中也有this。this在指向函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是哪个调用它的对象。
example1
function a(){
var user = "追梦子";
console.log(this.user); //undefined
console.log(this); //Window
}
a();
//window.a(); //默认函数的this指向就是window对象。
注:在严格版中的默认的this不再是window,而是undefined。
example2
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
o.fn();
这里的this指向的是对象o,因为你调用的fn是通过o.fn()执行的。
example3
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
这里的可能会有指向a还是b的疑惑,”this的最终指向的是哪个调用它的对象“指的是直接调用他的对象,多个对象调用时this指向的是上一级对象。
example4
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
看了example3,可能会想:卧槽,不是指向上一级对象么?其实这里的o.b.fn并没有执行,只是单纯的把fn这个函数复制给了j这个引用,实际上调用j()的是window这个对象,即最后一个代码是window.j().
example5
//构造函数版this
function Fn(){
this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子
这里的var a = new Fn()是创建有一个对象(相当于复制了一份Fn到对象a里面),那么这里的this当然是指向了a。
example6
function fn()
{
this.user = '追梦子';
return {};
}
var a = new fn;
console.log(a.user); //undefined
function fn2()
{
this.user = '追梦子';
return function(){};
}
var b = new fn2;
console.log(b.user); //undefined
function fn3()
{
this.user = '追梦子';
return 1;
}
var c = new fn3;
console.log(c.user); //追梦子
如果函数返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象,那么this还是指向函数的实例。构造函数默认返回的就是this 实例化的对象使用this就可以找到自己的属性和方法 通常构造函数return是可以省略的
example7
//修改函数this指针的三个方法
window.a = 1;
window.b = 2;
document.a = 10;
document.b = 20;
function fn(param){
console.log(this.a,this.b,param);
}
fn("默认");//1 2 "默认"
fn.call(document,"call");//10 20 "call"
fn.apply(document,"apply");//10 20 "apply"
fn.bind(document,"bind");//10 20 "bind"
call和bind的参数是一个个传入的,而apply是一次性传入一个数组,bind返回的是一个引用,需要加上()来指向函数。这三个方法都可以来改变函数的默认指针this。
var与变量提升
var用来声明变量。还有个和lvar作用差不多的let,不过let是严格模式中的,可以想成正常其他语言声明变量,不像var表现的不符合正常人的逻辑。
下面部分内容参考:https://www.cnblogs.com/52fhy/p/5117267.html
一般情况下,是可以省略var的,但有两点值得注意:
1、var a=1
与 a=1
,这两条语句一般情况下作用是一样的。但是前者不能用delete
删除。不过,绝大多数情况下,这种差异是可以忽略的。
2、在函数内部,如果没有用var
进行申明,则创建的变量是全局变量,而不是局部变量了。
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。
注:全局变量我感觉就是window对象下的一个变量。
example8
var a = 1;
b = 2;
delete a;
delete b;
console.log(a);//1
console.log(b);//报错
var c = 3;
var f = function fn(){
c = 4;
d = 5;
}
console.log(c);//4
console.log(d);//5
console.log(f.d);//undefined
作用域
js中只有全局作用域和函数作用域。控制语句(for,while,if…)并不会生成作用域。
example9
for(var i = 0;i < 4;i++);
console.log(i);//4
解析与执行过程
部分内容参考自https://www.cnblogs.com/foodoir/p/5977950.html
JavaScript引擎的工作方式是,先解析代码,获取所有被var声明的变量
和声明方式声明的函数
,然后再一行一行地运行。这可以解释很多js中让人费解的代码。
example10
alert(num);
var num = 10;
alert(num);
解析:
num:undefined
执行:
结果为:
undefined
10
example11
f1();
f2();
a = 3;
function f1(){//声明的方式声明的函数
console.log("f1");
}
var f2 = function(){//函数表达式
console.lgo("f2");
}
解析:
f1:函数的引用
f2:undefined
没有a
执行:
执行结果:
f1
报错:f2 is not defined
解析的时候出现相同的名字会怎么样呢?
example12
var a = 1;
var a = 2;
console.log(a);//2
example13
console.log(a);//ƒ a(){}
var a = 1;
function a(){
}
console.log(a);//1 这里容易误解,想想解析执行过程,其实这里的a最后执行了a=1,所以结果不是函数。
example14
console.log(fn);//f fn(){console.log("second")}
function fn(){
console.log("first");
}
function fn(){
console.log("second");
}
example12,example13,example14现象的原因:处理函数声明有冲突时,会覆盖;处理变量声明有冲突时,会忽略;函数声明和变量声明冲突,函数声明会覆盖变量声明。
example15
function f(a,b){
alert(a);
alert(b);
var b = 100;
function a(){}
}
f(1,2);
解析:
f:函数的引用
执行:
执行f(1,2)
解析:
b:undefined
a:指向函数引用
arguments:2
执行:
弹出:f a(){}
弹出:undefined
函数中的解析和执行过程的区别不是很大,在执行到函数的时候需要再解析下函数内容。 但是函数中有个arguments我们需要注意一下。