第 100 题:请写出如下代码的打印结果
yygmind opened this issue · 36 comments
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();结果如下
4
2
1
输出顺序是 4 2 1 .
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
// 以上只是 Foo 的构建方法,没有产生实例,此刻也没有执行
Foo.prototype.a = function() {
console.log(3)
}
// 现在在 Foo 上挂载了原型方法 a ,方法输出值为 3
Foo.a = function() {
console.log(4)
}
// 现在在 Foo 上挂载了直接方法 a ,输出值为 4
Foo.a();
// 立刻执行了 Foo 上的 a 方法,也就是刚刚定义的,所以
// # 输出 4
let obj = new Foo();
/* 这里调用了 Foo 的构建方法。Foo 的构建方法主要做了两件事:
1. 将全局的 Foo 上的直接方法 a 替换为一个输出 1 的方法。
2. 在新对象上挂载直接方法 a ,输出值为 2。
*/
obj.a();
// 因为有直接方法 a ,不需要去访问原型链,所以使用的是构建方法里所定义的 this.a,
// # 输出 2
Foo.a();
// 构建方法里已经替换了全局 Foo 上的 a 方法,所以
// # 输出 14 2 1
4 2 1
4
2
1
421
- 考察的应该是原型和函数的理解
4 2 1
4 2 1
输出顺序:4,2,1
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();答案:
4、2、1 Foo.a() 第一个为4没有什么异议
new 的时候会将函数的主函数执行一遍,并将原型挂载至新的函数上,此时obj有本身来自Foo的this.a,也有原型上的prototype.a,查找obj.a时,在函数本域上有this.a,则直接输出来自于Foo的this.a,也就是console.log(2)。接下来的Foo.a,这时候Foo函数内部由于同样有Foo.a = function ...,new的时候Foo.a的值相当于被重置了,则输出1。
4,2,1
4,2,1
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
// 实例方法
Foo.prototype.a = function() {
console.log(3)
}
// 静态方法
Foo.a = function() {
console.log(4)
}
Foo.a(); // 4 直接调Foo静态方法a
let obj = new Foo();
obj.a(); // 2 因是obj调用,故优先调用构造函数Foo自身的方法a,如果自身没有则执行原型链上的方法a
Foo.a(); // 1 因执行了一次new 操作,故再次调用Foo.a()时调用了Foo函数体内的静态方法afunction Foo() { // 构造函数Foo
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() { // 原型上也有个a属性
console.log(3)
}
Foo.a = function() { // 未new时,给函数对象添加a方法
console.log(4)
}
Foo.a(); // 很自然这里打印的是 4
let obj = new Foo(); // 实例化一个obj对象 ,执行了一次Foo函数
// 原型链
obj.__proto__ === Foo.prototype
Foo.prototype.__proto__ === Object.prototype
Object.prototype === null
obj.a(); // 2
Foo.a(); // 1
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a(); //4
let obj = new Foo(); //
obj.a(); //2
Foo.a(); //1
那些只说结果不去分析的,有啥意义。。
// 定义一个构造函数Foo
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
// 给构造函数Foo的原型对象上添加属性a
Foo.prototype.a = function() {
console.log(3)
}
// 函数也是对象,给Foo函数添加属性a
Foo.a = function() {
console.log(4)
}
// 访问Foo函数上的属性a执行 ,输出 4
Foo.a();
// 实例化出对象obj,在new的过程中,给Foo上的a重新赋值,实例化出的obj对象也有一个a
let obj = new Foo();
// 输出 2
obj.a();
// 输出1
Foo.a();
答案为:4, 2, 1
解析:
Foo.a()这个是调用 Foo 函数的静态方法 a,虽然 Foo 中有优先级更高的属性方法 a,但 Foo 此时没有被调用,所以此时输出 Foo 的静态方法 a 的结果:4let obj = new Foo();使用了 new 方法调用了函数,返回了函数实例对象,此时 Foo 函数内部的属性方法初始化,原型方法建立。obj.a();调用 obj 实例上的方法 a,该实例上目前有两个 a 方法:一个是内部属性方法,另一个是原型方法。当这两者重名时,前者的优先级更高,会覆盖后者,所以输出:2Foo.a();根据第2步可知 Foo 函数内部的属性方法已初始化,覆盖了同名的静态方法,所以输出:1
421
421
// 构造函数Foo
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
// 在构造函数Foo的原型上添加a方法
Foo.prototype.a = function() {
console.log(3)
}
// 在构造函数Foo上添加a方法
Foo.a = function() {
console.log(4)
}
// 直接调用Foo.a()方法
Foo.a();
// 实例化, 会执行构造函数
// 实例化所在事情:在Foo上添加a方法,在新建实例上添加a方法,在Foo的原型上添加a方法
let obj = new Foo();
//执行Foo的实例obj的方法a
obj.a();
// 执行Foo的方法a
Foo.a();function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a(); // 调用构造函数的自身的方法 ,所以结果是4
let obj = new Foo(); // new重新创建一个obj,使它指向Foo,拥有了构造函数的属性和方法
obj.a(); // 因为构造函数有直接方法,所以输出2
Foo.a(); // 构造函数重新全局a方法,所以结果结果是1,之前是4
// 结果是4、2、1// 构造函数Foo function Foo() { Foo.a = function() { console.log(1) } this.a = function() { console.log(2) } } // 在构造函数Foo的原型上添加a方法 Foo.prototype.a = function() { console.log(3) } // 在构造函数Foo上添加a方法 Foo.a = function() { console.log(4) } // 直接调用Foo.a()方法 Foo.a(); // 实例化, 会执行构造函数 // 实例化所在事情:在Foo上添加a方法,在新建实例上添加a方法,在Foo的原型上添加a方法 let obj = new Foo(); //执行Foo的实例obj的方法a obj.a(); // 执行Foo的方法a (Foo经过上一步实例化之后,重新绑定了a方法) Foo.a();
4
2
1
这个我会,来声个张,
421~
声明顺序:
Foo.a = function() { console.log(4) }
所以第一个为4,
接下来new了一下构造函数~
虽然把原型链挂到了新obj,
但是,构造函数重定义了Foo.a,且设定构造函数的娃的a为2。
2楼的解完美
补一句,
function Foo() { Foo.a = function() { console.log(1) } //this.a = function() {//干掉这里 让prototype上a,console出3可以生效的方法 //console.log(2) //} } Foo.prototype.a = function() { console.log(3) } Foo.a = function() { console.log(4) } Foo.a(); let obj = new Foo(); obj.a(); Foo.a();
`Foo.a(); // 4 全局的Foo.a
let obj = new Foo(); // 执行Foo的构造函数,将 最后的 Foo.a(全局)覆盖
obj.a(); // 2 this.a
Foo.a(); // 1 Foo构造函数里的 foo.a 因为全局的已经被覆盖
`
京东怎么总喜欢出这种乱七八糟的题
421
大家回答挺好的,考察的是原型链和实例的问题
function Foo() {
Foo.a = function() {
console.log(1);
};
this.a = function() {
console.log(2);
};
}
// 原型方法,在生成实例时使用
Foo.prototype.a = function() {
console.log(3);
};
// 静态方法,可以直接调用
Foo.a = function() {
console.log(4);
};
Foo.a(); // 实例没有生成,直接调用静态方法,输出4
let obj = new Foo();
obj.a(); // 实例中有a,不去原型链中查找,之前在Foo.prototype.a的函数也被覆盖,输出2
Foo.a(); // 生成实例后,Foo原型链中的静态方法被覆盖,输出1这道题很好的讲述了构造函数中,new做的事情:
(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个对象);所以,obj.a()输出2
(3)执行构造函数中的代码(为这个新对象添加属性); 所以Foo.a()输出1,因为被覆盖了
(4)返回新对象。
function Foo() { Foo.a = function() { console.log(1) } this.a = function() { console.log(2) } }
该步骤是函数声明,函数声明会被编译器优先进行提升,并且在全局(此题为全局)词法作用域中声明了叫Foo的标识符。
Foo.prototype.a = function() { console.log(3) }
在函数原型上添加了一个a函数
Foo.a = function() { console.log(4) }
在Foo上添加了一个a函数,js中万物皆函数,所以就相当于在Foo这个对象上添加了一个新的属性a,并赋值为一个函数。要注意的是,这并不会对Foo构造(new)出来的对象造成影响。
Foo.a() 执行了上面定义的函数 console.log(4)
let obj = new Foo();
new 相当于创建一个新对象,用Foo对其进行构造,题目中Foo中对obj有影响的只有this.a = ...
obj的__proto__也会指向其构造函数Foo的原型Foo.prototype
所以当obj中查找的属性不存在时,顺着__proto__到Foo.prototype中去找,还找不到就去Object.prototype中找。
同样Foo(),说明Foo被执行了一次。
在Foo中
”Foo.a = function() {
console.log(1)
}“
这段代码首先会在Foo的作用域中寻找是否存在Foo这个标识符,若存在,会将其属性a定义。若不存在,会查找父作用域中是否存在。所以Foo.其实改的是父作用域的Foo,因为函数内部不存在这个值的。
所以这段代码,在本题目中,其实写在哪都一样。
obj.a();
由于obj自身拥有a,所以会执行console.log(2)
Foo.a();
再此执行全局作用域中的Foo.a 因为Foo()执行了对Foo.a的修改,所以console.log(1)`
思路:
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a(); //由于Foo未初始化,所有不会执行构造函数中代码,所有调用的是外面的Foo.a,输出4
let obj = new Foo(); // 执行构造函数,`this.a`被执行
obj.a(); // 由于在Foo构造函数中存在`this.a`,所以此时不会向上查找原型链上的a函数,执行`this.a`中代码
Foo.a(); // 构造函数被执行,Foo.a被新的代码覆盖,此时Foo.a为构造函数内部的赋值,输出1结果:4,2,1
100题达成 前面又忘了(bushi)。。。
打印顺序 4 2 1
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
// 给Foo类的实例的原型增加名为a的属性,打印3
Foo.prototype.a = function() {
console.log(3)
}
// 给Foo对象增加一个名为a的属性,打印4
Foo.a = function() {
console.log(4)
}
// 调用Foo对象的a方法,输出4
Foo.a();
// 实例化Foo类为obj对象,此时Foo构造函数被调用
// Foo对象的a属性被替换为打印1的函数
// 实例方法a被赋值为一个打印2的函数
let obj = new Foo();
obj.a(); // 2
Foo.a(); //1function Foo() {
Foo.a = function() {
console.log(1)
} //静态方法
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
以上函数里面的方法,属性,原型链上的方法,属性只有实例对象才可以访问到
Foo.a = function() {
console.log(4)
}//静态方法
Foo.a(); //直接访问静态方法
let obj = new Foo(); //创建实例对象,这时候对象可以访问 原型链上的属性和方法,以及构造函数的属性和方法
obj.a(); //访问规则:先查好构造函数中是否有,没有在查看原型链中是否有
Foo.a(); //执行构造函数的时修改了静态方法
最总:4 2 1