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

【面试系列】之二:关于js原型

之二:关于js原型

1. 开篇

我记得初学js时,最难懂的概念就是js的原型,而且这个概念在笔试面试中常常提到,
因此今天我们把这个概念拿出来,好好聊一聊。

在仔细讲解之前,我们先来看一道题,这道题来自JavaScript高级程序设计中原型链那一节:

function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
};

function SubType(){
    this.subproperty = false;
}

SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};

var instance = new SubType();
alert(instance.getSuperValue());

请大家猜一猜最后alert出的结果是什么?

大家先思考一下再看下面的内容。

2. 几个知识点

如果上面的题没解出来,也不要灰心丧气,因为有可能有的人解出来的结果也不一定对。
要想弄明白原型等一系列概念,其实只需要记住这几个知识点。

2.1 先弄懂什么是prototype以及_proto_

_proto_:任何一个对象Object都有_proto_,它是每一个对象的私有属性,是天生自带的。
prototype:不是任何对象都有prototype,只有构造函数有prototype,是后天赋予的。

2.2 什么是原型链查找

其实只需要记住一句话:调用一个对象的属性或方法,一但这个对象中没有,就去这个对象的_proto_中查找。这个对象的_proto_指向自己构造函数的prototype属性
然后我们来看一张图:

原型链查找示意图

再来看一个例子:


var Person = function () {
    this.sleep = 'Zzzzz...'
}
Person.prototype.sayHello = function () {
    console.log('hello world');
}
var zhangsan = new Person();
zhangsan.sayHello();

其实zhangsan这个对象下面只有一个sleep属性,是没有sayHello方法的。
但是通过原型链查找会查zhangsan._proto_也就是查找它的构造函数的Person.prototypePerson.prototype下有sayHello这个方法,所以会在控制台输出hello world
所以啦,万变不离其宗!

3. 几种继承方式

除了最新的ES6外,js其实是没有继承和类的概念的,因此想要达到js的继承就要通过模拟的方式。
这里将主要介绍三种继承的方式:纯原型链继承,借用构造函数继承,组合继承

3.1 纯原型链继承

多说无益,来个简单暴力直接的方式,直接上代码:

function Father() {
    this.likeFood= ['牛排','饺子','啤酒','可乐']
}
Father.prototype.saylikeFood = function () {
    console.log(this.likeFood);  
};

function Son() {
}
Son.prototype = new Father();

var zhangsan = new Son();
zhangsan.likeFood.push('西瓜');
zhangsan.saylikeFood(); // ["牛排", "饺子", "啤酒", "可乐", "西瓜"]

Ok,这就是纯原型链的继承方式,其实说白了就是把继承的对象的prototype等于继承自构造函数的实例。
但是这样的方式有问题。接着上面的代码的后面我们再写:

var lisi = new Son();
lisi.saylikeFood(); // ["牛排", "饺子", "啤酒", "可乐", "西瓜"]

看出问题了吧,zhangsan直接修改了其构造函数的likeFood,
导致我们再实例的对象也收到了修改的影响,
因此这种继承方式有缺陷

3.2 借用构造函数继承

还是多说无益,我们直接来看例子,上代码:

function Father(name) {
    this.name = name;
    this.sayName = function () {
        console.log(this.name);
    }
}

function Son(name, age) {
    Father.call(this, name);
    this.age = age;
}

var zhangsan = new Son('zhangsan', 17);

这种继承方式并没有利用到原型以及原型链的概念,它主要利用call的特性,call的第一个参数传入this,后面的参数传入函数所需的参数。
这种方式归根结底其实就是在实例一个对象的时候,向这个对象的上面添加所需的属性和方法。
不信的话可以输出zhangsan看一下

但是其实这种方式也有问题,什么问题呢?
按照这种方式,每次new一个对象,就是实例化一个对象,都会向这个对象身上添加一堆属性和方法。
添加属性是没问题的,但是每次在对象身上添加的方法,这个函数就要重写一次。
函数不能进行复用,这就是最大的问题!

3.3 组合继承

这次要多说两句,组合继承其实分别是拥有以上两种方法的优点,同时也规避了以上两种方法的缺点。
这种方法的应用是最广泛的,是最普遍的,举个栗子来看一下:

function Father(name) {
    this.name = name;
}
Farther.prototype.sayName = function () {
    console.log(this.name);
}

function Son(name, age) {
    Farther.call(this, name);
    this.age = age;
}

Son.prototype = new Father();
Son.constructor = Son;
Son.prototype.sayage = function () {
    console.log(this.age);
}

var zhangsan = new Son();

来看一下,这种方式不错吧!
其实除了组合继承外,还有两种继承方式:原型式继承寄生式继承
这两种方式感兴趣的同学可以自行了解一下

4. 最后

抱歉,这篇这么迟才出来,其实应该早早完事的。
我最近买了一本《学习JavaScript数据结构与算法》再看,我准备新开辟一个专栏来写一下我的学习笔记。
下一次我决定和大家讲讲闭包的事。

本期的内容是原创的,但其实主要是看了《JavaScript高级程序设计》的启发!
建议你也去看书,读一下这本书的第六章的继承那一部分,相信你也会深有启发。

加油!

相关文章:

  • 基于nexus的maven私服配置
  • 设计模式之Adapter模式
  • 关于KMP算法理解(快速字符串匹配)
  • uva 10370 Above Average
  • linux下部署tomcat指定JDK版本编译并运行javaWEB应用
  • 个人视频发布汇总——教育改变人生
  • springmvc项目提交post表单参数乱码解决办法
  • MongoDB常用操作命令大全
  • I.MX6 android 4.2 源码下载
  • wait和waitpid详解
  • 使用WSAIoctl获取AcceptEx函数指针 [转]
  • esxi报错There is no more space for virtual disk--逻辑卷缩减!
  • Delphi 7使用自定义图标关联文件类型
  • NServiceBus---最流行的开源企业服务总线 for .Net
  • Struts2 - 常用的constant总结
  • [译]Python中的类属性与实例属性的区别
  • 0x05 Python数据分析,Anaconda八斩刀
  • JavaScript HTML DOM
  • JavaScript异步流程控制的前世今生
  • Joomla 2.x, 3.x useful code cheatsheet
  • JS字符串转数字方法总结
  • PhantomJS 安装
  • Python十分钟制作属于你自己的个性logo
  • React Transition Group -- Transition 组件
  • Redux系列x:源码分析
  • Sequelize 中文文档 v4 - Getting started - 入门
  • Service Worker
  • Spring-boot 启动时碰到的错误
  • spring学习第二天
  • Travix是如何部署应用程序到Kubernetes上的
  • 关于使用markdown的方法(引自CSDN教程)
  • 三栏布局总结
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 正则表达式小结
  • 仓管云——企业云erp功能有哪些?
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #传输# #传输数据判断#
  • (02)vite环境变量配置
  • (145)光线追踪距离场柔和阴影
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (剑指Offer)面试题34:丑数
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .net core webapi 大文件上传到wwwroot文件夹
  • .Net FrameWork总结