总体分为四大类:利用空对象作为中介继承、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);

试一试

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

  1. 【09-23】js原型继承学习笔记

    js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...

  2. JS原型继承与类的继承

    我们先看JS类的继承 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...

  3. js原型继承四步曲及原型继承图

    一:js原型继承四步曲 //js模拟类的创建以及继承 //动物(Animal),有头这个属性,eat方法 //名字这个属性 //猫有名字属性,继承Animal,抓老鼠方法 //第一步:创建父类 fun ...

  4. JS原型继承和类式继承

    前言 一个多月前,卤煮读了一篇翻译过来的外国人写的技术博客.此君在博客中将js中的类(构造)继承和原型继承做了一些比较,并且得出了结论:建议诸位在开发是用原型继承.文中提到了各种原型继承的优点,详细的 ...

  5. 关于js原型继承

    js的每个类都有一个prototype对象 访问对象的属性时,会先访问到对象自身是否有定义这个属性 如果没有定义,就会去访问对象所属类型的prototype对象是否有此属性 原型继承就是把类型的pro ...

  6. js原型继承

    原型链: Object(构造函数) object(类型(对象)) var o = {}; alert(typeof o); //结果是object alert(typeof Object); //结果 ...

  7. js原型继承深入

    js采用原型继承来实现类的派生,但是原型链再深入点,我们又知道多少呢,现在不妨往下看: 先来一个原型继承: var M1 = function() { this.param = "m1's ...

  8. 前端面试题总结二(js原型继承)

    今天这篇文章整理了JS原型和继承的一些知识点,面试的时候  基!本!都!会!问!还不快认真阅读下文,看看你还有哪些知识点需要掌握吧~ 1.原型链 基本思想:利用原型让一个引用类型继承另外一个引用类型的 ...

  9. JS 原型继承的几种方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. JS 原型 & 继承

    理解原型链 先看看http://www.ituring.com.cn/article/56184和http://www.cavabiao.com/prototype-and-inherit-of-ja ...

随机推荐

  1. 使用COE脚本绑定SQL Profile

    日常运维中,经常会遇到需要绑定好的执行计划的场景. 简单来说,就是将一个sql_id绑定好的plan_hash_value.如果没有使用到绑定变量,还需要把force_match设置为true. 用到 ...

  2. 213. House Robber II(动态规划)

    You are a professional robber planning to rob houses along a street. Each house has a certain amount ...

  3. ES6知识总结

    ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了.它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应 ...

  4. Tomcat 加载 jsp 异常:ServletException: java.lang.LinkageError

    环境:win10 JDK:java version "1.8.0_131" mvn 内置 Tomcat 报错: javax.servlet.ServletException: ja ...

  5. Flask最强攻略 - 跟DragonFire学Flask - 第十四篇 Flask-SQLAlchemy

    前不久刚刚认识过了SQLAlchemy,点击这里复习一下 当 Flask 与 SQLAlchemy 发生火花会怎么样呢? Flask-SQLAlchemy就这么诞生了 首先要先安装一下Flask-SQ ...

  6. WIFI CAT ET III Adapter Caterpillar ET3 New Arrival

    The old bluetooth cat et adatper iii has stopped production, and you can get the new WIFI CAT Caterp ...

  7. .net core webapi+vue 跨域访问

    最近在做一个前后端分离的示例,以下代码完美解决跨域的问题 一.后端服务 1.首先我们建一个.net core webapi的项目 2.项目引用Microsoft.AspNetCore.Cors 包 3 ...

  8. Linux命令(一)

    一:命令介绍,目录结构,基本格式 linux命令格式:   command [-options] [parameter1] ...    带-就是选项,不带-就是参数 ls ---文件显示    ls ...

  9. Python 用户交互程序Input

    1.用户交互,用户输入 用户输出命令是input. 设置一个变量并输出. name = input("name:") print(name) 注:python2 下 raw_inp ...

  10. Python Redis 发布订阅

    发布者:服务器 订阅者:Dashboad和数据处理 频道主逻辑 import redis class RedisHelper: def __init__(self): # 链接服务端 self.__c ...