文档章节

【宠粉通道】叫我讲解的一道前端JS面试题-灵魂三问:prototype?类的prototype是什么?对象的proto是什么

达达前端
 达达前端
发布于 2019/12/26 01:33
字数 2060
阅读 10
收藏 0

3 月,跳不动了?>>>

file

作者 | Jeskson

来源 | 达达前端小酒馆

1

究竟是什么样的题目让我徒弟疑惑呢?让我们看看截图先,来源于wx群:

file

看看我是怎么回答的:

file

file

file

file

file

function Foo() {
    getName = function () { alert (1); };
    return this;
}
var getName;
//只提升变量声明

function getName() { alert (5);}
//提升函数声明,覆盖var的声明

Foo.getName = function () { alert (2);};

Foo.prototype.getName = function () { alert (3);};

getName = function () { alert (4);};
//最终的赋值再次覆盖function getName声明

getName();
//最终输出4

看懂没呢?没看懂也别急哈:

先让我们了解函数的定义:

函数声明,可以先调用再声明

dadaFn();

function dadaFn(){
 console.log(dadaFn);
}

file

/ 返回 f -> function
function dadaFn() {
 console.log(dadaFn);
}

函数表达式,先声明再调用:

let daDafn = function() {
 console.log("dada");
};

daDafn();

file

let fn = function() {
    console.log(111);
}
fn(); //111
VM1188:2 111
undefined
let daDafn = function() {
 console.log("dada");
}

daDafn();
VM1197:2 dada
undefined

箭头函数:

let da = () => {};

console.log( da.prototype );

file

JavaScript prototype属性,可以让你向对象添加属性和方法:

格式:

object.prototype.name = value;

使用prototype属性向对象添加属性:

function dada (name,age) {
 this.name = name;
 this.age = age;
}

var dashu = new dada("dashucoding", 13);

dada.prototype.job = null;

dashu.job = it;

console.log(dashu.jog);

输出结果:

it

构造函数:

let da1 = new Function('a', 'b');

da1(1,2);

file

let da1 = new Function('a', 'b');

da1(1,2);

VM65:3 Uncaught ReferenceError: b is not defined
    at eval (eval at <anonymous> (local-ntp.html:1), <anonymous>:3:1)
    at <anonymous>:3:1
(anonymous) @ VM65:3
(anonymous) @ VM64:3

let fn1 = new Function('a', 'b',  'console.log(a * b)');
fn1(1, 2); //2
VM69:3 2
undefined

预解析,变量提升的概念:

file

面试题

file


function Foo() {
    getName = function () { console.log (1); };
    return this;
}
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};
var getName = function () { console.log (4);};
function getName() { console.log (5);}

//请写出以下输出结果:
Foo.getName();

getName();

Foo().getName();

getName();

new Foo.getName();

new Foo().getName();

new new Foo().getName();

VM243:5 2
VM243:7 4
VM243:2 1
VM243:2 1
VM243:5 2
VM243:6 3
VM243:6 3
//答案:
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3

变量定义提升,this指针指向,运算符优先级

原型、继承、全局变量污染、对象属性及原型属性优先级

灵魂三问:

prototype?类的prototype是什么?对象的proto是什么?

在JavaScript中,prototype对象是实现面向对象的一个重要机制。

每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。

实现面向对象机制

通过new创建一个类的实例对象的时候,prototype对象的成员都成为实例化对象的成员。

1、该对象被类所引用,只有函数对象才可引用; 2、在new实例化后,其成员被实例化,实例对象方可调用。

同时,函数是一个对象,函数对象若直接声明成员,不用被实例化即可调用。

定义和用法

prototype 属性使您有能力向对象添加属性和方法。

构造函数的简单介绍

file

function Person(){
 this.name = 'dada';
}
 var boy = new Person();
console.log(boy.name); //'dada'
VM254:5 dada
undefined

file

prototype属性的作用

为了解决构造函数的对象实例之间无法共享属性的缺点,js提供了prototype属性。

js中每个数据类型都是对象(除了null和undefined)。

每个对象都继承自另外一个对象,后者称为“原型”(prototype)对象,只有null除外,它没有自己的原型对象。

原型对象上的所有属性和方法,都会被对象实例所共享。

通过构造函数生成对象实例时,会将对象实例的原型指向构造函数的prototype属性。

每一个构造函数都有一个prototype属性,这个属性就是对象实例的原型对象。

原型对象的属性不是对象实例的属性。

prototype是作为构造函数的属性

对于对象实例来说,prototype是对象实例的原型对象。

所以prototype即是属性,又是对象。

file

原型链:原型链主要用于继承,每个对象都有一个proto属性指向其构造函数的原型对象,当访问对象的属性和方法时,会先在对象自身进行查找,如果不存在,则沿着proto属性向上一级查找,直到没找到返回 undefined,这样的查找过程,称之为原型链。

原型链,请找我文章:一篇文章带你了解JavaScript中的变量,作用域,和内存问题。

function Foo() {
    getName = function () { console.log (1); };
    return this;
}
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};

var getName = function () { console.log (4);};
function getName() { console.log (5);}

//请写出以下输出结果:
Foo.getName();  // 2

看代码,先定义一个Foo()的函数,之后为Foo创建一个叫getName的静态属性,用来存储一个匿名的函数,之后为Foo的原型对象,新创建了一个叫getName的匿名函数。

var getName = function () { console.log (4);};
function getName() { console.log (5);}

然后通过函数变量表达式,创建一个getName的匿名函数,然后由通过函数变量表达式,创建一个getName的函数。

最后一个是声明一个叫getName的函数。

Foo.getName();  // 2

这个不用说就是访问Foo()函数上存储的静态属性,答为2。

下一个问:

getName();

Foo().getName();

getName();

new Foo.getName();

new Foo().getName();

new new Foo().getName();
getName(); 的答案呢? // 5

function Foo() {
    getName = function () { console.log (1); };
    return this;
}

这里要分开理解看

Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};

var getName = function () { console.log (4);};
function getName() { console.log (5);}

预解析/变量提升

file

function Foo() {
    getName = function () { alert (1); };
    return this;
}
var getName;
//只提升变量声明

function getName() { alert (5);}
//提升函数声明,覆盖var的声明

Foo.getName = function () { alert (2);};
getName = function () { alert (4);};
//最终的赋值再次覆盖function getName声明

getName();
//最终输出4

var getName 只提升变量声明

function getName 函数声明,覆盖var的声明

第二个答案

直接调用getName()函数,就是访问当前上文作用域内的叫getName的函数

file

这样var getName提升,函数整体提升到上面了,那么就剩下getName结果为4的那个了。

第三个问是:// 1

一个是变量作用域问题,一个是this指向问题。

Foo().getName();

第一个Foo()函数:

function Foo() {
 getName = function() {
  console.log('1');
 }
}

即Foo().getName()中

file

先执行Foo()函数,然后调用Foo函数返回的返回值对象的getName属性函数。

file

第四个:

getName(); // 函数 1

相当于window.getName(),因为这个变量被Foo函数执行时修改了,结果同样为1。

file

五问:

new Foo.getName();

file

点 . 的优先级高于new操作,等价于:

new (Foo.getName)();
// 将getName函数作为了构造函数来执行
// 2

六的答案:

file

new Foo().getName(); // 3
// 运算符优先级括号高于new

等价于
(new Foo()).getName()

先执行Foo函数,此时作为构造函数,有返回值。

file

若有返回值则检查其返回值是否为引用类型

file

若返回值是引用类型,则实际返回值为这个引用类型。

file

价于
(new Foo()).getName()
# ```
![file](https://oscimg.oschina.net/oscnet/up-64360182130dc0753ebfeff18e85123859c.png)

new new Foo().getName();

new ((new Foo()).getName)();

// 3



## ❤️ 不要忘记留下你学习的脚印 [点赞 + 收藏 + 评论]

作者Info:

> 【作者】:Jeskson
> 【原创公众号】:达达前端小酒馆。
> 【福利】:公众号回复 “资料” 送自学资料大礼包(进群分享,想要啥就说哈,看我有没有)!
> 【转载说明】:转载请说明出处,谢谢合作!~

大前端开发,定位前端开发技术栈博客,PHP后台知识点,web全栈技术领域,数据结构与算法、网络原理等通俗易懂的呈现给小伙伴。谢谢支持,承蒙厚爱!!!

----
若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

----
## 请点赞!因为你们的赞同/鼓励是我写作的最大动力!
### 欢迎关注[达达](https://blog.csdn.net/qq_36232611)的CSDN!

**这是一个有质量,有态度的博客**

![前端技术栈](https://oscimg.oschina.net/oscnet/up-029f80e8b1b464677fbac79a7cde7dd11ce.png)

© 著作权归作者所有

达达前端
粉丝 4
博文 226
码字总数 368531
作品 0
广州
程序员
私信 提问
加载中

评论(0)

JS基础总结(2)——原型与原型链

前言 农历2019即将过去,趁着年前几天上班事情少,整理了一下javascript的基础知识,在此给大家做下分享,喜欢的大佬们可以给个小赞。本文在github也做了收录。 本人github: github.com/Mich...

lzg9527
01/20
0
0
如何理解JavaScript的原型和原型链?

之前有朋友在公众号给我留言,问问怎么去理解原型和原型链的问题。这个问题,在面试中,很多同学经常都会遇到。 回复多了,觉得大家对这块知识点理解还是不够深。于是决定今天来给大家讲讲,...

WEB开发阿靖
2018/12/07
0
0
如果再被问到原型和原型链......

求职过程中,经常会被问到关于原型和原型链,就问题本身而言并不难,主要是考察对JavaScript核心概念的理解,但如何能够说明白确实需要认真准备下。 我印象比较深刻的一次,有个面试官出了一...

我是一尾
2019/09/22
0
0
2020面试收获 - js原型及原型链

一、前言 2020年是特殊的一年,由于疫情原因,大家都窝在家办公。而我则怀着梦想,从天津来到了北京,开启了人生的第一次跳槽。 在面试过程中,频频被原型相关知识问住,每次回答都支支吾吾。...

菜鸡小前端
03/16
0
0
我还没搞懂 JS 中this指向及继承,直到有人向我这样解释它

在理解继承之前,需要知道 js 的三个东西: 什么是 JS 原型链 this 的值到底是什么 JS 的new 到底是干什么的 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 一、什么是 JS...

前端小智
2019/06/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

第二天

独立工程就是打成一个war包,war包可以部署到不同的服务器中; 聚合工程至少有一个是war包,去除web后manager聚合工程剩余dao、service、pojo、interface,把service改成war包 main下加入web...

七宝1
30分钟前
15
0
开源:从“复兴”走向“商业化”

在美国版“知乎”Quora上搜“Open Source(开源)”,出来第一条问题是: “Linux的失败真的是因为开源吗?”。其中一个回答给我很多启发: “有些人把安卓和Chrome OS的成功归结于Linux开源...

编辑部的故事
55分钟前
256
0
JavaScript等同于printf / String.Format - JavaScript equivalent to printf/String.Format

问题: I'm looking for a good JavaScript equivalent of the C/PHP printf() or for C#/Java programmers, String.Format() ( IFormatProvider for .NET). 我正在寻找一个等效于C / PHP p......

javail
今天
27
0
什么是Android上的“上下文”? - What is 'Context' on Android?

问题: In Android programming, what exactly is a Context class and what is it used for? 在Android编程中, Context类到底是什么?它的用途是什么? I read about it on the developer......

技术盛宴
今天
26
0
OkHttp配置HTTPS访问+服务器部署

1 概述 OkHttp配置HTTPS访问,核心为以下三个部分: sslSocketFactory() HostnameVerifier X509TrustManager 第一个是ssl套接字工厂,第二个用来验证主机名,第三个是证书信任器管理类.通过OkHtt...

氷泠
今天
26
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部