【JavaScript】要点知识的个人总结(1)
米娜桑,哦哈哟~
该篇章主要基于链接中的参考内容和代码测试得出的结论,面向具有一定基础的前端开发者。如有错误,请指出与包涵。
原型链的解释
白话翻译:原型链就相当于对象上的一个链条,通过隐性原型属性__proto__ 将其他相关的属性绑定以达到引用的效果,其链条的终点就是 Object.prototype,这就是原型链。
class.prototype === obj.__proto__
Object.create()声明的对象
Object.create({name: 1}) 相当于在这个对象的链条上再增加一条链条__proto__,所以 Object.create(null) 的结果是没有任何隐藏属性非常纯净且可高度定制的 {} (一般用于一些开源项目),当然通过
let a = {}
a.__proto__ = null
也可以获得纯净的对象,不过生成的性能一般,通过以下代码实现 Object.create()。
function create(obj) {
let F = function () {}
F.prototype = obj
return new F()
}
function create(obj) {
let a = {}
a.__proto = obj
return a
}
Function.prototype.bind() 的特别之处
通过 Function.prototype.bind() 声明的函数不是 Function 的实例,故不存在class.prototype === obj.__proto__
;不过可以通过
Object.prototype.toString.call()
可以得知它依然是一个函数。
并与 Function.prototype 是一致的。
new
- new 的过程如下
创建有 Object 函数实例出来的空对象;
将该对象绑定到相应的构造函数上,其此为 this 的上下文,如果没有返回对象的话,就返回 this
function zxNew() {
let fn = arguments[0]
if (typeof fn !== 'function') {
throw new TypeError('first param must be a function')
}
Array.prototype.shift.call(arguments)
let obj = Object.create(null);
obj.__proto__ = fn.prototype;
let res = fn.apply(obj, arguments);
return res instanceof Object ? res : obj
}
原型链继承的方式
- https://juejin.im/post/5b654e88f265da0f4a4e914c
- https://github.com/mqyqingfeng/Blog/issues/16
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/extends
原型继承
function Parent () {
this.name = 'temax'
}
Parent.prototype.fn = function () {
console.log(233)
}
function Child () {}
Child.prototype = new Parent()
let child = new Child()
缺点:属性共享、不能传参
经典继承——使用 call 方法借用构造函数的方式
function Parent (name) {
this.name = name
}
Parent.prototype.fn = function () {
console.log(233)
}
function Child (name) {
Parent.call(this, name)
}
let child = new Child('temax')
缺点:不能继承prototype上的属性
组合继承——即原型链继承和经典继承的结合
function Parent(name) {
this.name = name
}
Parent.prototype.fn = function () {
console.log(233)
}
function Child(name) {
Parent.call(this, name)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
let child = new Child(1)
缺点:父类函数执行两次
组合继承的优化
function Parent(name) {
this.name = name
}
function.prototype.fn = function () {
console.log(233)
}
function Child(name) {
Parent.call(this, name)
}
Child.prototype = Parent.prototype
child.prototype.constructor = Child
let child = new Child()
缺点:prototype 的保存地址其实就是父级的保存地址,也就是说如果改变 child.prototype 会直接影响到父级的 prototype,所以需要加一个__proto__进行隔离
寄生组合的方式——比较理想的组合方式
function Parent(name) {
this.name = name
}
function.prototype.fn = function () {
console.log(233)
}
function Child(name) {
Parent.call(this, name)
}
Child.prototype = Object.create(Parent.prototype)
child.prototype.constructor = Child
class的继承方式
class Parent{
}
class Child extends Parent{
}
this的指向
- this永远指向最后调用的对象。
也就是说 a.b.c.fn(),那么 fn 里面的 this 的指向 c 的属性。
如果令 d = b.c.fn;则 a.d() 中的 this 是指向 a 的。 - setTimeout 的 function 中的 this 是指向 window 对象的。因为 setTimeout 实则为 window.setTimeout。
- 可通过定义this的变量来调用或使用 apply/call/bind 的方式改变 this 指向。
箭头函数的this
- 自身没有声明 this,所以会在作用域链上找最近的 this。
- 不可以当作构造函数。
- 不能用作 Generator 函数。
- 不能使用 arguments,arguments 可以用 ...rest 取代。
apply、call、bind
- 可以通过 apply 和 call 对对象进行调用, 使得函数内的 this 绑定到该调用的值。
- apply 和 call 的区别就是传入方式的不一样,前者是数组传参的方式,后者是直接传参的方式。
- bind 跟 call 一致,只不过 bind 会创建并返回一个新的函数。
- 实现机制如下
call (apply同理,只是改变参数的形式)
Function.prototype.call = function(){
if (typeof this !== 'function') {
throw new TypeError('Called object must be a function')
}
let obj = Object(arguments[0]) || window,
obj.fn = this,
result;
arr = arguments.slice();
arr.shift();
result = obj.fn(...arr)
delete obj.fn
return result
}
bind
如果要模仿 Function.prototype.bind() 得到的函数 fn,需要设置
fn.__proto__ = Object.prototype
fn.prototype = undifned
Function.prototype.bind1 = function () {
let fn = this;
if(typeof fn === 'function'){
if(fn !== Function.prototype){
let obj = Object(arguments[0]) || window,
args = Array.prototype.slice.call(arguments,1),
TempFn = function () {},
FnBind = function () {
//当使用new来构造函数(通过bind得到的)时,会忽略bind(obj)的obj
//对于这个的理解,应该结合new和call的实现来解释,这个时候的this是指向 Object.create(null),如果没有设置prototype的话
//因为原生得到的(new fn1) instanceof fn1 为 true,
// (new fn1) instanceof fn 也为 true,
//又因为 TempFn.prototype = fn.prototype;(只要满足 ojb.__proto__ === class.prototype.constructor)
//所以用改造后得到的 (new fn2) instanceof TempFn 为 true
//简单来说就是,当为构造函数的时候,这里的this是等于指向实例,而实例 instanceof fn1 为true, 实例 instanceof fn也为true,
//而只要满足 ojb.__proto__ === class.prototype
//那么 instanceof 得到的就是 true,所以可以用 this instanceof TempFn 来表示
let bindArgs = Array.prototype.slice.call(arguments);
return fn.apply(this instanceof TempFn ? this : obj, args.concat(bindArgs))
};
TempFn.prototype = fn.prototype;
FnBind.prototype = new TempFn;
return FnBind
}else {
fn.prototype = undefined
fn.__proto__ = Object.prototype
return fn
}
}else {
throw TypeError('Called object must be a function')
}
}
事件循环
- https://segmentfault.com/a/1190000004322358#comment-area
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop#运行时概念
- https://juejin.im/post/59e85eebf265da430d571f89
- https://segmentfault.com/a/1190000011198232
事件循环是和消息队列共同实现JS同步异步运行的机制。消息队列先进先出,一个循环里,先从队列中取出宏任务并执行,如果存在异步任务,便会将其回调函数注册发放到消息队列当中;再执行微任务,直到相应的执行栈为空为止;执行完后启动新的循环;事件循环是js的运行机制。
事件循环还分宏任务和微任务
- 宏任务:整体代码;setTimeout;setInterval,宏任务消息队列
微任务:Promise; process.nextTick,微任务消息队列 - 通过以下代码测试
setTimeout(function(){
console.log('定时器开始啦')
});
new Promise(function(resolve){
console.log('马上执行for循环啦');
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log('执行then函数啦')
});
console.log('代码执行结束');
节点操作
- 添加节点可以通过 appendChild
- 通过 innerText 对节点添加文本信息
- 也可以通过 innerHTML 对节点添加 html 文本
- 利用 document.createElement 添加对应元素。
- 通过 node.addEventListener(type,listener,capture) 添加事件。第三参数为是否捕获,默认false,即冒泡
- document 为最大的节点。
- 当然也可以通过 DocumentFragment 来减少 dom 操作
- 以下是 ul 元素添加 li 元素的例子
let ul = document.querySelector('.cul');
// let ul = document.querySelectorAll('.cul')[0];
let a = '';
function myFunction(e){console.log(e)}
for(let i=0;i<5;i++){
a += `<li onclick='myFunction(${i})'>${i}</li>`
}
ul.innerHTML = a
let ul = document.querySelectorAll('.cul')[0];
for(let i=0;i<5;i++){
let a = document.createElement('li');
a.innerHTML = i
a.addEventListener('click',function () {
console.log(i)
})
ul.appendChild(a)
}
let ul = document.querySelectorAll('.cul')[0];
let fragment = document.createDocumentFragment()
for(let i=0;i<5;i++){
let a = document.createElement('li');
a.innerHTML = i
a.addEventListener('click',function () {
console.log(i)
})
fragment.appendChild(a)
}
ul.appendChild(fragment)
【JavaScript】要点知识的个人总结(1)的更多相关文章
- Javascript基础知识总结一
Javascript基础知识总结一 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...
- javascript 要点
javascript 要点 1 JavaScript:写入 HTML 输出 document.write("<h1>This is a heading</h1>&qu ...
- 学习javascript基础知识系列第二节 - this用法
通过一段代码学习javascript基础知识系列 第二节 - this用法 this是面向对象语言中的一个重要概念,在JAVA,C#等大型语言中,this固定指向运行时的当前对象.但是在javascr ...
- 学习javascript基础知识系列第三节 - ()()用法
总目录:通过一段代码学习javascript基础知识系列 注意: 为了便于执行和演示,建议使用chrome浏览器,按F12,然后按Esc(或手动选择)打开console,在console进行执行和演示 ...
- javascript常用知识点集
javascript常用知识点集 目录结构 一.jquery源码中常见知识点 二.javascript中原型链常见的知识点 三.常用的方法集知识点 一.jquery源码中常见的知识点 1.string ...
- 七个开法者经常忽略或误用的JavaScript基本知识
七个开法者经常忽略或误用的JavaScript基本知识 翻译自 http://tech.pro/tutorial/1453/7-javascript-basics-many-developers-ar ...
- JavaScript 基础知识 - BOM篇
前言 本篇文章是JavaScript基础知识的BOM篇,如果前面的<JavaScript基础知识-DOM篇>看完了,现在就可以学习BOM了. 注意: 所有的案例都在这里链接: 提取密码密码 ...
- JavaScript数组知识
JavaScript数组知识 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- JS控制语句 编程练习 学生数据,分别是姓名、性别、年龄和年级,接下来呢,我们要利用JavaScript的知识挑出其中所有是大一的女生的的名字哦。
编程练习 在一个大学的编程选修课班里,我们得到了一组参加该班级的学生数据,分别是姓名.性别.年龄和年级,接下来呢,我们要利用JavaScript的知识挑出其中所有是大一的女生的的名字哦. 学生信息如下 ...
- AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解
AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解 javascriptvue-clicommonjswebpackast 阅读约 27 分钟 抽象语法树(AST),是一 ...
随机推荐
- 前端每日实战:147# 视频演示如何用纯 CSS 创作透视按钮的悬停特效
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/qJEdKb 可交互视频 此视频是可 ...
- 通读Python官方文档之cgitb
cgitb CGI脚本异常管理 源代码:Lib/cgitb.py cgitb模块为Python脚本提供了一个特殊的异常管理器.名字有点误导人,它最初设计是为了以HTML格式展示cgi脚本的大量异常信息 ...
- 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/ZRjGGy 可交互视频 此视频是可 ...
- 集成google翻译的小tips
文章首发于github.io 2018-08-04 12:43:20 google翻译的强大,就像我们公司的slogan : "让语言无国界,让世人心相通" 友情提示: googl ...
- idea新建springboot项目
不多说废话,直接进入正题,按照下面的步骤创建一个springboot项目一般不会出错,当然不排除可能会有一些脸黑的,不过应该问题不大. 第一步,如果你是在已有的项目里面,新建一个springboot项 ...
- 鸟哥的Linux私房菜基础学习篇(第三版)——阅读笔记(二)
第一章 Linux是什么 1.Linux是什么 一套操作系统 早期的Linux是针对386开发的 具有可移植性 2.Unix及Linux的发展史 1973年,Unix诞生,Ritchie等人以C语言写 ...
- 基于Redis未授权访问的挖矿蠕虫分析
0x01 攻击方式 利用的是通用漏洞入侵服务器并获得相关权限,从而植入挖矿程序再进行隐藏. 通过对脚本的分析,发现黑客主要是利用 Redis未授权访问漏洞进行入侵.脚本里有个python函数. imp ...
- IPFS(星际文件系统)-初步接触
〇.IPFS介绍 从HTTP到IPFS,星际文件系统能变革信息传播的方式吗? 戴嘉乐:详解IPFS的本质.技术架构以及应用 以下为实现相关摘要 1.存储 在IPFS中,信息可以存储进IPFS系统中的块 ...
- Python习题集(四)
每天一习题,提升Python不是问题!!有更简洁的写法请评论告知我! https://www.cnblogs.com/poloyy/category/1676599.html 题目 如果一个 3 位数 ...
- C/C++、C#、JAVA(二):基本类型和转换操作
基本类型和转换操作 数据类型 C语言中的基本类型如下. 类型 存储大小 值范围 char 1 字节 -128 到 127 或 0 到 255 unsigned char 1 字节 0 到 255 si ...