其他分享
首页 > 其他分享> > JS原型链模式和继承模式

JS原型链模式和继承模式

作者:互联网

原型链模式

实例识别:
构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立开的

function CreateJsPerson(name, age){
    this.name = name;
    this.age = age;
}
CreateJsPerson.prototype.writeJs = function(){
        console.log("my name is " + this.name + ", i can                write js ~~")
    }

基于构造函数模式的原型模式解决了,方法或者属性共有的问题,想让谁共有就把他放在CreateJsPerson.prototype上即可

js中规定的

prototype

  1. 每一个函数数据类型(普通函数,类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值

constructor

  1. 并且在prototype上浏览器天生给它加了一个属性constructor(构造函数),属性值是当前函数(类)本身

_ proto _

  1. 每一个对象数据类型(普通的对象,实例,prototype..)也天生自带一个属性: _ _proto _ _,属性值是当前实例所属类的原型(prototype)
function Fn(){
    this.x = 100;
}
Fn.prototype.getX = function(){
    console.log(this.x);
}
var f1 = new Fn;
var f2 = new Fn;

console.log(Fn.prototype.constructor === Fn); // true
console.log(f1 instanceof Object); // true

原型链查找机制

  1. 通过 对象名.属性名 的方式获取属性值的时候, 首先在对象的私有的属性上进行查找, 如果私有中存在这个属性,则获取的是私有的属性值;
  2. 如果私有的没有,则通过__proto__找到所属类的原型, 类的原型上定义的属性和方法都是当前实例公有的属性和方法, 原型上存在的话, 获取的是共有的属性值;
  3. 如果原型上也没有,则继续通过原型上的__proto__继续向上查找, 一直找到Obejct.prototype为止
console.log(f1.getX === f2.getX); // true
console.log(f1.__proto__.getX === f2.getX);// true
console.log(f1.getX === Fn.prototype.getX); // true

在IE浏览器中,原型模式也是同样的原理,但是IE浏览器怕你通过__proto__把公有的修改,禁止我们修改__proto__

批量设置共有属性

  1. 起别名
function Fn(){
    this.x = 100;
}
var pro = Fn.prototype;
pro.getX = function(){}
pro.getY = function(){}
  1. 重构原型对象的方式
function Fn(){
    this.x = 100;
}
Fn.prototype = {
    getX: function(){},
    getY: function(){}
}
var f = new Fn;
console.log(f.constructor)' // Object

只有浏览器天生给Fn.prototype开辟的堆内存里面才有constructor,而我们自己开辟的这个堆内存没有这个属性,
这样constructor指向就不再是Fn而是Object

为了和原来的保持一致,我们需要手动的增加constructor的指向

Fn.prototype = {
   constructor: Fn
}

会把之前已经存在于原型上的属性和方法给替换掉, 用这种方式修改内置类的话, 浏览器会给屏蔽掉

Array.prototype = {
    constructor: Array,
    unique: function(){}
}
console.dir(Array.prototype);

但是可以使用prototype属性,一个个修改内置的方法,如果方法名和原来内置的重复了, 会把内置的修改掉, 在内置类的原型上增加方法, 名命都需要加特殊的前缀

Array.prototype.sort = function(){
    console.log("lemon");
}
var ary = [1, 2, 2, 1, 2, 3, 4];
ary.sort();
console.log(ary);

常用的六种继承模式

for in 循坏在遍历的时候, 可以把自己私有的和在它所属原型上扩展的属性和方法都遍历到.

Object.prototype.aaa = function(){};
var obj = {name: 'lemon', age: 22};
for(let key in obj){
    console.log(key)
}

可以使用以下方法,进行判断处理

for(let key in obj){
    if(obj.propertyIsEnumerable(key)){
        console.log(key);
    }
}
for(let key in obj){
    if(obj.hasOwnProperty(key)){
        console.log(key);
    }
}

Object.create(proObj)

创建一个新的对象, 但是要把proObj作为这个对象的原型, 在IE6-IE8不兼容(ECMAScript5)

var obj = {
    getX: function(){}
}
var obj2 = Object.create(obj)
console.dir(obj2)
obj.getY = function(){}
console.dir(obj2)

自己实现一个create

var obj = {
    getX: function(){}
}
function object(o){
    function Fn(){}
    Fn.prototype = o;
    return new Fn();
}
var newObj = object(obj);

原型链继承

原型继承是JS中最常用的一种继承方式, 子类B想要继承父类A中的所有的属性和方法(私有+公有), 只需要让B.prototype = new A;
特点: 它是把父类中的私有+公有的都继承到了子类原型上(共有的)
核心: 原型继承并不是把父类中的属性和方法克隆一份一模一样的给B,而是让B和A之间增加了原型链的连接, 以后B的实例n想要A中的getX方法,需要一级一级的向上查找来使用

function A(){
    this.x = 100;
}
A.prototype.getX = function(){
    console.log(this.x)
}
function B(){
    this.y = 200;
}
B.prototype = new A

缺点: 不安全, 可以通过子类或子类的实例,更改父类原型链上的属性和方法, 对A的实例和子类造成影响

var b = new B
var a = new A
b.__proto__.__proto__.getX = 3000;
console.log(a.getX)
B.prototype.__proto__.getX = 2000;
console.log(a.getX)

call继承

借用构造函数, 伪造对象继承和经典继承
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。

function A(){
    this.x = 100;
}
A.prototype.getX = function(){
    console.log(this.x);
}
function B(){
    A.call(this)
}
var b = new B;
console.log(b.x)

缺点:
父类在原型链中定义的函数不能被子类访问,也就是说所有的函数都必须写在构造函数内部,无法复用

冒充对象

把父类私有和公有的属性和方法,克隆一份一模一样的给子类私有的

function A(){
    this.x = 100;
}
A.prototype.getX = function(){
    console.log(this.x);
}
function B(){
    var temp = new A;
    for(var key in temp){
        this[key] = temp[key];
    }
}
var b = new B;
console.log(b.x)

混合模式继承

子私有 = 父私有, 子公有 = 父私有 + 父公有

function A(){
    this.x = 100;
}
A.prototype.getX = function(){
    console.log(this.x);
}
function B(){
    A.call(this)
}
B.prototype = new A;
B.prototype.constructor = B;
var b = new B;
console.log(b.x)

寄生组合式继承

子私有 = 父私有, 子公有 = 父公有

function A(){
    this.x = 100;
}
A.prototype.getX = function(){
    console.log(this.x);
}
function B(){
    A.call(this)
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
var b = new B;
console.log(b.x)

中间类继承法,不兼容

function avgFn(){
    arguments.__proto__ = Array.prototype;
    arguments.sort(function (a, b) {
        return a - b;
    })
    arguments.pop()
    arguments.shift()
    return eval(arguments.join("+")) / arguments.length;
}
avgFn(10, 20 ,30 ,10 ,30, 40, 40); // 26

标签:function,console,log,模式,JS,getX,原型,prototype,Fn
来源: https://www.cnblogs.com/xiaoxu-xmy/p/13644998.html