- 1. 构造函数的特点
- 2. 只有对象都有构造函数吗?
- 3. 如何判断一个函数是否为一个变量的构造函数?
- 4. 逗号运算符的规则
- 5. 说一下原型链
- 6. 描述new一个对象的过程?
- 7. 如何判断一个变量是数组类型?
- 8. 写一个原型链继承的例子
- 9. 函数方法中,forEach 和 map 的区别?
- 10. 日期 Math 数组 对象
- 11. 获取随机数,要求是长度一致的字符串格式
- 12. JS实现异步的几种方式
- 13. 构造json参数时key需要加引号吗?
- 14. 数组去重的方法
- 15. 将一个类数组对象转化为数组的几种方法
- 16. 什么是JS Engine(JS引擎)?
- 17. 对称加密和非对称加密算法
- 18. 如何在选择图片后,不经后端而显示预览图片?
- 19. Blob 和 ArrayBuffer
- 20. URL.createObjectURL()
- 21. 文件和二进制数据对象
- 22. fetch 发送2次请求的原因
- 23. 让坐标变化的2种方式
- 24.
requestAnimFrame
- 25.
onmouseenter
和onmouseover
对比 - 26. click 在 ios 上有300ms延迟,如何解决
- 27. PNG,GIF,JPG 的区别及如何选
- 28. 属性描述对象
- 29. 注意img的
onerror
属性: - 30. ajax解决浏览器缓存问题
- 31. 学习资料
# 1. 构造函数的特点
- 构造函数名称大写。
- 默认
return this
,写不写无所谓
function Foo(name,age){
this.name=name;
this.age = age;
this.class=1;
// return this
} // 默认就是return this,写不写无所谓
var f = new Foo('za',23)
console.log(f) // Foo {name: "za", age: 23, class: 1}
# 2. 只有对象都有构造函数吗?
所有的引用类型都有构造函数:
var a ={}
其实是var a = new Object()
的语法糖var a =[]
其实是var a = new Array()
的语法糖function Foo()
其实是var Foo = new Function()
(Function大写)
# 3. 如何判断一个函数是否为一个变量的构造函数?
应使用 instanceof
, typeof
不可以
var a = {}
a instanceof Object // true
判断引用类型还可以用 Object.prototype.toString.apply():
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call(function(){}) // "[object Function]"
注意:ie6/7下
Object.prototype.toString.apply(null) // [Object Object]
# 4. 逗号运算符的规则
逗号运算符,会从左到右依次计算表达式的值,最后取最右边的(每个都需要计算)
var s = (1,2,3)
console.log(s) // 3
# 5. 说一下原型链
五条原型规则
- 所有的引用类型(数组、对象、函数)都具有对象特性,即可自由扩展属性(除了null)
- 所有的引用类型(数组、对象、函数)都具有一个
__proto__
属性,属性值是一个普通对象(隐式原型) - 所有函数都有一个prototype属性,属性值也是一个普通对象(显式原型)
- 所有的引用类型(数组、对象、函数),
__proto__
属性值指向它的构造函数的 prototype 属性值 - 当试图得到一个引用类型的某个属性时,如果这个对象本身没有这个属性,那么会去它的
__proto__
中(即它的构造函数的 prototype )寻找
因此,获取实例对象obj
的原型对象,有三种方法。
obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf(obj)
上面三种方法之中,前两种都不是很可靠。__proto__
属性只有浏览器才需要部署,其他环境可以不部署。而obj.constructor.prototype
在手动改变原型对象时,可能会失效。
# 6. 描述new一个对象的过程?
- 创建一个对象
- this指向这个对象
- 执行代码,即对this赋值
- 返回this
# 7. 如何判断一个变量是数组类型?
var arr = []
arr instanceof Array; // true
# 8. 写一个原型链继承的例子
// 动物类
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()
hashiqi.eat() // animal eat
另一个例子:
// 获取元素的构造函数
function Elem(id){
this.elem = document.getElementById(id)
}
// 构造函数上的原型链上的方法
Elem.prototype.html = function(val){
var elem = this.elem;
if(val) {
elem.innerHTML = val;
return this;
} else {
return elem.innerHTML;
}
}
// 构造函数上的原型链上的方法
Elem.prototype.on = function(type,fn){
var elem = this.elem;
elem.addEventListener(type,fn);
return this
}
var div1 = new Elem('div1')
console.log(div1.html())
div1.html('<h1>gogo</h1>').on('click',function(){alert('clicked')}) //链式操作
div1.html('<h1>gogo</h1>').on('click',function({alert('clicked')}).html('<h1>nono</h1>')
# 9. 函数方法中,forEach 和 map 的区别?
- forEach()方法不会返回执行结果,而是undefined。
- 也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。
# 10. 日期 Math 数组 对象
# 11. 获取随机数,要求是长度一致的字符串格式
function getRandomNums(len = 10) {
var random = Math.random()
for (let i = 0; i < len; i ++) random += '*'
return random.slice(0, len)
}
// 更好的方法
function getRandomString() {
return Math.random()
.toString(36)
.substr(2)
}
// 比如,'ihen49kznl'
# 12. JS实现异步的几种方式
- callback
- 发布订阅模式
- Promise
- 生成器函数
- async/await
注意:await
在for
循环中才生效,forEach
不生效
# 13. 构造json参数时key需要加引号吗?
json不是最好加不加,而是必须加,而且加的是双引号。
# 14. 数组去重的方法
- indexOf循环去重
- ES6 Set去重;Array.from(new Set(array))
- Object 键值对去重;把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。
# 15. 将一个类数组对象转化为数组的几种方法
slice
Array.prototype.slice.call(arguments)
,或者[].slice.call(arguments)
亦可splice
Array.prototype.splice.call(arguments, 0);
Array.prototype.concat.apply([], arguments)
ES6中的
Array.from
语法:Array.from(arguments)
[...arguments]
# 16. 什么是JS Engine(JS引擎)?
处理并执行js代码的运行环境, 也就是专门处理Js脚本的虚拟机。
# 16.1. JS引擎中栈和堆
- 同其它编程语言(java)一样,JS引擎中也有堆(Heap)和栈(Stack)的概念
- 堆和栈都是内存中划分出来用来存储的区域,是一种数据结构,它基本记录了程序中的位置
- 栈(stack)为自动分配的内存空间,它由系统自动释放,用来存储方法和基本数据类型;
- 堆(heap)则是动态分配的内存,大小不定,也不会自动释放,用来存储引用数据类型;
基本数据类型存储
- 基本数据类型存放在栈中
- 栈内存中的简单数据,数据大小确定,内存空间大小可以分配,是直接按值存放的
引用数据类型
- 引用类型存放在堆中,变量实际上是一个存放在栈内存的指针,
- 这个指针指向堆内存中的地址。每个空间大小不一样,根据情况进行特定的分配
# 17. 对称加密和非对称加密算法
# 17.1. 可解密:
- 对称加密:DES、3DES、AES
- 非对称加密:RSA
# 17.2. 不可解密:
不可逆加密算法:MD5、SHA1
# 18. 如何在选择图片后,不经后端而显示预览图片?
- 监听
input
的change
事件,从e.target.files[0]
获取file对象。 window.URL
获取URL对象,利用URL.createObjectURL(file)
生成目标url
,设置img
的src
属性为生成的url
。 或者new一个FileReader()
得到reader
....
# 19. Blob 和 ArrayBuffer
# 19.1. Blob
Blob(binary large object)
,二进制类文件大对象,是一个可以存储二进制文件的“容器”,HTML5中的Blob对象除了存放二进制数据外还可以设置这个数据的MIME类型。File接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。
new Blob([data], {type: "application/octet-binary"})
Blob构造函数接受两个参数,第一个参数是一个包含实际数据的数组,第二个参数是数据的MIME类型。
# 19.2. ArrayBuffer
ArrayBuffer
对象表示内存中一段原始的二进制数据容器(缓冲区)
const buffer = new ArrayBuffer(8); // create an ArrayBuffer with a size in bytes
console.log(buffer.byteLength); // 8
# 19.3. Blob 和 ArrayBuffer 的区别
- Blob和ArrayBuffer都能存储二进制数据。Blob相对而言储存的二进制数据大(如File文件对象)。
- ArrayBuffer对象表示原始的二进制数据缓冲区,即在内存中分配指定大小的二进制缓冲区(容器),用于存储各种类型化数组的数据,是最基础的原始数据容器,无法直接读取或写入, 需要通过具体视图来读取或写入,即
TypedArray
对象或DataView
对象对内存大小进行读取或写入;Blob对象表示一个不可变、原始数据的类文件对象。 - ArrayBuffer是原始的二进制数据缓冲区,不能设置MIME类型;Blob可以储存大量的二进制编码格式的数据,可以设置对象的MIME类型。
二者可以相互转换:
// Blob => ArrayBuffer:
let blob = new Blob([1,2,3,4])
let reader = new FileReader();
reader.onload = function(result) {
console.log(result);
}
reader.readAsArrayBuffer(blob);
// ArrayBuffer => Blob:
let blob = new Blob([buffer])
# 19.4. 使用blob和URL.createObjectURL生成一个url
var blob = new Blob("保存为blob形式的数据");
var url = new URL.createObjectURL(blob);
可以被img等标签使用,例如:image.src = url;
# 20. URL.createObjectURL()
URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的File对象或Blob对象。
# 20.1. URL.createObjectURL(blob)
和FileReader.readAsDataURL(file)
的异同:
区别
- 通过
FileReader.readAsDataURL(file)
可以获取一段data:base64
的字符串 - 通过
URL.createObjectURL(blob)
可以获取当前文件的一个内存URL
执行时机
createObjectURL
是同步执行(立即的)FileReader.readAsDataURL
是异步执行(过一段时间)
内存使用
createObjectURL
返回一段带hash的url,并且一直存储在内存中,直到document
触发了unload事件(例如:document close)或者执行revokeObjectURL来释放。FileReader.readAsDataURL
则返回包含很多字符的base64
,并会比blob url
消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)
# 21. 文件和二进制数据对象
Blob对象是一个代表二进制数据的基本对象,在它的基础上,又衍生出一系列相关的API,用来操作文件。
File
对象:负责处理那些以文件形式存在的二进制数据,也就是操作本地文件;FileList
对象:File对象的网页表单接口;FileReader
对象:负责将二进制数据读入内存内容;URL
对象:用于对二进制数据生成URL。
对于不同类型的文件,FileReader
提供不同的方法读取文件。
readAsBinaryString(Blob|File)
:返回二进制字符串,该字符串每个字节包含一个0到255之间的整数。readAsText(Blob|File, opt_encoding)
:返回文本字符串。默认情况下,文本编码格式是’UTF-8’,可以通过可选的格式参数,指定其他编码格式的文本。readAsDataURL(Blob|File)
:返回一个基于Base64编码的data-uri对象readAsArrayBuffer(Blob|File)
:返回一个ArrayBuffer对象。
参考资料:js中Blob对象一般用法 (opens new window) ArrayBuffer-MDN (opens new window)
# 22. fetch 发送2次请求的原因
fetch 发送 post 请求的时候,总是发送2次,第一次状态码是204,第二次才成功?
原因很简单,因为你用fetch的post请求的时候,导致fetch
第一次发送了一个Options
请求,询问服务器是否支持修改的请求头,如果服务器支持,则在第二次中发送真正的请求。
# 23. 让坐标变化的2种方式
- 传统的top, left坐标修改
- CSS3中的
transform
属性
# 24. requestAnimFrame
requestAnimFrame();
是一个比较科学的API,相对于setInterval
和setTimeout
来讲,requestAnimFrame
会更科学
requestAnimFrame
的原理就是:当前绘制完成之后,去根据你机器的性能来确定间隔多长时间绘制下一帧,所以它是一个智能计算的过程。而setInterval
和setTimeout
会有一个固定的时间,比如我们指定给它每过60ms就绘制一帧,万一你绘制的内容非常大,以至于60ms之内不能完成,而requestAnimFrame
会是一个科学的方法,
但是也有一个问题:fps
————frame per second
(每秒多少帧).
使用requestAnimFrame
会导致帧与帧之间的时间间隔是不固定的,所以有一个动态的时间间隔。
# 25. onmouseenter
和onmouseover
对比
onmouseenter
和onmouseleave
是一组:当鼠标进入指定区域的时候触发,但是不支持冒泡,进入或者离开子组件都不触发。onmouseover
和onmouseout
是一组:当鼠标进入指定区域的时候触发,进入或者离开子组件也都触发
比如在A上绑定事件,A包含子元素B,onmouseenter
A进入B不触发,onmouseover
A进入B触发
# 26. click 在 ios 上有300ms延迟,如何解决
- 粗暴型,禁用缩放
<meta name="viewport" content="width=device-width, user-scalable=no">
- 利用
FastClick
,其原理是: 检测到touchend
事件后,立刻出发模拟click
事件,并且把浏览器300毫秒之后真正出发的事件给阻断掉
# 27. PNG,GIF,JPG 的区别及如何选
参考资料: 选择正确的图片格式 (opens new window) GIF:
- 8 位像素,256 色
- 无损压缩
- 支持简单动画
- 支持 boolean 透明
- 适合简单动画
JPEG:
- 颜色限于 256
- 有损压缩
- 可控制压缩质量
- 不支持透明
- 适合照片
PNG:
- 有 PNG8 和 truecolor PNG
- PNG8 类似 GIF 颜色上限为 256,文件小,支持 alpha 透明度,无动画
- 适合图标、背景、按钮
# 28. 属性描述对象
下面是属性描述对象的一个例子。
{
value: 123,
writable: false,
enumerable: true,
configurable: false,
get: undefined,
set: undefined
}
属性描述对象提供6个元属性。
value
value
是该属性的属性值,默认为undefined
。- 只要
writable
和configurable
有一个为true
,就允许改动。 - 另外,
writable
为false
时,直接目标属性赋值,不报错,但不会成功,如果用Object.defineProperty
的方式修改,则会成功。
writable
writable
是一个布尔值,表示属性值(value)是否可改变(即是否可写),默认为true
。
enumerable
enumerable
是一个布尔值,表示该属性是否可遍历,默认为true
。如果设为false
,会使得某些操作(比如for...in
循环、Object.keys()
、JSON.stringify
)跳过该属性。
configurable
configurable
是一个布尔值,表示可配置性,默认为true
。- 如果设为
false
,将阻止某些操作改写该属性,比如无法删除该属性,也不得改变该属性的属性描述对象(value
属性除外)。也就是说,configurable
属性控制了属性描述对象的可写性。
get
get
是一个函数,表示该属性的取值函数(getter),默认为undefined
。- 注意,一旦定义了取值函数
get
(或存值函数set
),就不能将writable
属性设为true
,或者同时定义value
属性,否则会报错。
var obj = {};
Object.defineProperty(obj, 'p', {
value: 123,
get: function() { return 456; }
});
// TypeError: Invalid property.
// A property cannot both have accessors and be writable or have a value
Object.defineProperty(obj, 'p', {
writable: true,
get: function() { return 456; }
});
// TypeError: Invalid property descriptor.
// Cannot both specify accessors and a value or writable attribute
set
set
是一个函数,表示该属性的存值函数(setter),默认为undefined
。
Object.defineProperty()
和Object.defineProperties()
参数里面的属性描述对象,writable
、configurable
、enumerable
这三个属性的默认值都为false
。
要冻结对象的读写状态,防止对象被改变,有三种方法,最弱的一种是Object.preventExtensions
,其次是Object.seal
,最强的是Object.freeze
。
# 29. 注意img的onerror
属性:
onerror
属性找图片加载失败了的时候,可以使用onerror
将图片替换为默认图片。注意,一定要在onerror
里面将onerror
置空,不然在新的图片也加载失败后,会形成死循环。
<img src="http://example.com/a.png" onerror="this.onerror=''; this.src='http://example.com/b.png'">
# 30. ajax解决浏览器缓存问题
- 在ajax发送请求前加上
anyAjaxObj.setRequestHeader ( "If-Modified-Since","0")
。 - 在ajax发送请求前加上
anyAjaxObj.setRequestHeader ( "Cache-Control","no-cache")
。 - 在URL后面加上一个随机数:
"fresh=" + Math.random()
。 - 在URL后面加上时间戳:
"nowtime=" + new Date().getTime()
。 - 如果是使用
jQuery
,直接这样就可以了$.ajaxSetup({cache:false})
。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。
# 31. 学习资料
https://github.com/huyaocode/webKnowledge (opens new window)