问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

关于js原型的面试题讲解

发布网友 发布时间:2022-04-24 00:57

我来回答

2个回答

懂视网 时间:2022-05-14 15:29

简单来说,就是当我们创建一个函数的时候,系统就会自动分配一个 prototype属性,可以用来存储可以让所有实例共享的属性和方法

用一张图来表示就更加清晰了:

1.jpg

图解:

  • 每一个构造函数都拥有一个 prototype 属性,这个属性指向一个对象,也就是原型对象
  • 原型对象默认拥有一个 constructor 属性,指向指向它的那个构造函数
  • 每个对象都拥有一个隐藏的属性 __proto__,指向它的原型对象
  • function Person(){}
    
    var p = new Person();
    
    p.__proto__ === Person.prototype // true
    
    Person.prototype.constructor === Person // true

    那么,原型对象都有哪些特点呢

    原型特点

    function Person(){}
    Person.prototype.name = 'tt';
    Person.prototype.age = 18;
    Person.prototype.sayHi = function() {
     alert('Hi');
    }
    var person1 = new Person();
    var person2 = new Person();
    person1.name = 'oo';
    person1.name // oo
    person1.age // 18
    perosn1.sayHi() // Hi
    person2.age // 18
    person2.sayHi() // Hi

    从这段代码我们不难看出:

  • 实例可以共享原型上面的属性和方法
  • 实例自身的属性会屏蔽原型上面的同名属性,实例上面没有的属性会去原型上面找
  • 既然原型也是对象,那我们可不可以重写这个对象呢?答案是肯定的

    function Person() {}
    Person.prototype = {
     name: 'tt',
     age: 18,
     sayHi() {
     console.log('Hi');
     }
    }
    
    var p = new Person()

    只是当我们在重写原型链的时候需要注意以下的问题:

    function Person(){}
    var p = new Person();
    Person.prototype = {
     name: 'tt',
     age: 18
    }
    
    Person.prototype.constructor === Person // false
    
    p.name // undefined

    一图胜过千言万语

    2.jpg

  • 在已经创建了实例的情况下重写原型,会切断现有实例与新原型之间的联系
  • 重写原型对象,会导致原型对象的 constructor 属性指向 Object ,导致原型链关系混乱,所以我们应该在重写原型对象的时候指定 constructor( instanceof 仍然会返回正确的值)
  • Person.prototype = {
     constructor: Person
    }

    注意:以这种方式重设 constructor 属性会导致它的 Enumerable 特性被设置成 true(默认为false)

    既然现在我们知道了什么是 prototype(原型)以及它的特点,那么原型链又是什么呢?

    原型链

    JavaScript 中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链

    同样的,我们使用一张图来描述

    3.png

  • 所有原型链的终点都是 Object 函数的 prototype 属性
  • Objec.prototype 指向的原型对象同样拥有原型,不过它的原型是 null ,而 null 则没有原型
  • 清楚了原型链的概念,我们就能更清楚地知道属性的查找规则,比如前面的 p 实例属性.如果自身和原型链上都不存在这个属性,那么属性最终的值就是 undefined ,如果是方法就会抛出错误

    class类

    ES6 提供了 Class(类) 这个概念,作为对象的模板,通过 class 关键字,可以定义类

    为什么会提到 class

    ES6class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

    class Point {
     constructor(x, y) {
     this.x = x;
     this.y = y;
     }
    
     toString() {
     return '(' + this.x + ', ' + this.y + ')';
     }
    }
    
    // 可以这么改写
    function Point(x, y) {
     this.x = x;
     this.y = y;
    }
    
    Point.prototype.toString = function () {
     return '(' + this.x + ', ' + this.y + ')';
    };

    class 里面定义的方法,其实都是定义在构造函数的原型上面实现实例共享,属性定义在构造函数中,所以 ES6 中的类完全可以看作构造函数的另一种写法

    除去 class 类中的一些行为可能与 ES5 存在一些不同,本质上都是通过原型、原型链去定义方法、实现共享。所以,还是文章开始那句话 JavaScript是基于原型的

    更多 class 问题,参考这里

    关系判断

    instanceof

    最常用的确定原型指向关系的关键字,检测的是原型,但是只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型

    function Person(){}
    var p = new Person();
    
    p instanceof Person // true
    p instanceof Object // true
    hasOwnProperty

    通过使用 hasOwnProperty 可以确定访问的属性是来自于实例还是原型对象

    function Person() {}
    Person.prototype = {
     name: 'tt'
    }
    var p = new Person();
    p.age = 15;
    
    p.hasOwnProperty('age') // true
    p.hasOwnProperty('name') // false

    原型链的问题

    由于原型链的存在,我们可以让很多实例去共享原型上面的方法和属性,方便了我们的很多操作。但是原型链并非是十分完美的

    function Person(){}
    Person.prototype.arr = [1, 2, 3, 4];
    
    var person1 = new Person();
    var person2 = new Person();
    
    person1.arr.push(5) 
    person2.arr // [1, 2, 3, 4, 5]

    引用类型,变量保存的就是一个内存中的一个指针。所以,当原型上面的属性是一个引用类型的值时,我们通过其中某一个实例对原型属性的更改,结果会反映在所有实例上面,这也是原型 共享 属性造成的最大问题

    另一个问题就是我们在创建子类型(比如上面的 p)时,没有办法向超类型( Person )的构造函数中传递参数

    热心网友 时间:2022-05-14 12:37

    今天遇到关于javascript原型的一道面试题,现分析下:
    原题如下:
    function
    A(){
    }
    function
    B(a){
      this.a
    =
    a;
    }
    function
    C(a){
      if(a){
    this.a
    =
    a;
      }
    }
    A.prototype.a
    =
    1;
    B.prototype.a
    =
    1;
    C.prototype.a
    =
    1;
    console.log(new
    A().a);
    console.log(new
    B().a);
    console.log(new
    C(2).a);
    分析:
    console.log(new
    A().a);  //new
    A()为构造函数创建的对象,本身没有a属性,所以向它的原型去找,发现原型的a属性的属性值为1,故该输出值为1;
    console.log(new
    B().a);  //new
    B()为构造函数创建的对象,该构造函数有参数a,但该对象没有传参,故该输出值为undefined;
    console.log(new
    C(2).a);  //new
    C()为构造函数创建的对象,该构造函数有参数a,且传的实参为2,执行函数内部,发现if为真,执行this.a
    =
    2,故属性a的值为2;
    故这三个的输出值分别为:1、undefined、2.  
    以上就是小编为大家带来的关于js原型的面试题讲解的全部内容了,希望对大家有所帮助,多多支持脚本之家~
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    sometimesome timesometimessome times的区别 瓜地的午餐怎么造句 夏季宝宝不吃饭应该怎么办 狼人杀里面的白狼王模式怎么玩? 狼人杀白狼王和骑士:操作至上的高效玩法指南 狼人杀手游白狼王怎么玩 详细玩法攻略 狼人杀 狼人杀的白狼王怎么玩? 国产轮毂品牌有哪些 国产轮毂品牌哪个品牌好 国内轮毂有哪些品牌 岗位和职务怎么填 我的驾驶证是湖南省衡阳市的,我想问下有什么网站可以查驾驶证有没有年审 面试的时候 到底怎么说了解javascript 湖南省驾驶证年检怎么查,谁能告诉我呀 湖南驾驶证年审查询 湖南c1驾照扣分怎么查询 网上查驾驶证真伪查询我的驾驶证是湖南怎么可以看到真伪呢? 怎样查询湖南省营业性道路运输驾驶员从业资格证? 湖南的驾照怎么在网上查驾照扣分情况? 湖南省驾驶证查询怎么查 湖南驾驶证学时怎么查 湖南省益阳市支付宝搜什么可以查到摩托车驾驶证 青浦教育局举报老师的电话是多少 青浦区白鹤镇金项村九组拆迁吗 青浦区农村安置房拆迁协议中看出是数砖头还是人头 青浦盈港苑2021年拆迁们吗青浦盈港苑小区2021年会拆迁吗 青浦区五厍浜路大西街最新拆迁动向 上海青浦,练塘工业区,普洛斯拖欠员工工资? 安顺市拆违办举报电话是多少 青浦区白鹤拆迁明细 拆违一般通知多久 我想查我的驾驶证还有多少分要怎么查.湖南邵阳的 JavaScript面试需要注意什么 如何查询湖南省地区的机动车驾驶证注销情况? javascript面试题级答案 湖南省公安厅换取国籍驾驶证查询电话 JavaScript:面试频繁出现的几个易错点 新拿到的驾驶证为什么在湖南公安平台查不到电子驾驶证的信息? www.hn122122.com湖南交通违法服务平台,这个是*机构还是企业机构? 金凤凰超级理财骗局,谁知道? 湖南省驾驶证邮寄怎么查 程序员面试时,Javascrip和Ajax都会被问一些什么问题 金凤凰接单平台是真是假 js面试题 需要用正则做的? 桐乡市申银万国金凤凰投资管理有限公司怎么样? 福建金凤凰资产管理有限公司怎么样? js的问题,面试别人问了我以下问题,js的执行原理是什么, 金凤凰理财投资可靠吗 面试问js原型怎么理解 金凤凰理财真相揭秘.金凤凰是不是传销.靠不靠谱 由此面试,面试官问我,js能做什么。我知道js是干什么用的,到底js能做...