关于构造函数和原型链运行机制的试题与知识点总结

2024-08-22 03:58

本文主要是介绍关于构造函数和原型链运行机制的试题与知识点总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目:

  • 如何准确判断一个变量是数组类型
  • 写一个原型链继承的例子
  • 描述new一个对象的过程
  • zepto(或其他框架)源码中如何使用原型链

知识点:

1. 构造函数

  • 构造函数要用大写字母开头
  • var a=其实是var a=new Object)的语法糖
  • var a=[]其实是var a=new Array)的语法糖
  • function Foo){…}其实是var Foo=new Function(.)
  • 使用instanceof 可以判断一个函数是否是一个变量的构造函数

a71efaafly1g2rc6awjmxj20mf0dzwhx.jpg

2. 原型规则和示例

  • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了“null"意外)
  • 所有的引用类型(数组、对象、函数),都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
  • 所有的函数,都有一个prototype(显式原型)属性,属性值也是一个普通的对象
  • 所有的引用类型(数组、对象、函数),_proto_属性值指向它的构造函数的"prototype"属性值

a71efaafly1g2rchgklygj20mg0e4dk5.jpg

  • 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。

    我们在一个构造函数的显式原型上去定义方法可以有效的减少内存占用,因为如果我们定义在构造函数内部,则每实例化一个对象,就会开辟一个堆内存去存放挂载到其实例上,然而对于方法的调用这是没有必要的

关于 prototype 它有以下几个要点,务必牢记:

  1. 每一个函数(类)都有原型属性,称作prototype,这个属性提供了可供当前类的实例调用的属性和方法。
  2. 浏览器默认给原型开辟的堆内存中有一个constructor属性,这个属性存放的是函数本身
  3. 每一个对象的实例上都有一个__proto__属性称为原型链,这个属性指向当前类的所属原型,不确定的原型都指向Object.prototype,然而Object的__proto__指向null

prototype下的name属性指函数名,length属性指传入的形参的个数

a71efaafly1g2rcm3gp5cj20me0e377t.jpg

利用 for in 循环可以来获取对象身上自己定义的属性而不获取来自原型的属性

a71efaafly1g2rcrpqiwvj20mk0e0tbu.jpg

3. 原型链

当一个方法在原型上没有时,就会查找原型链

a71efaafly1g2rcwekrs7j20mj0du0vy.jpg
a71efaafly1g2rd0r86dzj20mm0drmyo.jpg

4. intanceof

intanceof 用于判断 引用类型 属于哪个 构造函数 的方法。

finstanceofFoo的判断逻辑是:

  1. f的__proto__一层一层往上,能否对应到Foo.prototype,只要 f.__proto__ == Foo.prototype 就验证通过
  2. 再试着判断 f instanceof Object
function Foo(name) {this.name = name
}
function Foo2() { }var f = new Foo('蔡徐坤');// 让Foo2的prototype指向Foo的prototype,这时候,Foo2与Foo的prototype可以看作为一个对象,也就是说修改Foo的prototype相当于修改Foo1的prototype,反之亦然
Foo2.prototype = Foo.prototype;
Foo.prototype.age = 'unknown';
Foo2.prototype.hobbies = '唱、跳、篮球、Rap';// 由下可以看出Foo2与Foo的prototype指向同一个对象
console.log(Foo.prototype); // Foo { age: 'unknown', hobbies: '唱、跳、篮球、Rap' }
console.log(Foo2.prototype); //Foo { age: 'unknown', hobbies: '唱、跳、篮球、Rap' }// 由于实例 f 的 __proto__ 指向 Foo 的 prototype ,而Foo的 prototype 与 Foo2 的 prototype 是一个,所以 f 既属于 Foo 又属于 Foo2
console.log(f instanceof Foo); // true
console.log(f instanceof Foo2); // true

5. 关于原型重定向问题

先看下面的一个例子:

function fun(){this.a = 0;this.b = function(){alert(this.a);}
}
fun.prototype = {b: function(){this.a = 20;alert(this.a);},c: function(){this.a = 30;alert(this.a);}
}
var my_fun = new fun();
my_fun.b(); // 0
my_fun.c(); // this => my_fun.a = 30 ; 30

结果:0 30

my_fun.a 用来设置私有属性

my_fun.__proto__.a 用来设置公有属性

原型重定向导致的问题:

  1. 自己开辟的堆内存中没有constructor属性,导致类的原型构造函数缺失(解决:自己手动在堆内存中增加constructor属性)
  2. 当原型重定向后,浏览器默认开辟的那个类原型堆内存会被释放掉,如果之前已经存储了一些方法或属性,都会丢失(所以:内置累的原型不允许重定向到自己开辟的堆内存,因为内置类的原型上存在很多属性方法,重定向后都没了,这样是不被允许的;但浏览器对内置类有保护机制)
  3. 当我们需要给类的原型批量设置属性和方法的时候,一般都是让原型重定向到自己创建的对象中

解题:

1. 如何准确判断一个变量是数组类型

var arr = [];
console.log(arr instanceof Array); // true
console.log(typeof arr); // object 不能用typeof判断一个变量是否是数组类型

2. 写一个原型链继承的例子

基础实例:

//动物
function Animal(){this.eat = function(){console.Log('animal eat')}
}
//狗
function Dog(){this.bark = function(){console.Log('dog bark')}
}
Dog.prototype = new Animal()
//哈士奇
var hashiqi = new Dog()
//接下里代码演示时,会推荐更加贴近实战的原型继承示例!

封装DOM查询:戳我查看完整示例代码

function Elem(id) {this.elem = document.getElementById(id);
}Elem.prototype.html = function (html) {if (html == null) {return this.elem.innerHTML;} else {this.elem.innerHTML = html;return this; // 返回this,便于链式操作}
}Elem.prototype.on = function (eventType, fn) {if (eventType != null && fn != null) {this.elem.addEventListener(eventType, fn);return this;} else {throw new Error('请传入“事件类型”,“执行方法”!');}
}var div = new Elem('div');
div.on('click', function(){alert(div.html());
})

3. 描述new一个对象的过程

  • 创建一个新对象
  • this 指向这个新对象
  • 执行代码,即对this 赋值
  • 返回 this (这一步是默认的)

这篇关于关于构造函数和原型链运行机制的试题与知识点总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1095175

相关文章

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

前端知识点之Javascript选择输入框confirm用法

《前端知识点之Javascript选择输入框confirm用法》:本文主要介绍JavaScript中的confirm方法的基本用法、功能特点、注意事项及常见用途,文中通过代码介绍的非常详细,对大家... 目录1. 基本用法2. 功能特点①阻塞行为:confirm 对话框会阻塞脚本的执行,直到用户作出选择。②

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres