关于原型链

Posted by Xiaosa's Blog on October 13, 2020
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Foo (params) {
    return {}
}

console.log(Foo.prototype.constructor === Foo); // true

let a = new Foo()

a.constructor === Foo  // true 

//但其实只是个副作用   .constructor 委托给了Foo.prototype
// eg:)
Foo.prototype = {}

a.constructor === Foo // false

a.constructor === Object // true


  1. prototype与__proto__
  2. function与object
  3. new到底发生了什么

prototype(函数属性)与__proto__(对象原型)

首先说下在JS中比较容易让人困惑的prototype和__proto__ __proto__就是JavaScript中所谓的原型.

1
  一个对象的__proto__ 属性和自己的内部属性[[Prototype]]指向一个相同的值 (通常称这个值为原型),原型的值可以是一个对象值也可以是null(比如说Object.prototype.__proto__的值就是null).该属性可能会引发一些错误,因为用户可能会不知道该属性的特殊性,而给它赋值,从而改变了这个对象的原型. 如果需要访问一个对象的原型,应该使用方法Object.getPrototypeOf.

firefox、chrome等浏览器把对象内部属性[[Prototype]]用__proto__的形式暴露了出来.(老版本的IE并不支持__proto__,IE11中已经加上了__proto__属性)

prototype是function中特有的.proto 是原型,prototype是函数默认的一个属性,它指向一个对象(// todo 什么对象?),这个对象的constructor属性指向函数本身.

constructor属性 比较随意 不可枚举但是可写 js里面它可以随便赋值

function与object

function A(name){
	this.name = name;
	this.getName = function(){
		console.log(this.name);
	}

	var b = 'test';
	console.log(b);
}

var a = new A('testa');
A('TESTA');

当执行var a = new A(‘testa’);得到的a是这样的:

1
2
3
4
a:{
  getName:function()
  name:'testa'
}

当执行A(’TESTA’),相当于执行

1
2
window.name = 'TESTA'(由于非strict模式下,this默认指向window)
window.getName = function(){console.log(this.name);}

我们的函数A既可以直接执行,又可以new一下返回一个对象.function和object到底是什么关系,new的时候发生了什么?


new到底发生了什么

还是我们上面的问题,当我们执行 let a = new A(‘testa’)到底发生了什么.MDN上是这么说的 对于 let o = new Foo();

1
2
3
4
//JavaScript 实际上执行的是:
var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);

这样大概就明白了,当我们执行new A(‘testa’)的时候 JS会这样做

1
2
3
4
     1. var o = new Object();
     2. o.__proto__ = A.prototype;//这里还记得之那个function里面的默认的属性么?
     3. A.call(o)//由于这里this是指向o,可以把什么this.name/getName绑定到o上.
     4. 把这个o返回给a;//完成var a = new A()的过程.

这里注意下,上面所谓的第4步其实是一个简化的说法.真正的过程是在第3步之后,如果发现A返回是一个Object类型(非primitive类型,即非string,boolean,number,null,undefined类型就是Object类型),则直接返回A的返回值,否则把第1步new的Object返回出去.(默认情况下,JS中函数默认返回值是undefined) 举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
function A(name){
	this.name = name;
	this.getName = function(){
		console.log(this.name);
	}

	var b = 'test';
	console.log(b);

	return {};
}

var a = new A('testa');//{}

stackoverflow上一个人的回答来总结下就是:

1
2
3
In JavaScript, most functions are both callable and instantiable: they have both a [[Call]] and [[Construct]] internal methods.

在JS中,绝大多数的函数都是既可以调用也可以实例化的(箭头函数除外).我们既可以直接执行函数得到函数的返回值.也可以通过new操作符得到一个对象.