這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

1. 代碼輸出結果
function Person(name) {
this.name = name
}
var p2 = new Person('king');
console.log(p2.__proto__) //Person.prototype
console.log(p2.__proto__.__proto__) //Object.prototype
console.log(p2.__proto__.__proto__.__proto__) // null
console.log(p2.__proto__.__proto__.__proto__.__proto__)//null后面沒有了,報錯
console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null后面沒有了,報錯
console.log(p2.constructor)//Person
console.log(p2.prototype)//undefined p2是實體,沒有prototype屬性
console.log(Person.constructor)//Function 一個空函式
console.log(Person.prototype)//列印出Person.prototype這個物件里所有的方法和屬性
console.log(Person.prototype.constructor)//Person
console.log(Person.prototype.__proto__)// Object.prototype
console.log(Person.__proto__) //Function.prototype
console.log(Function.prototype.__proto__)//Object.prototype
console.log(Function.__proto__)//Function.prototype
console.log(Object.__proto__)//Function.prototype
console.log(Object.prototype.__proto__)//null
這道義題目考察原型、原型鏈的基礎,記住就可以了,
2. 代碼輸出結果
// a
function Foo () {
getName = function () {
console.log(1);
}
return this;
}
// b
Foo.getName = function () {
console.log(2);
}
// c
Foo.prototype.getName = function () {
console.log(3);
}
// d
var getName = function () {
console.log(4);
}
// e
function getName () {
console.log(5);
}
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3
輸出結果:2 4 1 1 2 3 3
決議:
- Foo.getName(),Foo為一個函式物件,物件都可以有屬性,b 處定義Foo的getName屬性為函式,輸出2;
- getName(),這里看d、e處,d為函式運算式,e為函式宣告,兩者區別在于變數提升,函式宣告的 5 會被后邊函式運算式的 4 覆寫;
- Foo().getName(),這里要看a處,在Foo內部將全域的getName重新賦值為 console.log(1) 的函式,執行Foo()回傳 this,這個this指向window,Foo().getName() 即為window.getName(),輸出 1;
- getName(),上面3中,全域的getName已經被重新賦值,所以這里依然輸出 1;
- new Foo.getName(),這里等價于 new (Foo.getName()),先執行 Foo.getName(),輸出 2,然后new一個實體;
- new Foo().getName(),這里等價于 (new Foo()).getName(), 先new一個Foo的實體,再執行這個實體的getName方法,但是這個實體本身沒有這個方法,所以去原型鏈__protot__上邊找,實體.__protot__ === Foo.prototype,所以輸出 3;
- new new Foo().getName(),這里等價于new (new Foo().getName()),如上述6,先輸出 3,然后new 一個 new Foo().getName() 的實體,
3. 代碼輸出結果
var F = function() {};
Object.prototype.a = function() {
console.log('a');
};
Function.prototype.b = function() {
console.log('b');
}
var f = new F();
f.a();
f.b();
F.a();
F.b()
輸出結果:
a Uncaught TypeError: f.b is not a function a b
決議:
- f 并不是 Function 的實體,因為它本來就不是建構式,呼叫的是 Function 原型鏈上的相關屬性和方法,只能訪問到 Object 原型鏈,所以 f.a() 輸出 a ,而 f.b() 就報錯了,
- F 是個建構式,而 F 是建構式 Function 的一個實體,因為 F instanceof Object === true,F instanceof Function === true,由此可以得出結論:F 是 Object 和 Function 兩個的實體,即 F 能訪問到 a, 也能訪問到 b,所以 F.a() 輸出 a ,F.b() 輸出 b,
4. 代碼輸出結果
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() 這個是呼叫 Foo 函式的靜態方法 a,雖然 Foo 中有優先級更高的屬性方法 a,但 Foo 此時沒有被呼叫,所以此時輸出 Foo 的靜態方法 a 的結果:4
- let obj = new Foo(); 使用了 new 方法呼叫了函式,回傳了函式實體物件,此時 Foo 函式內部的屬性方法初始化,原型鏈建立,
- obj.a() ; 呼叫 obj 實體上的方法 a,該實體上目前有兩個 a 方法:一個是內部屬性方法,另一個是原型上的方法,當這兩者都存在時,首先查找 ownProperty ,如果沒有才去原型鏈上找,所以呼叫實體上的 a 輸出:2
- Foo.a() ; 根據第2步可知 Foo 函式內部的屬性方法已初始化,覆寫了同名的靜態方法,所以輸出:1
5. 代碼輸出結果
function Dog() {
this.name = 'puppy'
}
Dog.prototype.bark = () => {
console.log('woof!woof!')
}
const dog = new Dog()
console.log(Dog.prototype.constructor === Dog && dog.constructor === Dog && dog instanceof Dog)
輸出結果:true
決議:
因為constructor是prototype上的屬性,所以dog.constructor實際上就是指向Dog.prototype.constructor;constructor屬性指向建構式,instanceof而實際檢測的是型別是否在實體的原型鏈上,
constructor是prototype上的屬性,這一點很容易被忽略掉,constructor和instanceof 的作用是不同的,感性地來說,constructor的限制比較嚴格,它只能嚴格對比物件的建構式是不是指定的值;而instanceof比較松散,只要檢測的型別在原型鏈上,就會回傳true,
6. 代碼輸出結果
var A = {n: 4399};
var B = function(){this.n = 9999};
var C = function(){var n = 8888};
B.prototype = A;
C.prototype = A;
var b = new B();
var c = new C();
A.n++
console.log(b.n);
console.log(c.n);
輸出結果:9999 4400
決議:
- console.log(b.n),在查找b.n是首先查找 b 物件自身有沒有 n 屬性,如果沒有會去原型(prototype)上查找,當執行var b = new B()時,函式內部this.n=9999(此時this指向 b) 回傳b物件,b物件有自身的n屬性,所以回傳 9999,
- console.log(c.n),同理,當執行var c = new C()時,c物件沒有自身的n屬性,向上查找,找到原型 (prototype)上的 n 屬性,因為 A.n++(此時物件A中的n為4400), 所以回傳4400,
7. 代碼輸出問題
function A(){
}
function B(a){
this.a = a;
}
function C(a){
if(a){
this.a = a;
}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);
輸出結果:1 undefined 2
決議:
- console.log(new A().a),new A()為建構式創建的物件,本身沒有a屬性,所以向它的原型去找,發現原型的a屬性的屬性值為1,故該輸出值為1;
- console.log(new B().a),ew B()為建構式創建的物件,該建構式有引數a,但該物件沒有傳參,故該輸出值為undefined;
- console.log(new C(2).a),new C()為建構式創建的物件,該建構式有引數a,且傳的實參為2,執行函式內部,發現if為真,執行this.a = 2,故屬性a的值為2,
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();
child1.show();
child2.show();
child1.change();
child2.change();
parent.show();
child1.show();
child2.show();
輸出結果:
parent.show(); // 1 [1,2,1] 5 child1.show(); // 11 [1,2,1] 5 child2.show(); // 12 [1,2,1] 5 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
這道題目值得神帝,他涉及到的知識點很多,例如this的指向、原型、原型鏈、類的繼承、資料型別等,
決議:
- parent.show(),可以直接獲得所需的值,沒啥好說的;
- child1.show(),
Child的建構式原本是指向Child的,題目顯式將Child類的原型物件指向了Parent類的一個實體,需要注意Child.prototype指向的是Parent的實體parent,而不是指向Parent這個類, - child2.show(),這個也沒啥好說的;
- parent.show(),
parent是一個Parent類的實體,Child.prorotype指向的是Parent類的另一個實體,兩者在堆記憶體中互不影響,所以上述操作不影響parent實體,所以輸出結果不變; - child1.show(),
child1執行了change()方法后,發生了怎樣的變化呢?
- this.b.push(this.a),由于this的動態指向特性,this.b會指向
Child.prototype上的b陣列,this.a會指向child1的a屬性,所以Child.prototype.b變成了[1,2,1,11]; - this.a = this.b.length,這條陳述句中
this.a和this.b的指向與上一句一致,故結果為child1.a變為4; - this.c.demo = this.a++,由于
child1自身屬性并沒有c這個屬性,所以此處的this.c會指向Child.prototype.c,this.a值為4,為原始型別,故賦值操作時會直接賦值,Child.prototype.c.demo的結果為4,而this.a隨后自增為5(4 + 1 = 5),
child2執行了change()方法, 而child2和child1均是Child類的實體,所以他們的原型鏈指向同一個原型物件Child.prototype,也就是同一個parent實體,所以child2.change()中所有影響到原型物件的陳述句都會影響child1的最終輸出結果,
- this.b.push(this.a),由于this的動態指向特性,this.b會指向
Child.prototype上的b陣列,this.a會指向child2的a屬性,所以Child.prototype.b變成了[1,2,1,11,12]; - this.a = this.b.length,這條陳述句中
this.a和this.b的指向與上一句一致,故結果為child2.a變為5; - this.c.demo = this.a++,由于
child2自身屬性并沒有c這個屬性,所以此處的this.c會指向Child.prototype.c,故執行結果為Child.prototype.c.demo的值變為child2.a的值5,而child2.a最終自增為6(5 + 1 = 6),
9. 代碼輸出結果
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = https://www.cnblogs.com/smileZAZ/p/function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue());
輸出結果:true
實際上,這段代碼就是在實作原型鏈繼承,SubType繼承了SuperType,本質是重寫了SubType的原型物件,代之以一個新型別的實體,SubType的原型被重寫了,所以instance.constructor指向的是SuperType,具體如下:

如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/498890.html
標籤:JavaScript
上一篇:資料型別
