https://github.com/ltadpolesjavascript
4. 数组对象有哪些经常使用方法nginx
7. 什么是闭包,为何要用它github
8. 介绍一下 JavaScript 原型,原型链,它们有何特色web
11. 同步和异步的区别,怎么异步加载 JavaScript
14. apply()、call()和 bind() 是作什么的,它们有什么区别
22. export 与 export default有什么区别
6种原始数据类型:
true
和 false
Null
类型只有一个值: null
,特指对象的值未设置undefined
引用类型:Object
typeof
操做符:返回一个字符串,表示未经计算的操做数的类型
typeof
操做符对于简单数据类型,返回其自己的数据类型,函数对象返回function
,其余对象均返回Object
null
返回Object
A instanceof B
,返回一个Boolean
类型的值
instanceof
检测的是原型,只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪一种类型
let a = []; a instanceof Array // true a instanceof Object // true
变量a 的
__proto__
直接指向Array.prototype
,间接指向Object.prototype
,因此按照instanceof
的判断规则,a 就是Object
的实例.针对数组的这个问题,ES5 提供了Array.isArray()
方法 。该方法用以确认某个对象自己是否为 Array 类型
prototype
原型,而后再在 prototype
上添加一个 constructor
属性,并让其指向该函数的引用
null
和undefined
是无效的对象,所以是不会有constructor
存在的,这两种类型的数据须要经过其余方式来判断
函数的
constructor
是不稳定的,这个主要体如今自定义对象上,当开发者重写prototype
后,原有的constructor
引用会丢失,constructor
会默认为Object
function F() {}; var f = new F; f.constructor == F // true F.prototype = {a: 1} var f = new F f.constructor == F // false
在构造函数
F.prototype
没有被重写以前,构造函数F
就是新建立的对象f
的数据类型。当F.prototype
被重写以后,原有的constructor
引用丢失, 默认为 Object
所以,为了规范开发,在重写对象原型时通常都须要从新给
constructor
赋值,以保证对象实例的类型不被篡改
Object
的原型方法,调用该方法,默认返回当前对象的 [[Class]]
。这是一个内部属性,其格式为 [object Xxx]
,其中 Xxx
就是对象的类型Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(11) ; // [object Number] Object.prototype.toString.call(true) ; // [object Boolean] Object.prototype.toString.call(Symbol()); //[object Symbol] Object.prototype.toString.call(undefined) ; // [object Undefined] Object.prototype.toString.call(null) ; // [object Null] Object.prototype.toString.call(new Function()) ; // [object Function] Object.prototype.toString.call([]) ; // [object Array]
null
表示"没有对象",即该处不该该有值
典型用法:
undefined
表示"缺乏值",就是此处应该有一个值,可是尚未定义
典型用法:
undefined
undefined
undefined
undefined
修改器方法:
访问方法:
迭代方法:
undefined
true
,不然返回 falsetrue
,不然返回 falsetrue
的数组元素放进一个新数组中并返回更多方法请参考 MDN 传送门
对象字面量
var obj = {}
Object 构造函数
var obj = new Object()
工厂模式
function Person(name, age) { var o = new Object() o.name = name; o.age = age; o.say = function() { console.log(name) } return o }
缺点: 每次经过Person
建立对象的时候,全部的say
方法都是同样的,可是却存储了屡次,浪费资源
构造函数模式
function Person(name, age) { this.name = name this.age = age this.say = function() { console.log(name) } } var person = new Person('hello', 18)
构造函数模式隐试的在最后返回return this
因此在缺乏new
的状况下,会将属性和方法添加给全局对象,浏览器端就会添加给window
对象,能够根据return this
的特性调用call
或者apply
指定this
原型模式
function Person() {} Person.prototype.name = 'hanmeimei'; Person.prototype.say = function() { alert(this.name); } Person.prototype.friends = ['lilei']; var person = new Person();
实现了方法与属性的共享,能够动态添加对象的属性和方法。可是没有办法建立实例本身的属性和方法,也没有办法传递参数
构造函数和原型组合
function Person(name, age) { this.name = name this.age = age } Person.prototype.say = function() { console.log(this.name) } var person = new Person('hello')
还有好几种模式,感兴趣的小伙伴能够参考 红宝书,大家确定知道的了!
浅拷贝
Array.prototype.slice()
也能够完成对一个数组或者对象的浅拷贝Object.assign()
方法深拷贝
JSON.parse(JSON.stringify(目标对象)
,缺点就是只能拷贝符合JSON
数据标准类型的对象更多参考 JavaScript 中的浅拷贝与深拷贝
简单来讲,闭包就是可以读取其余函数内部变量的函数
function Person() { var name = 'hello' function say () { console.log(name) } return say() } Person() // hello
因为 JavaScript 特殊的做用域,函数外部没法直接读取内部的变量,内部能够直接读取外部的变量,从而就产生了闭包的概念
用途:
最大用处有两个,一个是前面提到的能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中
注意点:
因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露
更多参考 JavaScript 中的闭包
首先明确一点,JavaScript是基于原型的
每一个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针.
图解:
prototype
属性,这个属性指向一个对象,也就是原型对象constructor
属性,指向指向它的那个构造函数[[prototype]]
,指向它的原型对象那么什么是原型链:
JavaScript
中全部的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有本身的原型对象,这样层层上溯,就造成了一个相似链表的结构,这就是原型链
全部原型链的终点都是
Object
函数的prototype
属性。Objec.prototype
指向的原型对象一样拥有原型,不过它的原型是null
,而null
则没有原型
更多参考 JavaScript 中的原型与原型链
function Animal() {} Animal.prototype.name = 'cat' Animal.prototype.age = 1 Animal.prototype.say = function() {console.log('hello')} var cat = new Animal() cat.name // cat cat.age // 1 cat.say() // hello
最简单的继承实现方式,可是也有其缺点
new
语句以后执行,不能放到构造器中function Animal() { this.species = "动物" } function Cat(name, age) { Animal.call(this) this.name = name this.age = age } var cat = new Cat('豆豆', 2) cat.name // 豆豆 cat.age // 2 cat.species // 动物
使用call或apply方法,将父对象的构造函数绑定在子对象上.
function Animal() { this.species = "动物" } function Cat(name){ Animal.call(this) this.name = name } Cat.prototype = new Animal() // 重写原型 Cat.prototype.constructor = Cat
若是没有
Cat.prototype = new Animal()
这一行,Cat.prototype.constructor
是指向Cat
的;加了这一行之后,Cat.prototype.constructor
指向Animal
.这显然会致使继承链的紊乱(cat1明明是用构造函数Cat生成的),所以咱们必须手动纠正,将Cat.prototype
对象的constructor
值改成Cat
extends
继承 ES6新增继承方式,Class 能够经过extends关键字实现继承class Animal { } class Cat extends Animal { constructor() { super(); } }
使用
extends
实现继承,必须添加super
关键字定义子类的constructor
,这里的super()
就至关于Animal.prototype.constructor.call(this)
固然,还有不少种实现继承的方式,这里就很少说了。而后,再推荐一波 红宝书
更多参考 JavaScript 中的继承
同步模式
同步模式,又称阻塞模式。javascript
在默认状况下是会阻塞加载的。当前面的 javascript
请求没有处理和执行完时,会阻止浏览器的后续处理
异步模式
异步加载又叫非阻塞,浏览器在下载执行 js
同时,还会继续进行后续页面的处理
异步加载 JavaScript
script
标签defer
async
defer
属性和async
都是属于script
标签上面的属性,二者都能实现JavaScript
的异步加载。不一样之处在于:async
在异步加载完成的时候就立刻开始执行了,defer
会等到html
加载完毕以后再执行
因为浏览器的 同源策略,在出现 域名、端口、协议有一种不一致时,就会出现跨域,属于浏览器的一种安全限制。
解决跨域问题有不少种方式,经常使用的就是如下几种:
jsonp
跨域:动态建立script
,再请求一个带参网址实现跨域通讯.缺点就是只能实现 get
一种请求document.domain + iframe
跨域:两个页面都经过js强制设置document.domain
为基础主域,就实现了同域.可是仅限主域相同,子域不一样的跨域应用场景Access-Control-Allow-Origin
便可,前端无须设置,若要带cookie
请求:先后端都须要设置nginx
反向代理接口跨域:同源策略是浏览器的安全策略,不是HTTP
协议的一部分。服务器端调用HTTP
接口只是使用HTTP
协议,不会执行JS脚本,不须要同源策略,也就不存在跨越问题WebSocket
协议跨域在 JavaScript
中,研究 this
通常都是 this
的指向问题,核心就是 this
永远指向最终调用它的那个对象,除非改变 this
指向或者箭头函数那种特殊状况
function test() { console.log(this); } test() // window var obj = { foo: function () { console.log(this.bar) }, bar: 1 }; var foo = obj.foo; var bar = 2; obj.foo() // 1 foo() // 2 // 函数调用的环境不一样,所获得的结果也是不同的
相同点:三者均可以改变 this 的指向
不一样点:
var obj = { name : 'sss' } function func(firstName, lastName){ console.log(firstName + ' ' + this.name + ' ' + lastName); } func.apply(obj, ['A', 'B']); // A sss B
call
方法第一个参数也是做为函数上下文的对象,可是后面传入的是一个参数列表,而不是单个数组var obj = { name: 'sss' } function func(firstName, lastName) { console.log(firstName + ' ' + this.name + ' ' + lastName); } func.call(obj, 'C', 'D'); // C sss D
bind
接受的参数有两部分,第一个参数是是做为函数上下文的对象,第二部分参数是个列表,能够接受多个参数var obj = { name: 'sss' } function func() { console.log(this.name); } var func1 = func.bind(null, 'xixi'); func1();
apply
、call
方法都会使函数当即执行,所以它们也能够用来调用函数
bind
方法不会当即执行,而是返回一个改变了上下文this
后的函数。而原函数func
中的this
并无被改变,依旧指向全局对象window
bind
在传递参数的时候会将本身带过去的参数排在原函数参数以前
function func(a, b, c) { console.log(a, b, c); } var func1 = func.bind(this, 'xixi'); func1(1,2) // xixi 1 2
内存泄漏:是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束
可能形成内存泄漏的操做:
你可能还须要知道 垃圾回收机制 此外,高程上面对垃圾回收机制的介绍也很全面,有兴趣的小伙伴能够看看
事件代理:通俗来讲就是将元素的事件委托给它的父级或者更外级元素处理
原理:利用事件冒泡机制实现的
优势:只须要将同类元素的事件委托给父级或者更外级的元素,不须要给全部元素都绑定事件,减小内存空间占用,提高性能; 动态新增的元素无需从新绑定事件
AMD
和CMD
都是为了解决浏览器端模块化问题而产生的,AMD
规范对应的库函数有Require.js
,CMD
规范是在国内发展起来的,对应的库函数有Sea.js
AMD和CMD最大的区别是对依赖模块的执行时机处理不一样
一、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
二、CMD推崇就近依赖,只有在用到某个模块的时候再去require
ECMAScript 6.0 是 JavaScript 语言的下一代标准
新增的特性:
let
const
includes()
startsWith()
endsWith()
等Array.from()
Array.of()
entries()
keys()
values()
等Object.is()
Object.assign()
entries()
keys()
values()
等rest
参数、函数参数默认值等Set
和 Map
Proxy
Promise
对象async
函数 await
命令Class
类Module
体系 模块的加载和输出方式了解更多,参考 ES6入门-阮一峰
ES6 容许使用“箭头”(=>)定义函数
var f = v => v; // 等同于 var f = function (v) { return v; }
注意点:
this
对象,就是定义时所在的对象,而不是使用时所在的对象new
命令,不然会抛出一个错误arguments
对象,该对象在函数体内不存在。若是要用,能够用 rest
参数代替Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.所谓Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果 --ES6入门-阮一峰
Promise
对象表明一个异步操做,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操做的结果,能够决定当前是哪种状态,任何其余操做都没法改变这个状态
特色:
Promise
新建后就会当即执行const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操做成功 */){ resolve(value); } else { reject(error); } })
Promise实例生成之后,能够用then方法分别指定resolved状态和rejected状态的回调函数
promise.then(function(value) { // success }, function(error) { // failure })
then
方法返回的是一个新的Promise实例
Promise.prototype.catch
用于指定发生错误时的回调函数,具备“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误老是会被下一个catch
语句捕获
getJSON('/post/1.json').then(function(post) { return getJSON(post.commentURL); }).then(function(comments) { // some code }).catch(function(error) { // 处理前面三个Promise产生的错误 });
catch
方法返回的仍是一个Promise
对象,所以后面还能够接着调用then
方法
出去上述方法,Promise还有其余用法,小伙伴们能够在这里查看大佬写的文章 ES6入门-阮一峰
async
函数是什么?一句话,它就是Generator
函数的语法糖
了解Generator函数的小伙伴,这里 传送门
async
特色:
async
函数返回一个Promise
对象,可使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操做完成,再接着执行函数体内后面的语句
async
函数内部return
语句返回的值,会成为then
方法回调函数的参数
async
函数返回的Promise
对象,必须等到内部全部await
命令后面的Promise
对象执行完,才会发生状态改变,除非遇到return
语句或者抛出错误
async
函数内部抛出错误,会致使返回的Promise
对象变为reject
状态。抛出的错误对象会被catch
方法回调函数接收到
function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('hello world', 50);
await
命令:await
命令后面是一个Promise
对象,返回该对象的结果。若是不是Promise
对象,就直接返回对应的值
async function f() { // 等同于 // return 123; return await 123; } f().then(v => console.log(v)) // 123
await
命令后面是一个thenable
对象(即定义then方法的对象),那么await
会将其等同于Promise
对象.也就是说就算一个对象不是Promise
对象,可是只要它有then
这个方法,await
也会将它等同于Promise
对象
使用注意点:
await
命令后面的 Promise
对象,运行结果多是 rejected
,因此最好把 await
命令放在 try...catch
代码块中await
命令后面的异步操做,若是不存在继发关系,最好让它们同时触发await
命令只能用在 async
函数之中,若是用在普通函数,就会报错了解更多,请点击 这里
export
与export default
都可用于导出常量、函数、文件、模块等
在一个文件或模块中,
export
、import
能够有多个,export default
仅有一个
经过
export
方式导出,在导入时要加{ }
,export default
则不须要
使用
export default
命令,为模块指定默认输出,这样就不须要知道所要加载模块的变量名;export
加载的时候须要知道加载模块的变量名
export default
命令的本质是将后面的值,赋给default
变量,因此能够直接将一个值写在export default
以后
参见 雅虎14条前端性能优化
首选明确两点:
JavaScript
是单线程语言
JavaScript
的Event Loop
是JS
的执行机制, 也就是事件循环
console.log(1) setTimeout(function(){ console.log(2) },0) console.log(3) // 1 3 2
JavaScript
将任务分为同步任务和异步任务,执行机制就是先执行同步任务,将同步任务加入到主线程,遇到异步任务就先加入到event table
,当全部的同步任务执行完毕,若是有可执行的异步任务,再将其加入到主线程中执行
视频详解,移步 这里
setTimeout(function(){console.log(1);},0); new Promise(function(resolve){ console.log(2); for(var i = 0; i < 10000; i++){ i == 99 && resolve(); } }).then(function(){ console.log(3) }); console.log(4); // 2 4 3 1
在异步任务中,定时器也属于特殊的存在。有人将其称之为 宏任务、微任务,定时器就属于宏任务的范畴。