1.
function Foo(){
getName = function(){
console.log(1);
};
return this;
}
Foo.getName = function(){
console.log(2);
}
Foo.prototype.getName = function(){
console.log(3);
}
var getName = function(){
console.log(4);
}
function getName(){
console.log(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName()//2
new Foo().getName();//3
逐行分析:
-
Foo.getName() 直接调用定义在Foo()外部的静态方法,输出2。
-
function getName()这种定义方式会导致变量提升 提前声明后会被var getName = function()这种方式覆盖,输出4。
-
运行Foo().getName()会覆盖掉之前的getName(),输出1。
首先要知道Foo()中的getName前没有var,所以该getName()为全局变量。
因此: 此时的Foo()内部的this指向window,而this.getName也就是输出1的这个getName,再return this使得window下的getName变成这个输出1的getName。 -
由于第三步已经将window中的getName覆盖成了Foo()中的getName,因此继续输出1。
-
new Foo.getName()相当于new (Foo.getName()),先输出2,再创建Foo.getName()这个方法的实例。
-
new Foo().getName()相当于(new Foo()).getName(),先创建了一个Foo()的实例,实例中找不到对应方法(因为Foo()中是getName()而非this.getName())则到原型上去找,输出3。
2.
window.name = 'Bytedance';
function A(){
this.name = 123;
}
A.prototype.getA = function(){
return this.name+1;
}
let a = new A();
let fnA = a.getA;
console.log(fnA());//Bytedance1
console.log(a.getA());//124
首先要记住的一个点:this永远指向最后调用它的那个对象。
那么
fnA = a.getA , fnA()
a.getA()
到底有什么区别呢?
a.getA的作用:从a里面找到getA这个方法。
a.getA()的作用:从a里面找到getA这个方法,并把a作为getA()的this,然后执行这个方法。
因此,fnA = a.getA , fnA()这种分开定义和执行两个步骤的写法会导致失去了指定this这个步骤。
因此题目中let fnA = a.getA 只是找到了return this.name+1这个方法,接下来调用时的this指向window,因此输出ByteDance1。
而a.getA()将this指向了A(),因此输出124。
3.
window.name = 'Bytedance'
class A {
constructor(){
this.name = 123;
}
getA(){
console.log(this);
return this.name+1;
}
}
let a = new A();
let fnA = a.getA;
console.log(fnA());
//undefined
//报错Cannot read properties of undefined (reading 'name')
在class A中,类内部的方法为严格模式,使得this的指向为undefined,因此在undefined上找name属性自然会报错
window.name = 'Bytedance'
var B = function(){
this.name = 123;
}
B.prototype.getB = function(){
console.log(this);
return this.name+1;
}
let b = new B();
let fnB = b.getB;
console.log(fnB());
//Window{...}
//Bytedance1
在构造函数B中,同第二题中的例子,先let fnB = b.getB再执行fnB()使得函数的this指向window,因此输出Window和Bytedance1。
4.
<script>
function exeuctor(handler) {
handler()
}
const obj = {
count: 0,
inc: function () {
console.log(this) // window
this.count++
}
}
exeuctor(obj.inc)
console.log(obj.count) //0
</script>
如果直接执行obj.inc()那么是可以正确让this指向obj从而输出1的,但是现在在外面又套了一层函数,因此this就指向window了。
要想让this正确指向此处需要用bind(不能用call和apply,因为bind才能实现不让函数立即执行,而是被调用了才执行)
exeuctor(obj.inc.bind(obj))
5.
var a = 1;
function printA(){
console.log(this.a);
}
var obj = {
a: 2,
foo: printA,
bar: function() {
printA();
}
};
obj.foo(); // 2
obj.bar(); // 1
var foo = obj.foo;
foo(); // 1
6.
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var obj2 = {};
obj1.foo(2);
console.log(obj1.a); // 2
obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3
var bar = new obj1.foo(4);
console.log(obj1.a); // 2
console.log(bar.a); // 4
谨记new绑定 > 显式绑定(call/apply/bind)> 隐式绑定(对象调用)>默认绑定(直接调用函数 指向window)
7.
(function(){
var x = y = 1;
})();
var z;
console.log(y); // 1
console.log(z); // undefined
console.log(x); // Uncaught ReferenceError: x is not defined
这里的关键点是理解"var x = y = 1"这句代码是从右往左执行的,也就相当于先在全局作用域中声明了y = 1,然后再在局部作用域中声明了var x = y。
8.
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = { demo: 5 };
this.show = function() {
console.log(this.a, this.b, this.c.demo);
};
}
function Child() {
this.a = 2;
this.change = function() {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
};
}
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
parent.show(); // 1 [1, 2, 1] 5
child1.show(); // 11 [1, 2, 1] 5
child2.show(); // 12 [1, 2, 1] 5
child1.change();
child2.change();
parent.show(); // 1 [1, 2, 1] 5
child1.show(); // 5 [1, 2, 1, 11, 12] 5
child2.show(); // 6 [1, 2, 1, 11, 12] 5
- 第一个parent.show(),直接输出,没啥要解释的。
- child1.a重写成了11,因此把this.a改成11,但是this.b中的this.a初始化时就已经确定,所以不变。
- 同上,只是this.a改成了12。
- child1和child2的change影响不到parent,因此还是输出一样的内容。
- 重点两行来了,关键点在于记得this.b和this.c都是引用类型,内容在所有实例之间共享,先看child1.show():
5.1 为什么被push进b的是11不是2?因为2是在new的时候被赋值的,之后被重写成11了,因此首先this.b变成[1, 2, 1, 11]
5.2 this.a变成this.b.length = 4
5.3 this.c.demo = this.a++,那么demo也变成4,而a++之后,this.a变成5
5.4 因此只看child1.change()的话,此时child1.show应该是5 [1, 2, 1, 11] 4 - 再考虑上child2.change()
6.1 this.b把12也push进去,因此最终this.b就是[1, 2, 1, 11, 12]
6.2 this.a变成this.b.length = 5
6.3 this.c.demo = this.a++,那么demo也变成5,而a++之后,this.a变成6
那么最终就得到了注释中的结果。