破解 JS(原型)继承

总体分为四大类:利用空对象作为中介继承、Object.create 继承、setPrototypeOf 继承、拷贝继承

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

Animal.prototype = {
  speak: function() {
    console.log(‘my name is ‘ + this.name);
  }
}

function Cat() {
  Animal.apply(this, arguments);
  this.food = ‘mouse‘;
}

一、利用空对象作为中介继承

function extend(child, parent) {
  var F = function() {};
  F.prototype = parent.prototype;
  child.prototype = new F();
  child.prototype.constructor = child;
}

F是空对象,所以几乎不占内存。这其实就是 YUI 实现继承的方法。

试一试

二、Object.create 继承

Object.create 会使用指定的原型对象和属性去创建一个新对象。

function extend(child, parent) {
  // 任何一个prototype对象都有一个constructor属性,指向它的构造函数。
  // 使 Cat.prototype 指向 Animal.prototype, 但他有一个副作用:Cat.prototype.constructor指向Animal
  child.prototype = Object.create(parent.prototype);
  // 修正 constructor
  child.prototype.constructor = child;
}

试一试

疑问一:为什么不直接  child.prototype = parent.prototype; ?

  如果这样的话,child.prototype 会直接引用 parent.prototype 对象,那么当你对 child.prototype.constructor 进行赋值操作时,就把 parent.prototype.constructor 也给修改了

疑问二:为什么不用child.prototype = new parent(); ?

   new parent() 确实会创建一个关联到 child.prototype 的新对象。但如果函数 parent 有一些副作用(比如修改状态、注册到其它对象、给 this 添加属性等等)的话,会影响到 child() 的后代,后果不堪设想!

综上所诉,Object.create 是最好的选择,虽然它是创建了一个新对象替换掉了默认的对象。那有没有直接修改默认对象的方法呢?答案就是 setPrototypeOf

三、setPrototypeOf 继承

setPrototypeOf 是 ES6新增的辅助函数。下面来做一下对比

// 抛弃默认的 child.prototype
child.prototype = Object.create(parent.prototype);

// 直接修改默认的 child.prototype
Object.setPrototypeOf(child.prototype, parent.prototype);

经过对比发现:如果忽略Object.create() 带来的轻微的损失(抛弃的对象需要进行垃圾回收),它比 ES6 的方法有更好的可读性。

四、拷贝继承

也是 jQuery 实现继承的方法

// 拷贝继承
function extend() {
    var options, src, copy, copyIsArray, clone,
        target = arguments[0] || {},
        deep = false,
        i = 1;

    if ( typeof target === ‘boolean‘) {
        deep = target;

        target = arguments[i] || {};
        i++;
    }

    if ( typeof target !== ‘object‘ && !isFun(target)) {
        target = {};
    }

    // 循环一个或多个要拷贝的对象
    for( ; i<arguments.length; i++ ) {
        if ( (options = arguments[i]) != null ) {
            for ( name in options ) {
                src = target[name];
                copy = options[name];

                // 防止死循环
                if ( target === copy ) {
                    continue;
                }

                copyIsArray = isArray(copy);
                if ( deep && copy && ( isPlainObject(copy) || copyIsArray ) ) {
                    // 深拷贝
                    if ( copyIsArray ) {
                        copyIsArray = false;
                        clone = src && isArray(src) ? src : [];
                    } else {
                        clone = src && isPlainObject(src) ? src : {};
                    }

                    target[name] = extend( deep, clone, copy );
                // 防止拷贝 undefined
                } else if ( copy !== undefined ) {
                    target[name] = copy;
                }
            }
        }
    }

    return target;
}

function isFun(obj) {
    return type(obj) === ‘[object Function]‘;
}

function isPlainObject(obj) {
    return type(obj) === ‘[object Object]‘;
}

function isArray(obj) {
    // IE8不支持
    if (Array.isArray) {
        return Array.isArray(obj);
    } else {
        return type(obj) === ‘[object Array]‘;
    }
}

function type(obj) {
    if ( obj == null ) {
        // obj + ‘‘ = ‘null‘/‘undefined‘
        return false;
    }

    return Object.prototype.toString.call(obj);
}

var object1 = {
  apple: 0,
  banana: { weight: 52, price: 100 }
};
var object2 = {
  banana: { price: 200 },
  cherry: 97
};

extend(true, object1, object2);

试一试

时间: 2024-10-26 17:28:12

破解 JS(原型)继承的相关文章

JS原型继承与类的继承

我们先看JS类的继承 1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>JS类的继承</title> 7 </head> 8 9 <body> 10 /* -- 类式继承 -- */ 11 <script type="text/javascript"> 12 //先声

JS原型继承和类式继承

类式继承(构造函数) JS中其实是没有类的概念的,所谓的类也是模拟出来的.特别是当我们是用new 关键字的时候,就使得"类"的概念就越像其他语言中的类了.类式继承是在函数对象内调用父类的构造函数,使得自身获得父类的方法和属性.call和apply方法为类式继承提供了支持.通过改变this的作用环境,使得子类本身具有父类的各种属性. JavaScript var father = function() { this.age = 52; this.say = function() { al

js原型继承

原型链: Object(构造函数) object(类型(对象)) var o = {}; alert(typeof o); //结果是object alert(typeof Object); //结果是function 每一个对象都有一个属性叫 __proto__ ,这个属性就是这个对象的原型(o. __proto__),函数可通过 函数名.prototype 获取原型,对象可以通过 对象.__proto__(双下划线)获取. 对象有原型,原型也是对象,所以原型也有原型,所有的函数都是对象,继承

关于js原型继承

js的每个类都有一个prototype对象 访问对象的属性时,会先访问到对象自身是否有定义这个属性 如果没有定义,就会去访问对象所属类型的prototype对象是否有此属性 原型继承就是把类型的prototype指向一个父类的新对象,这样每派生一个新类出来都会构造一个新的父类对象作为原型,这个对象和父类的prototype是分离的 因而可以用于添加子类的新属性而不影响父类 > function cls(){xx = function(){console.log(11)}} undefined >

js - 原型继承和应用

前言:本文大体摘自:https://blog.csdn.net/sysuzhyupeng/article/details/54645430    这位CSDN博主写的十分的好,逻辑性很强.后面 "如何安全的扩展一个内置对象 " 是我添加的.顺便把这位博主的  详解js中extend函数  和  call和apply上手分析  摘抄下来. 原型继承:利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就叫做原型继承. 原型继承是js的一种继承方式,原型继承

JS 原型继承的几种方法

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <script type="text/javascript"> function Person() { this.name = '老王

我的博客园初篇 解密 js原型继承

网上的关于原型继承的文章多入牛毛 但是我感觉并不适合新手了解 首先假如这位新手了解过面向对象java啊 c#啊他会理解继承 但是和javascript的继承有有所不同,又假如这位新手初入前端 以前没了解过面向对象 你和他说一大堆术语 更加把他搞得蒙头转向.我在这里尝试用人类认知的模式来解释什么事原型继承以及为什么需要它. 从某种意义来说面向对象的三大特性在我看来是为了“偷懒”(纵观全世界科技发展莫不如此)而由聪明人想出来的法子,在代码世界中,代码的复用也就是多次使用时司空见惯的,比如你一进门就写

js原型继承的几种方式

1. 原型链继承 2,构造函数继承(对象冒充继承) 3,组合继承(原型链继承+构造函数继承) 4,原型式继承 5. 寄生组合式继承 一.原型链继承 function Show(){ this.name="run"; } function Run(){ this.age="20"; //Run继承了Show,通过原型,形成链条 } Run.prototype=new Show(); var show=new Run(); alert(show.name)//结果:ru

分享一个js原型继承的方法

function Person(){ this.color = [23,2,3,32] } undefined var p = Object.create(new Person()) undefined p.color.push(1)

JS 类继承 原型继承

参考文档:JS原型继承和类继承 <script src="jquery-2.0.3.js"> </script> <script> /*//类继承 var father=function(){ this.age=53; this.say=function(){ console.log("name:"+this.name+",age:"+this.age); } }; var child=function(){