一个关于JavaScript中作用域链的问题,prototype 和 __proto__ 的区别?
请看代码
代码一
<script type="text/javascript">
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.__proto__ = animal;
var tidy = new dog();
console.log(dog.price) //2000
console.log(tidy.price) // undefined
</script>
代码二
<script type="">
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.prototype = animal;
var tidy = new dog();
console.log(dog.price) //undefined
console.log(tidy.price) // 2000
</script>
为什么结果是相反的?
JavaScript中基于原型链的继承是怎么样的?
JavaScript javascript面向对象 prototype
Answers
__proto__
是实例(如 tidy)访问原型对象,同时它是非标准的,ES5 标准方法是
Object.getPrototypeOf()
prototype
是构造函数(如 Dog) 访问原型对象
可以这样验证
function Dog() {}
var tidy = new Dog();
// 它们引用的是同一个内存地址,即它们的原型。
tidy.__proto__ === Dog.prototype
但是到这里并没有体现基于原型链的继承
function Dog() {}
function Animal() {}
// 实现原型链继承
Dog.prototype.__proto__ = Animal.prototype;
var tidy = new Dog();
// tidy 的原型指向 Dog.prototype
tidy.__proto__ === Dog.prototype
// 因为 Dog.prototype.__proto__ === Animal.prototype
// tidy 的原型的原型(形成原型链)指向 Animal.prototype
tidy.__proto__.__proto__ === Animal.prototype
// 原型链的终端是 Object.prototype
tidy.__proto__.__proto__.__proto__ === Object.prototype
// 再往前就是 null 了
tidy.__proto__.__proto__.__proto__.__proto__ === null
根据上面大神的解释,我总结了一下,作用域链的指向如下
以下代码可以直接运行,大家可以试一下
代码一
<script type="text/javascript">
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.__proto__ = animal;
var tidy = new dog();
console.log(dog.__proto__ === animal) //true
console.log(dog.__proto__.__proto__ === animal.__proto__) //true
console.log(dog.__proto__.__proto__.__proto__ === Object.prototype) //true
console.log(dog.__proto__.__proto__.__proto__.__proto__ === null) //true
console.log(tidy.__proto__ === dog.prototype) //true
console.log(tidy.__proto__.__proto__ === dog.prototype.__proto__) //true
console.log(tidy.__proto__.__proto__ === Object.prototype) //true
console.log(tidy.__proto__.__proto__.__proto__ === null) //true
console.log(dog.price) //2000
console.log(tidy.price) // undefined
</script>
代码二
<script type="text/javascript">
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.prototype = animal;
var tidy = new dog();
console.log(tidy.__proto__ === dog.prototype) //true
console.log(tidy.__proto__.__proto__ === animal.__proto__) //true
console.log(tidy.__proto__.__proto__.__proto__ === Object.prototype) //true
console.log(tidy.__proto__.__proto__.__proto__.__proto__ === null) //true
console.log(dog.__proto__ === Function.prototype) //true
console.log(dog.__proto__.__proto__ === Object.prototype) //true
console.log(dog.__proto__.__proto__.__proto__ === null) //true
console.log(dog.price) //undefined
console.log(tidy.price) // 2000
</script>
又有人问这个问题了,
__proto__
本质上其实是标准里规定的
[[prototype]]
属性,原本是不可用 js 访问的,后来(据说标准里又规定可以)firefox 和 chrome 中把这个属性命名为
__proto__
。后来
ES
又添加了函数
getPrototypeof
,这样就可以通过这个函数来访问这个属性,所以这个
__proto__
现在不是标准的一部分。
然后,再说
new
的创建过程,当执行
new func()
的时候,执行过程如下:
1、首先创建一个新的对象,比如叫
obj
;
2、
obj.[[prototype]] = func.prototype
;
3、令
this=obj
,执行函数
func
;
4、如果
func
的返回值是一个对象,则
new
的返回值就是这个对象,否则返回值是
obj
当 __读取__(注意是读取)对象的属性的时候,返回值是:
if(obj.prop)
return obj.prop
else if(obj.[[prototype]].prop)
return obj.[[prototype]].prop;
else if(obj.[[prototype]].[[prototype]].prop)
return obj.[[prototype]].[[prototype]].prop;
//......一直这样找下去
else { return undefined;}
如下图:
var Fish = new Function(){}
//等价于
var Fish = function(){}
prototype
是作用在构造方法上的,它会影响由此构造方法所创建的所有对象的原型,但它不会影响构造方法本身(构造方法本身是一个function对象)的原型。
__proto__
是一个非标准属性,用来表示该对象当前的原型。
dog.prototype = animal;
var tidy = new dog();
这两句代码的结果是“
tidy
对象的原型是
animal
”,也就是:
tidy.__proto__ === dog.prototype === animal
但是
dog.prototype != dog.__proto__
。
不知道这么说能理解吗?