【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),是一 ...
随机推荐
- boostrap3 bootstrap-datetimepicker.min.js设置中文语言
问题 bootstrap3中使用bootstrap-datetimepicker遇到设置中文语言的问题 解决办法 bootstrap-datetimepicker在使用的时候要先引入momentjs中 ...
- Java实现生产者消费者(一)
问题描述:生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时 ...
- vuex和localStorage,全局变量的区别
vuex是状态管理,是为了解决跨组件之间数据共享问题的,一个组件的数据变化会映射到使用这个数据的其他组件当中.如果刷新页面,之前存储的vuex数据全部都会被初始化掉. localStorage是H5提 ...
- 神奇的 SQL 之扑朔迷离 → ON 和 WHERE,好多细节!
开心一刻 楼主:心都让你吓出来了! 狮王:淡定,打个小喷嚏而已 前情回顾 神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(一)中,我们讲到了 3 种联表算法:SNL.BNL 和 I ...
- Go组件学习:如何读取ini配置文件
代码示例全部保存在,欢迎star:https://github.com/EnochZg/golang-examples 安装组件 go get gopkg.in/ini.v1 使用 先创建ini后缀的 ...
- [poj1062][最短路]昂贵的聘礼
(最近总是有想让我的小博客更加充实的冲动,遇见一个不平常的题就想写下来.今天这个题姑且算是同学推荐的好题,很有意思,志之) 题目 题面 年轻的探险家来到了一个印第安部落里.在那里他和酋长的女儿相爱了, ...
- mysql中实现更新数据+1,再次更新数据-1
$sql="update article set comment=comment^1 where a_id=2"; 这条语句你会发现当你更新comment字段时为1,再次更新时为0 ...
- 记录一个引用文件所有js文件的方法
在项目api声明的时候,避免每次添加新的js都要对应去处理 首先我在项目api文件下新建一个files的文件夹,然后再api文件夹下的index.js这样写: var api = {}; const ...
- js Vquery
// JavaScript Document function myAddEvent(obj,sEv,fn){ alert('fn:'+fn); if(obj.attachEvent){ obj.at ...
- 【TIJ4】第四章全部习题
第四章 没啥好说的...... 4.1 package ex0401; //[4.1]写一个程序打印从1到100的值 public class PrintOneToHundred { public s ...