淺談JS的__proto__和prototype,引伸call

天馬行空的Max發表於2018-05-21
__proto__、prototype傻傻分不清楚? 記住以下兩點:
1.__proto__是每個物件都有的一個屬性,而prototype是函式才會有的屬性。
2.__proto__指向的是當前物件的原型物件,而prototype指向的,是以當前函式作為建構函式構造出來的物件的原型物件

(寫在最前面,轉自知乎@劉狗蛋)


var Person=function(){
this.age=1;
}
Person.prototype.name=”wwx”;
現在來例項化一個Person
1、var b={};

2、b.__proto__=Person.prototype;   
console.log(b)
console.log(b.name)

console.log(b.__proto__.name)  
那麼__proto__是什麼?我們在這裡簡單地說下。每個物件都會在其內部初始化一個屬性,就是__proto__,當我們訪問一個物件的屬性 時,如果這個物件內部不存在這個屬性,那麼他就會去__proto__裡找這個屬性,這個__proto__又會有自己的__proto__,於是就這樣 一直找下去,也就是我們平時所說的原型鏈的概念。

 

3、此時我們還需要讓b這個物件有age屬性,這時候我們可以b.age=1; OK加上了
Oh,No!讓我們來想一些東西 如果Person 有100個屬性呢,我們就要100個b.xxx=YYY. 太複雜了,真的不能忍!
Person.call(b)  搞定!此時應該有疑問,為什麼一個call就可以搞定呢?其內部究竟是怎麼實現的?

以上其實也就是相當於 var b = new Person();

這個new究竟做了什麼?我們可以把new的過程拆分成以下三步:其實也就是我們上面那三步

  1. var b={}; 也就是說,初始化一個物件b。

  2. b.__proto__=Person.prototype;

  3. Person.call(b);也就是說構造b,也可以稱之為初始化b。

思考:call 並不能call出來Person.prototype驗證:
var Boy=function (){ 
this.sex=”man”;
}
Boy.prototype.hair=”black”;
var c={};
Boy.call(c)
console.log(c.hair) //undefined

call()的官方解釋,“呼叫一個物件的一個方法,以另一個物件替換當前物件。”
Person.call(b);  等等Person 好像不符合 “一個物件的一個方法”,其實非也,你可以列印一下 windown.Person  

練習:

var Person = function () { }; 
 Person.prototype.Say = function () { 
        alert(“Person say”); 
 } 
 Person.prototype.Salary = 50000; 
  var Programmer = function () { }; 
 Programmer.prototype = new Person(); 
 Programmer.prototype.WriteCode = function () {
         alert(“programmer writes code”); 
 };
 Programmer.prototype.Salary = 500; 
  var p = new Programmer();
 p.Say();
 p.WriteCode(); 
 alert(p.Salary);

附上一段官方翻譯:

Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties. Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property.
When a constructor creates an object, that object implicitly references the constructor’s prototype property for the purpose of resolving property references. The constructor’s prototype property can be referenced by the program expression constructor.prototype, and properties added to an object’s prototype are shared, through inheritance, by all objects sharing the prototype. Alternatively, a new object may be created with an explicitly specified prototype by using the Object.create built-in function. –ECMAScript® 2015 Language Specification

每個建構函式都有一個名為“prototype”的屬性,用於實現基於原型的繼承和共享屬性。 由建構函式建立的每個物件都有一個隱式引用(稱為物件的原型),以指向其建構函式的“prototype”屬性的值。
當建構函式建立一個物件時,為了解析屬性引用,該物件隱式引用建構函式的prototype屬性。 建構函式的prototype屬性可以通過程式表示式constructor.prototype來引用,並且新增到物件原型的屬性通過繼承共享原型的所有物件來共享。 或者,可以使用Object.create內建函式通過顯式指定的原型建立新物件。 -ECMAScript®2015語言規範

部分引用連結:https://www.jianshu.com/p/f542286f015a

相關文章