JavaScript深度学习(六)—— 原型&原型链

文章目录

    • 原型&原型链
      • 原型: prototype
        • 特点&作用:可以提取公有属性
        • 隐式原型 __proto__
        • 注意点:
        • 练习题:
      • 原型链
        • 特殊点
        • 原型链的应用
          • 方法
          • 应用
        • 原型链上的增删改查:
        • 练习题

原型&原型链

  • 所有对象都是通过new 函数创建
  • 所有的函数也是对象
    • 函数中可以有属性
  • 所有对象都是引用类型

原型: prototype

所有函数都有一个属性:prototype,称之为函数原型

默认情况下,prototype是一个普通的Object对象,如:Person.prototype={xxx:xxx};

默认情况下,prototype中有一个属性,constructor,它也是一个对象,它指向构造函数本身。

当有一个对象的时候,一定能知道他的构造函数: obj.proto.constructor.name
JavaScript深度学习(六)—— 原型&原型链_第1张图片

特点&作用:可以提取公有属性

当访问一个对象的成员时:

  1. 看该对象自身是否拥有该成员,如果有直接使用
  2. 在原型链中依次查找是否拥有该成员,如果有直接使用
    Person.prototype.LastName='deng';
    function Person(){
    }
    var obj = new Person();
    obj.LastName == 'deng'
    

隐式原型 proto

==所有对象==都有一个属性:__proto__,称之为隐式原型

默认情况下,隐式原型指向创建该对象的函数的原型。

function text(){
}
var obj = new test();
//obj.__proto__ === test.prototype

function text(){
    return {} // -> new Object
}
var obj = new test();
//obj.__proto__ === Object.prototype

原理:

    //当调用new时,在函数的最前边隐式的加上 
    var this = {
        __proto__:Person.prototype
    };
    //此时Person的原型是默认的prototype
    var obj={
        name:"li"
    }
    //如果更改Person的__proto__的属性
    person.__proto__=obj;
    //此时Person的原型指向obj

注意点:

  1. 对象的最终原型都会指向Object(null没有原型)
  2. 在函数原型中加入成员,以增强起对象的功能,但是会导致原型污染,使用需谨慎

练习题:

下列代码执行完之后访问 person.name 是啥?
Person.prototype.name = "sunny"; 
function Person() { 
 
    } 
var person = new Person;
Person.prototype = {    
    name:"cherry" 
    }

解析:此时应该是 sunny.
最开始的时候__proto__ 和 Person.prototype 指向的是同一个房间,
后来 Person.prototype 指向了一个新的房间,
但是访问 person.name 他找的是__proto__,
__proto__还是指向原来那个房间啊,所以是 sunny

原型链

JavaScript深度学习(六)—— 原型&原型链_第2张图片

  • 所有的函数都是通过new Function来产生的
  • 所有的对象都是通过new 函数来产生的
  • 由上可知:自定义对象的隐式原型(proto)都指向Function.prototype

特殊点

  1. Function的__proto__指向自身的prototype
  2. Object的prototype的__proto__指向null

原型链的应用

方法
  • Object.getPrototypeOf(对象):静态方法,获取对象的隐式原型(W3C不推荐直接使用系统成员__proto__)

  • Object.setPrototypeOf(对象,对象):静态方法,设置对象的隐式原型,将第一个对象的隐式原型设置为第二个参数

  • Object.prototype.isPrototypeOf(对象):判断当前对象(this)是否在指定对象的原型链上

  • Function.prototype.isPrototypeOf(对象):这里就是判断对象是否在Function的原型链上

  • 对象 instanceof 函数:判断函数的原型是否在对象的原型链上

  • Object.create(对象):创建一个新对象,其隐式原型指向指定的对象

  • Object.prototype.hasOwnProperty(属性名):判断一个对象自身是否拥有某个属性

应用
  • 继承类数组转换为数组Array.prototype.slice.call(arr)
  • 实现继承 (圣杯模式)
     var inherit = (function () {     
        var F = function () {};
        return function (Origin,Target) {
            F.prototype = Origin.prototype; 
            Target.prototype = new F();       
            Target.prototype.constructor = Target;      
            Target.prototype.uber = Origin.prototype;
        }
    }())
    

原型链上的增删改查:

  • 增:只能父类自己增加属性,子类无法给父类增加属性。

  • 删除/修改属性,只能在父类中修改删除,子类无法修改删除父类属性。

    • 有一种特殊情况可以修改父类属性,当父类属性为引用值时,可以通过引用值修改。
    function Father() {  
        this.name = "xuming"; 
        this.fortune = {       
            card1:"visa"    
        } 
    } 
    //当使用以下方法时,可以改值
    son.fortune.card2="master";
    
    解释:因为son.fortune 就相当于 fortune 被你取出来了,
    取出来之后.name 就相当于 fortune.name 给自己加 东西,
    这不算一种赋值的修改,这算一种调用的修改,
    这种层面上的修改是可以的, 但是直接给他加值覆盖进去是不行的,
    这种修改也仅限于引用值,原始值是不可以的###
    
例子:
Grand.prototype.LastName = "Deng";
function Grand(){
    
}
var grand = new Grand();

Father.prototype = grand;
function Father(){
    this.name="xiaoming";
}
var father = new Father();
Son.prototype = father;
function Son(){
    this.hobbit = "smoke";
}
var son = new Son();

练习题

题目1var F = function () {}
Object.prototype.a = function () {} //所有的对象都有
Function.prototype.b = function () {}//所有的函数都有

var f = new F();

console.log(f.a, f.b, F.a, F.b);//f是对象,F是函数也是对象
// fn    undefined    fn    fn

题目2function 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

题目3function User() {}
User.prototype.sayHello = function() {}

var u1 = new User();
var u2 = new User();

console.log(u1.sayHello === u2.sayHello); //true
console.log(User.prototype.constructor); //User Function
console.log(User.prototype === Function.prototype); // false
console.log(User.__proto__ === Function.prototype); // true
console.log(User.__proto__ === Function.__proto__); // true
console.log(u1.__proto__ === u2.__proto__);  // true
console.log(u1.__proto__ === User.__proto__); // false
console.log(Function.__proto__ === Object.__proto__); // true
console.log(Function.prototype.__proto__ === Object.prototype.__proto__); // false
console.log(Function.prototype.__proto__ === Object.prototype); // true

你可能感兴趣的:(JavaScript基础)