JavaScript Basic Memo
1、this 的指向
1)、由 new 调用?绑定到新创建的对象。
2)、 由 call 或者 apply(或者 bind)调用?绑定到指定的对象。
3)、 由上下文对象调用?绑定到那个上下文对象。
4)、 默认:在严格模式下绑定到 undefined,否则绑定到全局对象。
2、new关键字的过程
- 创建一个新对象
- 将 this 绑定到新创建的对象上
- 在新创建的对象上添加一个叫 __proto__ 的属性,指向构造函数的原型 prototype 对象
- 返回新创建的对象 return this
- function Student(name, age) {
- this.name = name;
- this.age = age;
- }
- var first = new Student('John', 26);
- function Student(name, age) {
创建了一个新对象 —— first 对象
this 绑定到 first 对象。所有 this 引用指向 first。
添加__proto__。first.__proto__ 现在指向 Studnet.prototype。
所有事情完成后,我们将新的 first 对象返回出来赋值给新的 first 变量。
3、call、apply 和 bind 的区别
共同点:都是改变代码运行时的上下文
不同点:apply 接收一个包含多个参数的数组,而 call 与 bind 接收的是若干个参数的列表,另外 bind 会创建一个被初始化参数改造的新函数
- // 一个简单的实现
- Function.prototype.bind = function(ctx) {
- var fn = this;
- return function() {
- fn.apply(ctx, arguments);
- }
- // ......
- }
4、获取对象属性的方法
Object.getOwnPropertyNames vs Object.keys
- var a = {};
- Object.defineProperties(a, {
- one: {enumerable: true, value: 'one'},
- two: {enumerable: false, value: 'two'},
- });
- // 只能获取 enumerable 为 true 即可枚举的属性
- // ["one"]
- Object.keys(a);
- // 可不可枚举都能得到
- // ["one", "two"]
- Object.getOwnPropertyNames(a);
5、闭包
定义:是一个由函数和其词法作用域绑定在一起所形成的组合结构
特征:函数可以记住并访问其词法作用域,即时函数在当前的词法作用域外执行也可以
栗子:
- function Eat() {
- var desc = ' is eating';
- function eat(animal) {
- console.log(animal.name + desc);
- }
- return eat;
- }
- var eat = Eat();
- //全局变量
- var desc = '正在吃...';
- var dog = {name: 'dog'};
- // 闭包里的词法作用域(又叫静态作用域)是在函数创建时就和函数绑定了
- // 知道输出结果了吧!
- eat(dog);
- // 还不明白,看这个
- var x = 1;
- function foo() {
- console.log(x);
- }
- function bar(fn) {
- var x = 2;
- fn();
- }
- //输出?
- bar(foo);
应用:模块加载器
- var MyModules = (function Manager(){
- var modules = {};
- function define(name, deps, impl) {
- for(var i=0; i<deps.length; i++) {
- deps[i] = modules[deps[i]];
- }
- modules[name] = impl.apply( impl, deps );
- }
- function get(name) {
- return modules[name];
- }
- return {
- define: define,
- get: get
- };
- })();
6、怎么理解JS模块化?有没有使用过webpack?
优点:提高代码的可维护性、可重用性,避免污染命名空间
7、怎么弥补 CSS in JS 不支持嵌套、keyframes、媒体查询等特性的缺陷 ?
使用 styled-components,它的实现原理是使用 ES6的模板字符串特性,解决了在 JSX 中编写 CSS 的各种问题,由于它最终是在 head 里插入 style,所以它支持所有 CSS 特性,同时又能获取 JS 强大的控制力,具体详情戳这里styled-components 背后的魔法
8、requestAnimationFrame 优化原理
requestAnimationFrame 会自动匹配 W3C 所建议的刷新频率,既不会因为频率太高,增加开销,也不会频率太低,造成动画丢帧卡顿。
优点:
- requestAnimationFrame 会把每一帧中所有的 DOM 操作使用 DocumentFragment 集中起来,在一次重绘或回流中完成
- 在隐藏或不可见的元素中,
requestAnimationFrame
将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量 - 如果页面不是激活状态下的话,会暂停调用来提升性能和电池寿命。
9、怎么突破 localStorage 的容量限制
- localstorage的跨域存储方案,使用postMessage
- IndexedDB 用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索。
10、Event Loop 原理
当 js 代码执行时会将不同的变量存到堆(heap)和栈(stack)中。其中,堆中存放着一些对象,而栈中则存放着一些基础类型变量以及对象的指针。
而执行栈是指当一系列方法被依次调用的时候,因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个单独的地方。这个地方被称为执行栈。
当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境,这个过程反复进行,直到执行栈中的代码全部执行完毕。
当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。
这个过程需记住当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
以下事件属于宏任务:
setInterval()
setTimeout()
以下事件属于微任务
new Promise()
new MutaionObserver()
那么,下面这段代码的结果是 ?
- setTimeout(function () {
- console.log(1);
- });
- new Promise(function(resolve,reject){
- console.log(2)
- resolve(3)
- }).then(function(val){
- console.log(val);
- })
- // 2 3 1
详细规则为:
当一个程序有:setTimeout, setInterval ,setImmediate, I/O, UI渲染,Promise ,process.nextTick, Object.observe, MutationObserver的时候:
1.先执行 macrotasks:I/O -》 UI渲染-》requestAnimationFrame
2.再执行 microtasks :process.nextTick -》 Promise -》MutationObserver ->Object.observe
3.再把setTimeout setInterval setImmediate【三个货不讨喜】 塞入一个新的macrotasks,依次:setTimeout ,setInterval --》setImmediate
- setImmediate(function(){
- console.log(1);
- },0);
- setTimeout(function(){
- console.log(2);
- },0);
- new Promise(function(resolve){
- console.log(3);
- resolve();
- console.log(4);
- }).then(function(){
- console.log(5);
- });
- console.log(6);
- process.nextTick(function(){
- console.log(7);
- });
- console.log(8);
- // 结果是:3 4 6 8 7 5 2 1
11、Vue.js 中 nextTick 的实现原理
当观察到数据变化时,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会一次推入到队列中。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际(已去重的)工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MutationObserver,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。
Vue源码详解之nextTick:MutationObserver只是浮云,microtask才是核心! · Issue #6 · Ma63d/vue-analysis
12、Vue 实现原理
vue
将data
初始化为一个Observer
并对对象中的每个值,重写了其中的get
、set
,data
中的每个key
,都有一个独立的依赖收集器。- 在
get
中,向依赖收集器添加了监听 - 在mount时,实例了一个
Watcher
,将收集器的目标指向了当前Watcher
- 在
data
值发生变更时,触发set
,触发了依赖收集器中的所有监听的更新,来触发Watcher.update
- const Observer = function(data) {
- // 循环修改为每个属性添加get set
- for (let key in data) {
- defineReactive(data, key);
- }
- }
- const defineReactive = function(obj, key) {
- // 局部变量dep,用于get set内部调用
- const dep = new Dep();
- // 获取当前值
- let val = obj[key];
- Object.defineProperty(obj, key, {
- // 设置当前描述属性为可被循环
- enumerable: true,
- // 设置当前描述属性可被修改
- configurable: true,
- get() {
- console.log('in get');
- // 调用依赖收集器中的addSub,用于收集当前属性与Watcher中的依赖关系
- dep.depend();
- return val;
- },
- set(newVal) {
- if (newVal === val) {
- return;
- }
- val = newVal;
- // 当值发生变更时,通知依赖收集器,更新每个需要更新的Watcher,
- // 这里每个需要更新通过什么断定?dep.subs
- dep.notify();
- }
- });
- }
- const observe = function(data) {
- return new Observer(data);
- }
- const Vue = function(options) {
- const self = this;
- // 将data赋值给this._data,源码这部分用的Proxy所以我们用最简单的方式临时实现
- if (options && typeof options.data === 'function') {
- this._data = options.data.apply(this);
- }
- // 挂载函数
- this.mount = function() {
- new Watcher(self, self.render);
- }
- // 渲染函数
- this.render = function() {
- with(self) {
- _data.text;
- }
- }
- // 监听this._data
- observe(this._data);
- }
- const Watcher = function(vm, fn) {
- const self = this;
- this.vm = vm;
- // 将当前Dep.target指向自己
- Dep.target = this;
- // 向Dep方法添加当前Wathcer
- this.addDep = function(dep) {
- dep.addSub(self);
- }
- // 更新方法,用于触发vm._render
- this.update = function() {
- console.log('in watcher update');
- fn();
- }
- // 这里会首次调用vm._render,从而触发text的get
- // 从而将当前的Wathcer与Dep关联起来
- this.value = fn();
- // 这里清空了Dep.target,为了防止notify触发时,不停的绑定Watcher与Dep,
- // 造成代码死循环
- Dep.target = null;
- }
- const Dep = function() {
- const self = this;
- // 收集目标
- this.target = null;
- // 存储收集器中需要通知的Watcher
- this.subs = [];
- // 当有目标时,绑定Dep与Wathcer的关系
- this.depend = function() {
- if (Dep.target) {
- // 这里其实可以直接写self.addSub(Dep.target),
- // 没有这么写因为想还原源码的过程。
- Dep.target.addDep(self);
- }
- }
- // 为当前收集器添加Watcher
- this.addSub = function(watcher) {
- self.subs.push(watcher);
- }
- // 通知收集器中所的所有Wathcer,调用其update方法
- this.notify = function() {
- for (let i = 0; i < self.subs.length; i += 1) {
- self.subs[i].update();
- }
- }
- }
- const vue = new Vue({
- data() {
- return {
- text: 'hello world'
- };
- }
- })
- vue.mount(); // in get
- vue._data.text = '123'; // in watcher update /n in get
13、跨域解决方案
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
16、前端优化的方法
参考:
http://www.ayqy.net/blog/%E5%89%8D%E7%AB%AF%E4%BC%98%E5%8C%96%EF%BC%9A%E9%9B%85%E8%99%8E35%E6%9D%A1/
JavaScript Basic Memo的更多相关文章
- Javascript Basic Operation Extraction
1. logic operation : '&&' and '||' .For this two logic operations,its' results are inconcl ...
- JavaScript Basic
Exercise-1 Write a JavaScript program to display the current day and time in the following format. T ...
- CSS Basic Memo
1.bootstrap 清除浮动原理 .clearfix:before, .clearfix:after { content: ' ', display: table } .clearfix:afte ...
- Chapter 2 JavaScript Basic
Has 5 primitive types: Undefined, Null, Boolean, String, Number. typeof operator Undefined return u ...
- JavaScript 的基本语法
说明:此类博客来自以下链接,对原内容做了标注重点知识,此处仅供自己学习参考! 来源:https://wangdoc.com/javascript/basic/introduction.html 1. ...
- JavaScript 语言的历史
说明:此类博客来自以下链接,对原内容做了标注重点知识,此处仅供自己学习参考! 来源:https://wangdoc.com/javascript/basic/introduction.html 1.诞 ...
- JavaScript教程——JavaScript 的基本语法(标识符)
标识符 标识符(identifier)指的是用来识别各种值的合法名称.最常见的标识符就是变量名,以及后面要提到的函数名.JavaScript 语言的标识符对大小写敏感,所以a和A是两个不同的标识符. ...
- JavaScript的发展史
一.JavaScript发展历程 1. 诞生 JavaScript因互联网而生,紧跟浏览器的发展而发展. 1990年,欧洲核能研究所(CERN)科学家在互联网(Internet)基础上,发明了 ...
- JavaScript入门-学习笔记(一)
JavaScript入门(一) 学习js之前,我们先来了解一下,什么是JavaScript? JavaScript是一种解释型语言.在运行的时候,一边读一边编译一边执行.简单来说就是,在执行js代码时 ...
随机推荐
- python学习之文本文件上传
最近用python的flask框架完成了一个最基本的文本文件上传,然后读取. 前端用的Angular的ng2-file-upload完成文件上传,后端用flask接收上传的文件,接着做处理. 在交互的 ...
- textfield reload issue and other things reload problem.===================================
https://github.com/flutter/flutter/issues/18828 https://blog.csdn.net/u011272795/article/details/830 ...
- 2、Storm中的一些概念理解
1.Tuple,Value,Field Tuple官方解释: "A tuple is a named of values where each value can be any type.& ...
- MyElasticsearch
目录 那些必须要知道的事儿 搭建elasticsearch环境 快速上手 elasticsearch分析数据的过程漫谈 建议器:Suggester IK中文分词器 elasticsearch for ...
- 【mac微信小助手】WeChatPlugin使用教程!
微信小助手 mac版集微信防撤回和微信多开等诸多功能于一身,可以有效的阻止朋友微信撤回消息,还能开启无手机验证登录,再也不用每次登录扫码验证啦,非常方便! wechatplugin mac版安装教 ...
- 将项目添加到服务上时报web modules的错误
将项目添加到服务上时报web modules的错误如下图: 这是tomcat的版本和web modules的版本不支持造成的,如果在如下地方修改不了: 这时候就要在项目的根目录修改如下图: 用工具打开 ...
- centos卸载mysql
1.查看系统安装mysql rpm -qa|grep -i mysql 2.卸载 rpm -ev --nodeps mysql-community-release-el7-5.noarch 3.查询剩 ...
- HBase Filter及对应Shell
比较运算符 CompareFilter.CompareOp比较运算符用于定义比较关系,可以有以下几类值供选择: EQUAL 相等 GREATER 大于 GREATER_OR_EQUAL 大于等于 LE ...
- HTML与CSS的一些知识(三)
CSS: 1.三大样式:行内(内嵌).内部(内联).外部(外联):基本都知道. 2.三大特性: a.继承性:父级样式会被子级继承(!important不会被继承,<a></a> ...
- 20175312 2018-2019-2 《Java程序设计》第9周学习总结
20175312 2018-2019-2 <Java程序设计>第9周学习总结 教材学习内容总结 已依照蓝墨云班课的要求完成了第九章的学习,主要的学习渠道是PPT,和书的课后习题. 总结如下 ...