当前位置: 首页 > news >正文

翻译:原型继承是如何工作的

原文链接

前言:本人表述能力不太好,如果有不清晰的地方请一定回复,我会改。

每个人都知道js有原型继承。但js只默认提供了 new 运算符实现特定的原型继承。所以,大多数的说明都很难读懂。这篇文章目的就是说清楚什么是原型继承,和怎么在js中使用原型继承。

原型继承的定义

当你读到关于js的原型继承,经常能看到如下定义:

当访问对象的属性时,JavaScript将向上遍历原型链,直到找到具有对应的属性- -- Javascript Garden

大多数js的实现使用了 __proto__ 属性来表示原型链中的下一个对象。在本文中将看到 __proto__ 与 prototype 的区别。

:ledger: __proto__ 非标准的,代码中不应该使用。他在这篇文章中用来解释js原型是怎么工作的。

下面的代码展示了js引擎怎么检索属性

function getProperty(obj, prop) {
    if (obj.hasOwnProperty(prop))
        return obj[prop]
    else if (obj.__proto__!=null)
        return getProperty(obj.__proto__, prop)
    else return undefinded
}复制代码

我们用一个经典例子:一个二维点。一个点有两个坐标 x , y 和一个方法 print

用前面写到的原型链的定义,我们将写一个对象 Point ,他有三个属性 x,y, print 。为了创建一个新的二维点,我们写了一个对象,并设置了 __proto__

var Point = {
    x: 0,
    y: 0,
    print: function () {console.log(this.x, this.y);}
};
var p = {x: 10, y: 20, __proto__:Point};
p.print(); // 10 20复制代码

诡异的js原型继承

知道什么最让人迷惑吗?每个这样定义原型继承的人不写这样的代码,他们代码是这样的:

function Point(x,y){
    this.x = x;
    this.y = y;
}
Point.prototype = {
    print: function () { console.log(this.x, this.y); }
}
var p = new Point(10, 20);
p.point(); // 10 20复制代码

这个就和上面的那段代码完全不一样了。 Point 现在是个 function ,有个 prototype 属性,还有 new 运算符。都什么鬼?

new 是怎么工作的?

Brendan Eich   希望 js 是个传统的面向对象的编程语言,就像 Java 和 C++ 一样。在这些语言中,使用new运算符创建类的实例。所以他给 js 写了个 new 运算符。

  • C++ 有构造函数的概念,初始化实例属性。所以, new 操作目标必须是函数。
  • 我们需要要把对象的方法放在某个地方。既然js是个原型语言( prototype language ),那就放在方法的 prototype 属性上吧。

new 运算符有方法F和参数: new F(arguments) 。做了单个简单的步骤:

  1. 创建类的实例。一个空对象将 __proto__ 属性设置为 F.prototype
  2. 实例化。 F 及其参数集被调用,并把 this 设置上去
  3. 返回该实例

现在我们理解了 new 做了什么,可以用 js 实现它

function New(f){
/*1*/    var n = {__proto__:f.prototype};
         return function(){
/*2*/       f.apply(n, arguments);
/*3*/       return n;
         };
    }复制代码

测试下

function Point(x,y) {
    this.x= x;
    this.y=y
}
Point.prototype = {
    print: function(){console.log(this.x,this.y)}
};
var p1 = new Point(10, 20);
p1.print();// 10 20
console.log(p1 instanceof Point);// true
var p2 = New(Point)(10,20);
p2.print();
console.log(p2 instanceof Point);// true复制代码

js里真实的原型继承

JavaScript规范 只提供了 new 运算符。但Douglas Crockford找到了利用 new 运算符实现真正的原型继承的方法。我们现在写 Object.create 方法。

Object.create = function(parent) {
    function F() {};
    F.prototype = parent;
    return new F();
};复制代码

这看上去很奇怪,但是它做的事情却很简单。它只是创建了一个新对象,并把 prototype 设置为任何你想设置的。如果可以使用 __proto__ ,他就可以写成这样

Object.create = function(parent) {    return  {__proto__: parent};
};复制代码

下面的代码是用真正的原型继承实现的 Point

var Point = {
  x: 0,
  y: 0,
  print: function () { console.log(this.x, this.y); }
};
 
var p = Object.create(Point);
p.x = 10;
p.y = 20;
p.print(); // 10 20复制代码

总结

我们知道了原型继承是什么,以及 js 是怎么实现它的。

但是,原型继承的使用( Object.create and __proto__ )有几个缺陷:

  • 不标准: __proto__ 是非标准的甚至反对这样做。而 Object.create 和Douglas Crockford的实现不完全等同。
  • 没优化: Object.create 还没有像 new 构造一样优化。要 慢了10倍

一些深入阅读:

相关文章:

  • 35岁并不是程序员的坎,只是你没有真的认清事实
  • Web安全的重要性(面试必备),被黑无数次还不怕吗?
  • 学前端,css与javascript是重难点,基础不好一切白费!
  • Web前端开发应该必备的编码原则
  • vue全家桶开发 去哪儿 项目总结
  • 这「五类人」最适合转Web前端,必须要了解的前端工程师
  • 每周分享,前端自学「书籍推荐」
  • 「程序员之路」年轻,总得做些什么吧(致那些还未定型的程序员)
  • 自学入门,省去几万学费,web前端必须要知道的「基础知识」
  • 身为前端,你不得不懂的一些HTTP知识(附赠3道面试题)
  • web前端30个项目列表,学完即可上手做项目
  • 还在羡慕程序员工资高吗?看完这篇前端学习计划,你也可以拿高薪
  • 到达瓶颈的前端业务员思考总结,药到病除,方可突破
  • Nginx热升级流程,看这篇就够了
  • 全栈必经Nginx,不懂 Nginx 的前端不是好前端
  • Google 是如何开发 Web 框架的
  • 《Java编程思想》读书笔记-对象导论
  • iOS编译提示和导航提示
  • Less 日常用法
  • Mac转Windows的拯救指南
  • maven工程打包jar以及java jar命令的classpath使用
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 大型网站性能监测、分析与优化常见问题QA
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 小程序button引导用户授权
  • 学习HTTP相关知识笔记
  • 自动记录MySQL慢查询快照脚本
  • nb
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • #Linux(权限管理)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $(selector).each()和$.each()的区别
  • (C++)八皇后问题
  • (pojstep1.1.2)2654(直叙式模拟)
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • **CI中自动类加载的用法总结
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798
  • [ 网络基础篇 ] MAP 迈普交换机常用命令详解
  • [20170728]oracle保留字.txt
  • [2669]2-2 Time类的定义