0

0

JavaScript原型和原型链的方法介绍(代码示例)

不言

不言

发布时间:2019-01-10 10:59:44

|

2864人浏览过

|

来源于segmentfault

转载

本篇文章给大家带来的内容是关于javascript原型和原型链的方法介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

1、题目

如何准确判断一个变量是数组

写一个原型链继承的例子

继承实现的其他方式

立即学习Java免费学习笔记(深入)”;

es6 实现继承的底层原理是什么

描述new一个对象的过程

zepto及其他源码中如何使用原型链

2.知识点

2.1 构造函数

特点:以大写字母开头

function Foo(name,age){
    //var obj = {}
    //this = {}
    this.name = name;
    this.age = age;
    this.class = 'class1'
    // return this
}

var f1 = new Foo('liming',19);

扩展

var o = {} 是 var o = new Object() 的语法糖

var a = [] 是 var a = new Array() 的语法糖

function Foo(){}  相当于 var Foo = new Function(){}

2.2 原型规则

五条规则:

1.所有引用类型(对象,数组,函数)都具有对象特性,即可以自由扩展属性

2.所有引用类型(对象,数组,函数)都具有一个__proto__(隐式原型)属性,是一个普通对象

3.所有的函数都具有prototype(显式原型)属性,也是一个普通对象

4.所有引用类型(对象,数组,函数)__proto__值指向它构造函数的prototype

5.当试图得到一个对象的属性时,如果变量本身没有这个属性,则会去他的__proto__中去找

for (var key in object) {
    //高级浏览器中已经屏蔽了来自原型的属性
    //建议加上判断保证程序的健壮性
    if (object.hasOwnProperty(key)) {
        console.log(object[key]);
    }
}

2.3 原型链

obj.__ proto . proto . proto __ ...

Object.prototype === null

instanceof 用于判断引用类型属于哪个构造函数

obj instanceob  Foo

实际意义:判断 Foo.prototype 在不在 obj的原型链上

3.题目解答

3.1 如何准确判断一个变量是数组

arr instanceof Array

3.2 写一个原型链继承的例子

封装dom查询

function Elem(id){
    this.elem = document.getElementById(id);
};

Elem.prototype.html = function(val){
    var elem = this.elem;
    if (val) {
        elem.innerHTML = val;
        return this;
    }else{
        return elem.innerHTML;
    }
}

Elem.prototype.on = function(type,fun){
    var elem = this.elem;
    elem.addEventListener(type,fun);
    return this;
}

var p1 = new Elem('id1');
p1.html("test").on('click',function(){
    console.log('点击');
})

3.3 继承实现的其他方式

3.3.1 原型继承

ModelGate
ModelGate

一站式AI模型管理与调用工具

下载
        var obj = {
            0:'a',
            1:'b',
            arr:[1]
        }
        
        function Foo(arr2){
            this.arr2 = [1]
        }

        Foo.prototype = obj;

        var foo1 = new Foo();
        var foo2 = new Foo();

        foo1.arr.push(2);
        foo1.arr2.push(2);

        console.log(foo2.arr);  //[1,2]
        console.log(foo2.arr2); //[1]

优点:实现简单

缺点:

1.无法向父类构造函数传参

2.同时new两个对象时改变一个对象的原型中的引用类型的属性时,另一个对象的该属性也会修改。因为来自原型对象的引用属性是所有实例共享的。

3.3.2 构造继承

        function Super(b){
            this.b = b;
            this.fun = function(){}
        }
        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }

        var foo1 = new Foo(1,2);
        console.log(foo1.b);

优点:可以向父类传参,子类不会共享父类的引用属性

缺点:无法实现函数复用,每个子类都有新的fun,太多了就会影响性能,不能继承父类的原型对象。

3.3.3 组合继承

function Super(){
    // 只在此处声明基本属性和引用属性
    this.val = 1;
    this.arr = [1];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(){
    Super.call(this);   // 核心
    // ...
}
Sub.prototype = new Super();

优点:不存在引用属性共享问题,可传参,函数可复用

缺点:父类的属性会被实例化两次,获取不到真正实例父类(无法区分实例是父类创建还是父类创建的)

优化:

         function Super(b){
            this.b = b;
            this.fun = function(){}
        }

        Super.prototype.c = function(){console.log(1111)}

        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }


        Foo.prototype = Super.prototype;
        //修复构造函数:
        var foo1 = new Foo(1,2);

缺点:无法区分实例是父类创建还是子类创建的

3.3.4 寄生组合继承

         function Super(b){
            this.b = b;
        }

        Super.prototype.c = function(){console.log(1111)}

        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }

        var f = new Function();
        f.prototype = Super.prototype;
        Foo.prototype = new f();
        //等同于 Foo.prototype = Object.create(Super.prototype);
        
        var foo1 = new Foo(1,2);

对父类的prototype进行一次寄生,即包装成一个空对象的prototype,再把这个对象实例化出来作为子类的peototype。

缺点:无法区分实例是父类创建还是子类创建的

可以添加以下代码:

Foo.prototype.constructor = Foo

这种解决方法不能用于上面的组合优化方法,因为子类父类引用的是同一个原型对象,修改会同时修改。

总结:

继承主要是实现子类对父类方法,属性的复用。

来自原型对象的引用属性是所有实例共享的,所以我们要避免从原型中继承属性。

在构造函数中通过call函数可以继承父类构造函数的属性和方法,但是通过这种方式实例化出来的实例会将父类方法多次存储,影响性能。

通过组合继承我们使用call继承属性,使用原型继承方法,可以解决以上两个问题,但是通过这种方式实例化出来的对象会存储两份父类构造函数中的属性。

用父类的原型构造一个新对象作为子类的原型,就解决了多次存储的问题,所以最终的寄生组合继承就是最佳继承方式,它的缺点就是书写起来比较麻烦。

3.3.6 node源码中的继承实现

function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
}; 

function Stream(){
    //...
}

function OutgoingMessage() {
  Stream.call(this);
  //...
}

inherits(OutgoingMessage, Stream);

OutgoingMessage.prototype.setTimeout = ...

以上是寄生组合继承的一个实例。

1.在OutgoingMessage构造函数中通过call继承Stream构造中的属性。

2.调用inherits方法继承Stream原型中的属性。

3.扩展OutgoingMessage自身原型的函数。

inherits方法中使用了Object.create方法,该方法的作用是通过指定的原型对象和属性创建一个新的对象。

ctor.prototype=Object.create(superCtor.prototype,{.....});

该方法实际上就做了我们上面寄生组合继承中的工作

var f = new Function();
f.prototype =superCtor.prototype;
return new f();

后面的参数是给原型对象添加属性,可选属性(非必填),即把自身作为新创建对象的构造函数。

value: 表示constructor 的属性值;
writable: 表示constructor 的属性值是否可写;[默认为: false]
enumerable: 表示属性constructor 是否可以被枚举;[默认为: false]
configurable: 表示属性constructor 是否可以被配置,例如 对obj.a做 delete操作是否允许;[默认为: false]

3.4 es6继承的实现方式

参考我这篇文章:https://segmentfault.com/a/11...

3.5 描述new一个对象的过程

  1. 创建一个对象

  2. {}._proto_ = 构造函数.prototype

  3. this指向这个对象

  4. 执行代码即对this赋值

  5. 返回this

3.6 zepto及其他源码中如何使用原型链

var Zepto = (function(){

    var $,zepto = {}
    
    // ...省略N行代码...
    
    $ = function(selector, context){
        return zepto.init(selector, context)
    }

    zepto.init = function(selector, context) {
        var dom
        
        // 针对参数情况,分别对dom赋值
        
        // 最终调用 zepto.Z 返回的数据
        return zepto.Z(dom, selector)
    }    

   fnction Z(dom, selector) {
      var i, len = dom ? dom.length : 0
     for (i = 0; i < len; i++) this[i] = dom[i]
      this.length = len
      this.selector = selector || ''
    }

   zepto.Z = function(dom, selector) {
     return new Z(dom, selector)
   }
  
    $.fn = {
        // 里面有若干个工具函数
    }
      
  
    zepto.Z.prototype = Z.prototype = $.fn
  
    
    // ...省略N行代码...
    
    return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

46

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

178

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

51

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

92

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

102

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

227

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

532

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

171

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号