JS数据类型判断
typeof可以用来判断number、string、Boolean、function、symbol、undefined类型数据
instanceof可以判短Array、Date和Function
用object.prototype.toString可以判断所有类型
var gettype=Object.prototype.toString
gettype.call('aaaa') 输出 [object String]
gettype.call(2222) 输出 [object Number]
gettype.call(true) 输出 [object Boolean]
gettype.call(undefined) 输出 [object Undefined]
gettype.call(null) 输出 [object Null]
gettype.call({}) 输出 [object Object]
gettype.call([]) 输出 [object Array]
gettype.call(function(){}) 输出 [object Function]
闭包
闭包,即函数的定义后表达式位于另一个函数的内部,而且这些函数可以访问他们外部函数声明的所有变量,参数和定义的其他函数。
当内部函数在包裹它的函数外部被调用时就形成了闭包,即内部函数会在外部函数返回后执行。
原型链
1.所有引用类型都有对象特性
2.所有的引用类型都有一个_proto_属性,属性值是一个普通的对象
3.所有的函数都有一个prototype属性,属性值是一个普通的对象
4.所有的引用类型的_proto_属性都指向它的构造函数的prototype属性值
5.当试图获得对象某一属性,但是对象本身没有的话会去它的_proto_属性(即它的构造函数的prototype属性值)中寻找
原型链继承
每个构造函数都有一个原型对象,原型对象都有一个指向构造函数的指针(construct),而实例都有一个内部指针指向原型对象。其中构造函数都有一个prototype属性指向实例对象
实例→原型对象→构造函数
↑ ← ↓
假设有构造函数A和B,通过A.prototype = new B(); 把A的prototype属性指向了B的实例,那么A实例的内部指针也会发生改变: A实例→B原型对象
我的理解:
A实例→A原型对象→A构造函数→(A.prototype = new B() )B实例→B原型对象
这样A就能继承B的所有属性和方法
This
1.谁调用函数或方法this就指向谁
2.如果没有上一级调用,那么this就指向window
3.即使一个函数中包含多个对象,这个函数被最外层的对象所调用,this也只是指向它上一级对象
arguments对象
在函数代码中,使用arguments对象无需指出参数名就能访问参数。如arguments[0]访问的就是函数第一个参数。
arguments.length可以用来获取参数的个数
用arguments判断参数个数就可以用来模拟函数重载
function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 5);
} else if(arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //输出 “15”
doAdd(40, 20); //输出 “60”
ES6常用属性
1.let和const
let和const都是用来声明变量的,其中let为js新增了块级作用域,let定义的变量作用域为代码块。const同常用来定义常量,一旦声明值就不能改变。
2.函数参数默认值
function printText(text = 'default') {
console.log(text);
}
这样没有传入参数值的时候text的值就为default
3.箭头函数
特点:不需要用function来创建;省略return关键字;继承上下文this关键字。
var A = function (a,b){
return a+b;
}
//使用箭头函数
var a = (a,b) =>a+b;
function a() {
console.log(a)
}
//使用箭头函数
let a = ()=>{
console.log(a)
}
箭头函数与普通函数的区别
- 箭头函数是匿名函数,不能作为构造函数,不能用new
- 箭头函数不绑定this,会从上下文捕获this来作为自己的this值
- 箭头函数在用call()和apply()方法调用一个函数时只是传入了一个参数,对this不影响
- 箭头函数没有原型属性
- 箭头函数不绑定arguments属性,转而用rest参数解决
4.模板字符串
如插入一段HTML在ES5中需要用到+和/来进行多行文字拼接
$("body").html("This demonstrates the output of HTML \
content to the page, including student's\
" + name + ", " + seatNumber + ", " + sex + " and so on.");
在ES6中只需要用到``就可以,${}用于界定
$("body").html(`This demonstrates the output of HTML content to the page,
including student's ${name}, ${seatNumber}, ${sex} and so on.`);
5.结构赋值
let [a,b,b] = [1,2,3]
let [a,[b],c] = [1,[2],3] //解构赋值要求两边模式相同
let [x,y = 'a'] = ['b'] //解构赋值允许设置默认值
//注意:ES6使用严格的(===)判断一个位置是否有效
//如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
function f() {
console.log('aaa');
}
let [x = f()] = [1];
2.对象的解构赋值
let {foo,baz} = {foo:"a",baz:"b"}
//嵌套解构
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
//如果要为P赋值
let {p,p:[x, { y }]} = obj
6.数组
- 数组去重
var arr = [1,2,3,4,4,5];
var arr2 = [...new Set(arr) ]; //arr2就是去重之后的数组
- 数组拷贝
浅拷贝,只复制指针,修改b会导致a变化
let arr = [1,2,3]
let arr2 = [...arr];
- 深拷贝
利用concat
let arr = [1,2,3];
let arr2 = [].concat(arr);
利用JSON深拷贝
let obj = {
a:1,
b:2,
c:undefind,
fun:function () {
console.log("function")
}
};
let obj2 = JSON.parse(JOSN.Stringify(obj));
console.log(obj2);
//object:[a:1,b:2]
//用JSON拷贝会忽略undefined和function
- 数组合并
let arr = [1,2];
let arr2 = [3,4];
[...arr,...arr2];
//[1,2,3,4]
requestAnimationFrame用于实现高性能帧动画的计时器
优势:
1.经过浏览器优化,更加流畅
2. 窗口没激活时动画停止,更加节省资源
3. 更加省电,尤其是对于移动端
使用方法:
var control;
function animate () {
control = requestAnimationFrame(animate);
//动画
}
//开始
control = requestAnimationFrame(animate);
//结束
cancelAnimationFrame(control);
对于低版本浏览器:
window.requestAnimationFrame(function (){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame||
function (callback) {
window.setTimeout(callback,1000/60);
}
})();
//使用
(function animation() {
requestAnimationFrame(animation);
//动画
})
.call()和.apply()的作用
都可以改变this的指向
apply能劫持另外一个对象的方法,继承它的属性
Function.apply(obj,args)方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args–>arguments)
call:和apply的意思一样,只不过是参数列表不一样.
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
链接:https://www.nowcoder.com/questionTerminal/a77ad7c0e09546a69ed1aa34b2269121
前端性能优化的方法
1.压缩CSS,JS源码,CSS sprites(将多个图片融合到一张图里)
2.使用cdn缩短HTTP请求的响应时间
3.添加Expires头,通过一个长久的Expires头使组件被缓存
4.把样式表放在头部,防止白屏。脚本放在底部,减少首屏的出现等待时间
5.避免CSS表达式
6.引用外部的CSS,JS
7.开启Ajax缓存
JS继承
父类
function animal(name){
this.name=name;
this.sleep = function () {
console.log('sleep');
}
}
animal.prototype.age = 3;
1.原型链继承
function cat(){
}
cat.protoype = new animail();
var an = new cat();
console.log(an.age) //3
缺点:
无法实现多继承
新实例无法向父类构造函数传参
2.借用构造函数继承
function cat() {
animal.call(this,"miao");
}
var an = new cat();
console.log(an.name) //miao
缺点:
只能继承父类的构造函数属性
每个新实例都有父类的构造函数副本,臃肿
3.组合继承
原型链继承+借用构造函数继承
function cat(name) {
animal.call(this,name)
}
cat.prototype = new aniaml():
var an = new cat("ju");
console.log(an.name) // "ju",继承构造函数属性
console.log(an.age) //"3",继承了父类的原型属性
结合了两种方式的优点,传参和复用。是常用方法
4.原型式继承
function cat(obj) {
function F() {};
f.prototype = obj; //继承传入的参数
returen new F(); //返回函数对象
}
var an = animal(); //获取父类的实例
var an2 = cat(an); //继承父类
console.log(an2.age) //3
用函数来封装一个对象,然后返回函数的调用,这个函数就成了可以随意添加属性的实例或对象。objext.create()就是这个原理
5.寄生式继承
给原型式继承再套一个壳子
function cat(obj) {
function F() {};
f.prototype = obj; //继承传入的参数
returen new F(); //返回函数对象
}
var an = animal(); //获取父类的实例
//再套一个函数壳子
function cat2(obj) {
var tool = cat(obj);
tool.name = "wang!"
return tool;
}
var an2 = cat2(an);
console.log(an2.name) //"wang!" 继承了tool的属性
6.寄生组合式继承
是继承的主流方法
function an(){}
an.prototype = animal.prototype; //继承父类的原型属性
function cat(){
animal.call(this) //继承父类构造函数的属性
}
cat.prototype = new an(); //cat对象再继承an对象
var an2 = new cat();
7.ES6的class继承
class animal {
}
class cat extends animal {
}
通过extends cat继承了animal类的所有属性和方法