js基础
- 原始数据类型(6个)
- typeof使用(null的值是多少)
- boolean类型和其它类型的转换
- Object转原始类型(tostring,valueof,[symbole.toprimitive]三个的优先级问题)
- NaN(isNaN()函数)
- 执行上下文,变量对象,和作用域链(三者关系)
- 闭包(作用域链去解释)
- 原型和原型链(prototype和prototype.construct指向,_ proto_)
- 手写new(1.生成新对象2.arguments取出构造函数【第一个值】3.对象的原型绑定到传入的构造函数的原型4.绑定this执行构造函数【let result=construct.apply(obj,arguments)】 5.返回新对象)
function myNew(){
let obj={};
let construct=arguments.shift();
obj._proto_=construct.prototype;
if(typeof construct !='function'){
throw new TypeError('第一个参数必须为函数')
}
let result=construct.apply(obj,arguments);
return result;
}
- instanceof(判断原型链中是否能找到类型的prototype,手写的话就是循环递归需要检测的obj的原型对象)
- 继承的6个方式
1.原型链继承(子构造函数的prototype=父类的实例)
- 特点:可以继承父类构造函数属性,父类原型属性
- 缺点:1.新实例无法向构造函数传参2.继承单一3.所有新实例都共享父类实例属性
2.借用构造函数(子类的构造函数中 Super.call(this,args),call和apply将父类的构造函数引入子类构造函数中)
- 特点:1.只继承了父类构造函数属性,没有继承父类原型属性 2.可以继承多个构造函数属性(call多个)3.子类实例中可以向父类传参
- 缺点:1.方法都要在构造函数中定义 2.只是继承了父类的构造函数属性 3.无法实现构造函数复用 4.每个新实例都有构造函数副本
3.组合继承(原型链式继承和借用构造函数式继承同时使用)
- 特点:可以传参可以复用,每个新的实例的构造函数都是私有的
- 缺点:调用两次父类构造函数,子类的构造函数会代替原型上父类构造函数
原型式继承(先创建一个临时的构造函数,传入的对象作为构造函数的原型,返回这个临时类的新实例)
function content(obj){
function F(){};
F.prototype=obj;
return new F();
}
- 特点:执行了一次浅拷贝(类似Object.create())
寄生式继承(在原型式继承外面继续封装一层,在这里面添加属性和方法)
let super=new Super();
function creatAnother(obj){
let clone=content(obj);
clone.say=function(){
alert('hi');
}
clone.name="gar";
return clone;
}
let super2=creatAnother(super);
- 特点:所有返回值都有say方法和name属性
- 缺点:没有用到原型不能复用
寄生组合式继承
function inheritPrototype(subType,superType){
let prototype=content(superType.prototype);
prototype.constructor=subType;
subType.prototype=protype;
}
function Sub(){
Super.call(this)
}
//函数接收俩个参数,子类构造函数和父类构造函数
//1.创建一个超类原型的副本
//2.为创建的副本添加constructor属性指定值为子类构造函数(修复因为重写而丢失的constructor属性)
//3.将新创建的副本赋值给子类的原型
-使用寄生式继承来继承超类的原型(还要重新指定constructor),然后将结果指定给子类的原型。解决了组合式俩次调用父类构造函数问题
- call 和apply(都是改变this指向只是参数不一样,call是参数列表,apply是数组)
- 实现要点
- 1.不传入第一个参数的话,就默认window 2.添加一个属性指向this 3.获取入参(去除第一个值) 4.改变this的这个属性函数执行 5.删除属性 6.返回结果
es6的继承
function MyDate(){}
MyDate.prototype.test=function(){
return this.getTime();
}
let d=new Date()
Object.setPrototypeof(d,MyDate.prototype);
Object.setPrototypeof(MyDate.prototype,Date.prototype);
- 思路:先创建父类的实例=>改变实例的_ proto_ 为子类的prototype=>子类的的prototype的实例_ proto_指向父类的prototype
call 的实现
Function.prototype.mycall(context){
var context=context||window;
context.fn=this;
var arg=[...arguments].slice(1);
let result=context.fn(...arg);
delete context.fn;
return result;
}
apply的实现
Function.prototype.myApply(context){
var context=context||window;
cotext.fn=this;
var result;
if(arguments[1]){
result=context.fn(...arguments[1]);
}else{
result=context.fn();
}
delete context.fn;
return result;
}
bind实现(1.使用者必须是函数2.返回是一个函数3.因为返回是函数所以可以new,所以返回值有俩个结果 附:入参和call一样是个列表)
Function.prototype.mybind(context){
if(typeof this!='function'){
throw new TypeError('Error')
}
var _this=this;
var arg=[...arguments].slice(1);
return Function F(){
if(this instanceof F){
return new _this(...args,...arguments);
}else{
return _this.apply(context,args.concat(arguments))
}
}
}
js的深浅拷贝
- js浅拷贝(1. Object.assign({},a) 2.let b={...a})只是拷贝了第一层
- js深拷贝
- JSON.parse(JSON.stringify(obj)) (缺点:1.会忽略symbole和undefine 2.不能序列化函数 3.不能解决循环引用问题)
function deepClone(source){
const result=source instanceof Array?[]:{};
for(let keys in source){
if(source.hasownprototype(keys){
result[keys]=typeof source[keys]=='object'?deepClone(source[keys]):source[keys];
}
}
return result;
}
迭代方法
- every() 所有正确才会返回true
- filter() 返回运算后为true的数据的数组
- forEach() 无返回单纯循环
- map() 返回加工后的数组
- some() 只要一个为true就为true
数组操作
-
slice() 截取返回一个新的数组
可以存在俩个参数
[start,end) 如果只有一个参数就是start -
splice() 删除,插入 和替换
第一个参数,要删除的位置
第二个参数,要删除的项 第三个参数及以上,要替换的项
删除 splice(0,2) 从0开始删除俩项
插入 splice(2,0,'red') 从第二项开始开始插入red 替换 splice(2,1,'red','green') 从第二项开始删除一项并且插入red 和green