一、类数组转数组方式
1、展开运算符实现
- 代码 :[...类数组]
- 在工作中经常使用
2、利用数组方法slice与call结合实现
- 代码 :[].slice.call(arguments)
- **原理:
**先通过数组找到slice方法,
通过call让这个slice执行,并把其中的this变成类型组
3、创建一个空数组通过循环把类数组放入
- 代码:
var ary = [];
for (var i = 0; i < arguments.length; i++) {
ary[i]=arguments[i];
}
- 最基础方式
4、Array.from()
- 代码:Array.from(xxx)
- 返回值:返回值是一个数组,项跟xxx一样
5、封装一个方法
function toArray(arg){
try{
return [].slice.call(arg)
}catch(error){
var ary = [];
for(var i = 0;i<arg.length;i++){
ary.push(arrg[i])
}
return ary
}
}
try{}catch(){}
try{
//要执行可能会报错的代码
}catch(err){
//形参对应的是 上边运行的错误信息
//上边运行出错,机会走到这个catch,但是不会影响主体代码执行
console.log(err)//返回报错代码
} //报错时不会阻碍下方代码执行
6、...知识点
- **Array.isArray(xxx)
**作用:用来判断xxx是不是一个数组 - Object.keys(obj)
作用:把obj所有的私有属性名拿出来
目的:循环对象\
var obj = {q:1,w:2;j:3,f:4}
Object.keys(obj).forEach(k=>{
console.log('属性名',k,'属性值',obj[k]);
})
//或者
for(let k in obj){
if(obj.hasOwnProperty(k)){ //加判断是为了排除它的公有属性
console.log('属性名',k,'属性值',obj[k]);
}
}
- try{}catch(){}
try{
//要执行可能会报错的代码
}catch(err){
//形参对应的是 上边运行的错误信息
//上边运行出错,机会走到这个catch,但是不会影响主体代码执行
console.log(err)//返回报错代码
} //报错时不会阻碍下方代码执行
二、手写实现
this复习
- 全局下的this是window
- 自执行函数this是window
- 箭头函数的this是上一级作用域中的this !!!!
- 定时器中的this是window 但若定时器中的函数为箭头函数,则依照箭头函数的规则!
- 事件绑定对应函数中的this是 绑定的元素
- 其他看点 点前边是谁this就是谁,没点就是window
- new执行类的时候 其中的this就是实例
- 类原型上的方法中的this得是实例
- call可以改变函数中的this指向 f.call(111)
apply和bind都是改变函数中this指向的
1、实现call
- 关键是实现call功能
function fn(q,w,e){
console.log(this);
console.log(q,w,e);
return 888
}
var obj = {
name:'珠峰'
}
Function.prototype.myCall = function(target,...arg){
//this-->fn
let fn = this;//把fn执行,然后把其中的this换成target
let a = Symbol('mycall')
target[a] = fn;//res是fn的执行结果
let res = target[a](...arg);//myCall的执行结果就是fn的执行结果
delete target[a];//删除不掉,在删除之前就已经被打印出来,规避不了
return res;
}
let res = fn.call(obj,1,2,3);//res-->888
let res2 = fn.myCall(obj,1,2,3)//res-->888
2、apply
- 代码 fn.apply(xxx,[a,b,c,d])
- 返回值:前边函数改变this后的执行结果
- 用法:
功能跟call一样;
区别在于call执行的时候,给函数传的实参是散开写的
apply执行的时候,给函数传的实参是一个集合的方式
【手写实现apply】
//手写apply
Function.prototype.myApply = function(target,arg){
let fn =this;
let a = Symbol('myapply');
target[a] = fn;
let res = target[a](...arg);
delete target[a];
return res;
}
3、bind
- 代码:fn.bind(xxx,a,b,c,d)
第一个参数为this的指向,后边为要传递的实参 - 返回值:一个新的函数
- 白话:bind会返回一个新函数,新函数执行的时候,会让函数fn执行,并且把fn中的this换成obj,后边的实参传给fn (新函数执行的时候,把新函数传递给实参会放到之前传递的实参后边)
function fn(){
console.log(arguments);
console.log(this);
}
var obj ={
name :'珠峰'
}
let res1 = fn.bind(obj,2,2,5,4,3)//返回的是一个新的函数,并不会使fn执行,新函数执行时才会让fn执行
let res2 = fn.call(obj,2,2,5,4,3)
【手写实现bind】
//手写bind
Function.prototype.myBind = function (target,...arg){
return (...arg2)=>{
let fn = this;
let a = Symbol('mybind')
target[a] = fn;
let res = target[a](...arg,...arg2);
return res;
}
}
let res3 = fn.myBind(obj,2,2,5,4,3)
4、create
- 代码:obj = Object.create([])
- 返回值:空对象
- 作用:Object.create 执行会返回一个空对象,这个对象的__proto__是指向create的参数(然后就可以用参数的方法)
//参照理解
var obj = new Object();
var obj2 = {};
var obj3 = Object.create(null);
var obj4 = Object.create([]);
console.log(obj,obj2,obj3,obj4);
//Object.create 执行会返回一个空对象,这个对象的__proto__是指向create的参数
【手写实现create】
//实现
function create(target){
//var obj ={}
//obj.__proto__ = target//__proto__可能会有报错的风险,可以把她的类的原型改成需要的东西(原型重写)
function QQQ(){
QQQ.prototype = target;
let a = new QQQ;
return a
} //内置类的原型不能修改
return obj
}
var obj4 = create([])
三、class(es6新增)
1、class简介
class是es6新增的一个用来创造类的方式,创造出来的类不能当作普通函数执行。
2、用法
- 代码:class 类名{ constructor(形参){ 私有属性 } 共有属性 }
- static:静态属性 可以直接加到函数自己身上而不是原型上
class Person {
constructor(name, age, sex) { //这的小括号是接受形参的
console.log(arguments);
this.name = name;
this.age = age;
this.sex = sex;
}
eat(food) {
console.log(`吃${food}`);
}
height = 100 //私有属性的简写方式(如果是常数的情况下)
static qqq = 888 //静态属性 指的是Person自己属性
static ttt = 899 // Person的prototype是它的一个内置的静态属性;
static uuu = 222
}
let p1 = new Person('小孔', 12, 0)
//对比
function Person(name,age,sex){
this.name = name ;
this.age = age;
this.sex = sex;
}
Person.prototype.eat = function(food){
console.log(`吃${food}`)
Person.ttt = 888//静态属性
}
四、练习题
// 变量提升阶段
// 声明+定义了Foo
// 声明了一个getName
// ——声明—— +定义getName 5
getName() // 5
function Foo() {
getName = function () { console.log(1); };
return this;
}
Foo.getName = function () { console.log(2); }
Foo.prototype.getName = function () { console.log(3); }
var getName = function () { console.log(4); }
function getName() { console.log(5); }
getName(); // 4
Foo.getName(); // 2
Foo().getName();// window.getName() 1
//Foo() 把window下的getName 从log4变成了log1函数
// window.getName()
var a = { aa: 23 }
b = a;
b.x = a = {}
getName(); //1
let p1 = new Foo.getName();
// 点比new优先级高;先通过Foo找到getName,然后new执行getName
let p2 = new Foo().getName();
// 小括号的优先级是最大的;先new执行了Foo 得到的实例再去找到getName 然后执行
let p3 = new new Foo().getName();
// 先new Foo 得到实例之后找到getName 然后再通过new执行getName