原型 原型鏈 call / apply

原型定義:

  1. 原型是function對象的一個屬性,它定義了構造函數製造出的對象的公共祖先。通過該構造函數產生的對象,可以繼承原型的屬性和方法。原型也是對象。
  2. 利用原型特點和概念,可以提取共有屬性。
  3. 對象如何查看原型  ——> 隱式屬性 __proto__
  4. 對象如何查看對象的構造函數 —— > constructor

用下面的代碼來展現下什麼是原型

//Person.prototype        --    原型
//Person.prototype  = {}      是祖先
Person.prototype.LastName = "haha";
Person.prototype.say = function () {
    console.log('abcd');
}
function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
var person1 = new Person('xuming', 35, 'male');
var person2 = new Person();
//person1和person2都可以訪問祖先的LastName屬性

原型是怎麼來用的呢?

1-提取共有屬性

//當我們每次構造一個新的對象時,下面的這些共有屬性都要執行一遍,造成冗餘
function Car(color, owner) {
    this.owner = owner;
    this.carName = 'BMW';
    this.height = 1400;
    this.lang = 4900;
    this.color = color;
}

var car = new Car('red', 'prof.ji');

 

//修改上面的冗餘    提取公共屬性
Car.prototype.carName = 'BMW';
Car.prototype.lang = 4900;
Car.prototype.height = 1400;
function Car(color, owner) {
    this.owner = owner;
    this.color = color;
}

var car = new Car('red', 'prof.ji');


//或者用更簡單的方式
Car.prototype = {
    carName = 'BMW',
    lang = 4900,
    height = 1400
}
function Car(color, owner) {
    this.owner = owner;
    this.color = color;
}

var car = new Car('red', 'prof.ji');

2-constructor

//當我們構造這樣一個對象時,會自帶一個prototype屬性,prototype屬性裏有自帶兩個屬性,
//即
//prototype = {
//    constructor:系統產生的,默認指向自己
//    _proto_
//}
function Car() {
//    constructor:Car
}

var car = new Car();

3-隱式屬性 __proto__

//當我們定義一個對象{}的時候,裏面其實並不是空的
//系統已經有一個隱式的__proto__,它指向當前自己的  xxx.prototype
function Persin() {
    //var this = {
    //    __proto__:Person.prototype      
    //}
}

=====================================================================================

//問題1   person.name打印啥?
Person.prototype.name = 'sunny';
function Person() {
    //    __proto__:Person.prototype 
}
var person = new Person();
Person.prototype.name = 'cherry';
console.log(person.name)   //打印cherry

=====================================================================================

//問題2   person.name打印啥?
Person.prototype.name = 'sunny';
function Person() {
    //    __proto__:Person.prototype 
}
var person = new Person();
Person.prototype = {
    name : 'cherry'
}

console.log(person.name)   //打印sunny

========================================================================================
//原因:重點是這裏有一個隱式的間接過程

Person.prototype = {name : 'sunny'}
__proto__ = Person.prototype;
Person.prototype = {name: 'cherry'}

=====================================================================================

//問題3   person.name打印啥?
Person.prototype.name = 'sunny';
function Person() {
    //    __proto__:Person.prototype 
}

Person.prototype = {
    name : 'cherry'
}

var person = new Person();
console.log(person.name)   //打印cherry

 

原型鏈

原型鏈的最頂端是Object,它就沒有__proto__屬性了。它的孩子都有。

Grand.prototype.lastName = "Deng";
function Grand () {

}

var grand = new Grand();

Father.prototype = grand;
function Father() {
    this.name = 'xuming'
}
var father = new Father();

Son.prototype = father;
function Son() {
    this.hobbit= 'smoke'
}
var son = new Son();

原型鏈增刪改查

絕大多數對象的最終都會繼承自Object.prototype

Object.create(原型);()裏可以填兩種值:原型和null

Object.create(null)創建數出來的對象是沒有繼承自Object.prototype的,但是Object.create(原型)創建出來的對象是有繼承的

 

call / apply改變this指向(借用別人的函數實現自己的功能)

call()   //系統默認第一個參數用以改變this指向,第二個參數開始和形參一一對應

function Person(name,age) {
    this.name = name;
    this.age = age;
}

var person = new Person('deng', 100);

var obj = {}

Person.call();     //此時相當於Person()

//但是call可以傳參一個對象,如下
Person.call(obj); //此時Person裏的this改變了指向,指向obj,而不是person

//call()   //系統默認第一個參數用以改變this指向,第二個參數纔開始和形參一一對應

apply和call幾乎一模一樣,唯一不同的是:

call     可以傳無限個參數,需要把實參按照形參的個數一個一個傳進去

apply  只能傳兩個參數,一個改變this指向,一個封裝好參數列表的數組arguments,(其實就是把一個一個的參數封裝成數組傳過去)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章