原型定義:
- 原型是function對象的一個屬性,它定義了構造函數製造出的對象的公共祖先。通過該構造函數產生的對象,可以繼承原型的屬性和方法。原型也是對象。
- 利用原型特點和概念,可以提取共有屬性。
- 對象如何查看原型 ——> 隱式屬性 __proto__
- 對象如何查看對象的構造函數 —— > 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,(其實就是把一個一個的參數封裝成數組傳過去)