JS筆記(7): 原型和原型鏈

1、面向對象編程

  • 面向對象編程Object Oriented Programmimg:把具備相同特徵的事務抽象出一個類,把描述這個類的屬性和方法掛在這個類的原型(prototype)上,這種方式叫作面向對象編程
    • 構造函數模式 + 原型模式 = js面向對象模式
  • 對象:萬物皆對象 對象封裝了一些屬性和方法用來描述一個事物或者供咱們調用
  • 類:對象的具體細分(按照功能特色進行分類:大類、小類)
    • 內置類:Object / Array / Date / RegExp / Function
  • 實例:類中具體的一個事物(拿出類別中的具體一個實例進行研究,那麼當前類別下的其餘實例也具有這些特色和特徵)
    • new xxx()

2、原型{prototype):

  • 1.全部的函數數據類型都有一個prototype的屬性,它的屬性值是一個對象,瀏覽器會爲他開闢一個堆內存
  • 2.在瀏覽器給prototype開闢的堆內存中有一個自帶的屬性:constructor,這個屬性存儲的是當前函數自己
  • 3.全部的對象都有一個__proto__的屬性,這個屬性指向當前所屬類的prototype(若是不能肯定它是誰的實例,就是基類Object的實例)

3、原型鏈(__proto__):

  • 它是一種基於__proto__的向上查找機制。當咱們操做實例上的某個屬性或者方法的時候,首先會在本身空間中查找私有屬性或方法
  • 找到則查找結束,用私有屬性便可;若是沒查到,則基於__proto__找所屬類(即構造函數)的prototype,若是有則用此公有屬性,若是沒有,繼續基於原型上的__proto__向上查找,一直找到基類Object的prototype爲止
  • 若是Object.prototype上沒有此屬性,則此屬性或方法不存在
  • 只要是函數,無論是什麼類,永遠都是內置Function類的實例
  • 構造函數的原型下的方法只給它的實例化對象使用

原型鏈執行題:

題目一:
function Fn(name, age) {
    let n = '哈哈';
    this.name = name;
    this.age = age;
    this.AA = function(){
        console.log(1)
    }
};
Fn.prototype.m = function () {
    console.log(2);
};
Fn.prototype.AA = function(){
    console.log(3);
}
Object.prototype.m = function () {
    console.log(4);
};
Function.prototype.m = function(){
    console.log(5)
}
let f1 = new Fn('Tom','18');
let f2 = new Fn('Jerry','18');

// console.log(f1.n); //undefined
console.log(Fn.prototype.m()); //2 ud
console.log(new Fn().m()); //2
console.log(f1.m()); //2

console.log(f1.m() === Fn.prototype.m()); //true
console.log(typeof Fn.prototype); // 'object'
console.log(f1 === f2); // false
console.log(f1.__proto__.AA === f2.__proto__.AA); // true

console.log(f1.__proto__.AA === Fn.prototype.AA); // true 
console.log(f1.hasOwnProperty === Fn.prototype.hasOwnProperty); //true
f1.BB = '123'; // 給本身設置私有屬性 
f1.__proto__.CC = '456';// 給原型上設置公有屬性(每一個實例均可以用這個屬性)<=> Fn.prototype.name = '123'
console.log(f1.BB);//123
console.log(f1.CC);//456
複製代碼
題目二:
function Fn(){
    var n = 10;
    this.name = '珠峯';
    this.age = 12;
    console.log(this); //實例 {name:'珠峯',age:12}
};
Function.prototype.n = function(){
    console.log(123);
};
var fn = new Fn();
console.log(fn); // 實例 {name:'珠峯',age:12}
console.dir(Fn); // Fn函數自己
console.log(fn.n); // f(){console.log(123)}
console.log(Fn.n); // 123 undefined
console.log(Fn.n()); // 123 undefined
console.log(fn.name); //'珠峯'
console.log(fn.age); // '12'
console.log(fn.constructor); //Fn(){...}
console.log(fn.__proto__); //{constructor: ƒ}
console.log(Fn.prototype); //{constructor: ƒ}
console.log(fn instanceof Fn); //true
console.log(fn instanceof Object); //true
console.log(fn instanceof Function); //flase
console.log('n' in fn); //flase
console.log('n' in Fn); //true n在Fn的原型(Function.prototype.n)上 
console.log('name' in fn); //true
console.log('name' in Fn); //true Fn有一個自帶的屬性name
console.log('age' in Fn); //false
console.log('constructor' in Fn); //true
console.log('toString' in Fn); //true toString是在基類Object上的公有屬性
console.log(fn.hasOwnProperty('name')); //true
console.log(fn.hasOwnProperty('age'));//true
console.log(fn.hasOwnProperty('n')); //false
console.log(fn.hasOwnProperty('toString')); //false

function hasPubProperty(attr,obj){
    return (attr in obj) && (obj.hasOwnProperty(attr) === false)
};
console.log(hasPubProperty('toString',fn)); //true
複製代碼
題目三:
function Foo(name, age) {
    this.name = name;
    this.printName = function () {
        console.log('haha', this.name);
    }
}
Foo.prototype.alertName = function () {
    alert(this.name)
}
Foo.prototype.printName = function () {
    console.log('hihi', this.name);
}
var f = new Foo('zhangsan'); 
f.printName = function () {
    console.log('hehe', this.name);
}
f.printName(); // hehe,zhangsan
f.alertName(); // 彈出 zhangsan
複製代碼
題目四:
var fullname = 'John Doe';
var obj = {
    fullname: 'Colin Ihrig',
    prop: {
        fullname: 'Aurelio De Rosa',
        getFullname: function () {
            return this.fullname;
        }
    }
};
console.log(obj.prop.getFullname()); // Aurelio De Rosa
var test = obj.prop.getFullname;
console.log(test());//全局 John Doe
複製代碼
題目五:
function Person(name) {
    this.name = name;
}
Person.prototype.share = [];
Person.prototype.printName = function () {
    alert(this.name);
}
var person1 = new Person('Byron');
var person2 = new Person('Frank');
person1.share.push(1); // [1]
person2.share.push(2); // [1,2]
console.log(person2.share); // [1,2] 
複製代碼
題目六:
function foo() {
    this.add = function (x, y) {
        return x + y;
    }
}
foo.prototype.add = function (x, y) {
    return x + y + 10;
}
Object.prototype.minus = function (x, y) {
    return x - y;
}
var f = new foo();
console.log(f.add(1, 2));//3
console.log(f.minus(1, 2));//-1
複製代碼
題目七:
function A() {
}
function B(a) {
    this.a = a;
}
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a); // 1
console.log(new B().a); //undefined
console.log(new C(2).a); //2
複製代碼
題目八:
function Fn() {
    this.x = 100;
    this.y = 200;
    this.getX = function () {
        console.log(this.x); // 100
    }
}
Fn.prototype.getX = function () {
    console.log(this.x); // undefined
};
Fn.prototype.getY = function () {
    console.log(this.y); // 200 undeined
};
var f1 = new Fn;
var f2 = new Fn;
console.log(f1.getX === f2.getX); //false 分別開闢私有做用域 是各自的私有屬性
console.log(f1.getY === f2.getY); //true 是所屬類prototype上的公有屬性
console.log(f1.__proto__.getY === Fn.prototype.getY); //true
console.log(f1.__proto__.getX === f2.getX); // false 
console.log(f1.__proto__.getX === Fn.prototype.getX); //true
console.log(f1.constructor); //Fn(){...}
console.log(Fn.prototype.__proto__.constructor); // Object(){...}
f1.getX();
f1.__proto__.getX();
f2.getY();
Fn.prototype.getY();
複製代碼
題目九:
function Fn(name){
    this.name = name;
    let name = 20;
}    
Fn.prototype.say = function(){
    console.log(5);
}
Function.prototype.say = function(){
    alert(8);
}
Function.say = function(){
    alert(9);
}
Function.__proto__.say = function(){
    alert(10);
}    
let oo = new Fn;
oo.__proto__.say = function(){
    console.log(6);
}
oo.__proto__.__proto__.say = function(){
    console.log(7);
}
oo.say(); //6 
// 自身Fn裏沒有say屬性,到所屬類的原型上找,Fn.prototype.say 等價於 oo.__proto__.say 即console.log(6)

複製代碼
題目十:
function fn() {
    return function(){
        console.log(3);
    }
}
fn.prototype.say = function () {
    console.log(2);
}
Function.prototype.say = function () {
    console.log(4);
}
fn.say = function () {
    console.log(1);
};
new fn().say(); //4 new fn() 
// 返回值是一個匿名函數,匿名函數.say() 即找匿名函數所屬類的原型,即Function.prototype.say
new fn.say(); // 1 先看 fn.say 再看new fn.say 即new function(){console.log(1);}
複製代碼
相關文章
相關標籤/搜索