sheep

sheep 查看完整档案

杭州编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

sheep 发布了文章 · 10月25日

类型判断

typeof 类型判断
typeof 判断只能 JavaScript 中的基本类型和 Object 引用类型, 对于各种 Object 只是粗略的判断为 Object 类型, 并不会判断出对象的具体类型。所以 typeof 能判断的类型有 Number, String, Boolean, Symbol, undefined,BigInt,Object.

注: typefo null 的结果为 Object 类型的, 但实际上 null 并不是 Object类型, 它所以 Null 类型,能的到这样的结果是因为 JavaSscript typeof行为上的错误所导致的。

// 1. typeof

let symbol = Symbol()

typeof 23                       // number
typeof "Jason"                  // string
typeof true                     // boolean
typeof undefined                // undefined 
typeof symbol                   // symbol
typeof 9007199254740991n        // bigint


// 不判断对象的具体类型
typeof {}               // object
typeof []               // object
typeof new Error()      // object
typeof null             // object

typeof function(){}     // function
注: function 函数隶属于 Object 类型的 但是 typeof function 时返回的是 function 而并不是 Object,这是因为 typefo 对于 function 函数区分对待,实际不并不存在 function 类型, 这是 JavaSscript 早期的错误,但对编程非常便利。
instanceof 类型判断
instanceof 判断对象的具体类型, instanceof 是通过目标对象中原型链的 prototype 与指定类型的 prototype 进行类型检查, 只要原型链中存在指定类型的原型 prototype 就返回 true 反之 false, instanceof 没有 typeof 那么局限, 它可以对 Object 的各类对象进行具体的检查判断。
new Date() instanceof Date                              // true
new String() instanceof String                          // true
new Number() instanceof Number                          // true
new Error() instanceof Error                            // true
function(){} instanceof Function                        // true
new Map() instanceof Map                                // true
new Set() instanceof Set                                // true
new RegExp('ab+c', 'i') instanceof RegExps              // true

....
注: null 没有原型, 所以不可用此方法进行判断
Object.prototype.toString() 类型判断
各种类型或对象调用 Object.prototype.toString() 方法时将返回 [object 类型] 的字符串, 可以用来判断各种数据类型。只是返回的的字符串可能在实际的编程应用中有点不好操作, 所以需要一函数来对判断后返回的结果进行处理。
  let res= {}

  "Null Undefined String Number Boolean Function Date RegExp Error Array Object Math JSON Class".split(" ").map(item =>{
    res["[object "+ item + "]"] = item.toLowerCase();
  })
  
    function  type(obj){
    return typeof obj === "object" || typeof obj === "function" ? res[Object.prototype.toString.call(obj)] || "object" : typeof obj;
  }
  
  // 测试
  let date = new Date();
  function f(){}
  
  
  type(date);       // date
  type(f);          // function
  type([])          // array
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月18日

发布订阅模式

发布订阅模式
class EventEmitter {
  constructor() {
     this.cache = {}
  }
  
  // 注册事件
  $on(eventType, fn) {
    // 添加事件
    this.cache[eventType] = this.cache[eventType] || [];
    this.cache[eventType].push(fn);
  }
  
  // 触发事件
  $emit(eventType) {
    if(this.cache[eventType]) {
        this.cache[eventType].forEach(handle=>{
            handle();
        })
    }
  }
}

// 测试

let eventEmitter = new EventEmitter();
function f(){
   console.log("Jason");
}
eventEmitter.$on('click' f);
eventEmitter.$emit('click');        // Jason
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月12日

手写 Instanceof 和 new

手写 instanceof
instanceof 检查目标对象的原型链中是否有与指定对象的原型相同的原型,
通过 === 严格等于来对于两个原型是否相等。
function myInstanceof(obj, obj2) {
    let proto = obj.__proto__;
    let prototype = obj2.prototype;
    let queue = [proto];
    // 循环 obj 原型链进行获取 __proto__ 与 prototype 对比
    while(queue.length) {
        let temp = queue.shift();
        if(temp === null) return false;
        if(temp === prototype) return true;
        queue.push(temp.__proto__);
    }
}

// 测试

myInstanceof(new Date(), Date);         // true
myInstanceof({}, Object);               // true
myInstanceof('Jason', Number);          // false
myInstanceof(23, Stirng);               // false
手写 new
思路:
    1. new F() 通过构造函数创建的对象的 __proto__ 指向构造函数的原型.
    2. F() 构造函数中的 this 指向 F()构造函数的实例对象.
function myNew(F){
    let result = {};
    let arg = Array.prototype.slice.call(arguments, 1);
    // 将实例对象的 __proto__ 指向 F.prototype
    Object.setPrototypeOf(result, F.prototype);
    // this 指向实例对象
    F.apply(result, arg);
   return result;
}

// 测试
function F(name, age) {
    this.name = name;
    this.age = age;
}

let user = myNew(F, "Jason", 23);
console.log(user.__proto__ === F.prototype);            // true
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月4日

this指向问题

不同开发法环境下全局环境中this指向
提示: this 的指向是在代码运行时,被动态绑定的。
  • 浏览器中下全局环境的 this 指向 window
//测试
console.log(this);      // window
  • node 中全局环境的 this 指向 global
//测试
console.log(this)       // global
  • "use strict" 严格模式下全局环境的 this 指向 undefined
"use strict"

// 测试
console.log(this)      // undefined
谁调用 this 就指向谁
  • 函数在全局环境中自行调用时函数中 this 指向全局环境中 this 指向的对象

注意: 全局环境中的函数自行调用类似于被全局环境中 this 指向的对象所调用(如:window.F())

let name = "Jason"
function getName() {
    console.log(this.name);
}

1. 浏览器中
getName()       // Jason, this -> window
// 类似于
window.getName()

3. node 环境中
getName()       // Jason, this -> global
// 类似于
global.getName()

3. 严格模式中
"use strict" 
getName()       // undefined, this -> undefined
// 类似于
undefined.getName()
  • 对象中的方法在被对象调用时 this 指向调用它的对象
let user = {
    name: "Jason",
    getName: function(){
        console.log(this);
        console.log(this.name);
    },
    obj: {
        age: 23,
        getAge: function(){
            console.log(this);
            console.log(this.age);
        }
    }

}

// 测试
user.getName()          // user Jason, this -> user
user.obj.getAge()       // obj 23, this -> obj
构造函数中的 this 指向构造函数的实例对象
function User(name, age) {
    this.name = name;
    this.age = age;
}
User.prototype.getUser = function(){
    console.log(this)
}

// 测试
let user = new  User("Jason", 23)
user.getUser();// this 指向构造函数实例, this -> user
setTimeout, setInterval 中的 this 指向全局中的 this
let F = ()=> {
    setTimeout(function(){
        console.log(this)
    },2000)
}
// 测试
F();        // window, this -> window
Class 中的 this 指向类实例的对象
class User {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    getUser(){
        console.log(this.name);
        console.log(this.age);
        console.log(this);
    }
}

// 测试
let user = new User("Jason", 23);
user.getUser()      // Jason 23, this -> user
箭头函数中没 this, 如果箭头函数中使用 this 的话, this 指向取决于外层对象或函数的 this 指向
setTimeout(()=>{
    console.log(this);
},3000)
// this -> windeow, 箭头函数中的 this 指向取决于 setTimeout 的 this 指向
查看原文

赞 0 收藏 0 评论 2

sheep 发布了文章 · 9月27日

防抖与节流方法

防抖
防抖是当某一个时间段内多次触发同一事件时,只执行最后一次触发的事件。其余的事件都会被清除。
function debounce(f, m) { 
    let time; 
    return function(){ 
            let arg = Array.prototype.slice.call(arguments, 1);
            if(time) { 
                clearTimeout(time); 
            } 
            time = setTimeout(function(){ 
                    f.apply(this, arg)
                    },m)
     } 
} 

// 测试 
function fun(){ 
    console.log("防抖"); 
} 
let test = debounce(fun, 1000); 
window.addEventListener('scroll', test)
节流
节流是在某一个时间段内事件只能被触发一次并执行,如果想再次触发执行需等待下一个时间周期。
  • 方法一
function throttle(f, m) { 
    let status = true; 
    return function(){ 
        let arg = Array.prototype.slice.call(arguments, 1); 
        if(!status) return ; 
        status = false; 
        setTimeout(function(){ 
        f.apply(this, arg); status = true; 
        }, m) 
     }
} 
     
// 测试 
function fun(){ 
    console.log("防抖"); 
} 
let test = throttle(fun, 1000); 
window.addEventListener('scroll', test);
  • 方法二
function throttle(f, m) { 
    let lastTime = 0; 
    return function () { 
        let arg = Array.prototype.slice.call(arguments, 1); 
        let newTime = Date.now(); 
        console.log(newTime - lastTime); 
        if (newTime - lastTime > m) { 
            setTimeout(function () { 
                f.apply(this, arg); }, m); 
        } 
       lastTime = newTime; 
   }; 
}
                
// 测试 
function fun(){ 
    console.log("防抖"); 
} 
let test = throttle(fun, 1000);
window.addEventListener('scroll', test);
总结
  • 防抖只执行最后一次触发的事件
  • 节流只执行时间周期内第一次触发的事件
  • 防抖在时间段内触发多次函数事件,但会被清除只保留最后一次,并执行
  • 节流在时间段内只能触发执行一次事件,如果想再次触发执行将等到下一个时间周期
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 9月27日

手写 call , apply, bind 方法

手写call方法
手写call思路:对象通过 Object.attributes 来访问它的属性.这时给对象添加一个属性,该属性指向需要绑定对象的函数。
通过Object.attributes去调用函数,函数中的this 指向了调用它的对象Object. 最后将属性从对象中移除。
    1. object.f = this
    2. object.f()
    3. delete object.f;
Function.prototype.myCall = function(context) {
   const self = context || window;
   let arg = Array.prototype.slice.call(arguments,1)
   self.f = this;
   self.f(...arg);
   delete self.f;
}

// 测试
function getUser(age){
    console.log(this.name);
    console.log(age)
}
let user = {    
      name: 'Jason'
}
getUser.myCall(user,24)
  • argument类数组转换为数组的方法
//方法一 
let arg = Array.prototype.slice.call(argment,1)
//方法二 
let arg = Array.prototype.concat.apply([],arguments)
//方法三 
let arg = Array.from(arguments)
// 方法四
let arg = [...arguments]
  • ...展开语法传递参数
Function.prototype.myCall = function(context, ...item) {
   const self = context || window;
   self.f = this;
   self.f(...item);
   delete self.f;
}

// 测试
function getUser(age){
   console.log(this.name);
   console.log(age);
}
let user = {    
      name: 'Jason'
}
getUser.myCall(user,24)

如上代码中的 const self = this || window 是用指定传入的对象为null时,默认为window对象

手写apply方法
apply与call的实现方式相同,apply只能出入两个参数, 第一个参数为绑定的this对象,第二个参数为一个数组,作为函数的参数。
Function.prototype.myApply = function(context, arr) {
    const self = context || window;
    if(!Array.isArray(arr)){
      throw new TypeError("传入的参数类型不正确,传入一个数组");
    }
     self.f = this;
     self.f(...arr);
     delete self.f;
}

// 测试
function getAge(age){
    console.log(age)
}
getAge.myApply(null, 24)

*arguments 实现apply可传递多个参数(其实的是一个伪数组对象)

Function.prototype.myApply = function(context) {
    const self = context || window;
    let arg = Array.prototype.slice.call(arguments,1)
    if(!Array.isArray(arg)){
      throw new TypeError("传入的参数类型不正确,传入一个数组");
    }
     self.f = this;
     self.f(...arg);
     delete self.f;
}

// 测试
function getAge(age){
    console.log(age)
}
getAge.myApply(null, 24)
  • ...展开语法实现apply传递多个参数(其实传入了一个数组)
Function.prototype.myApply = function(context,...item) {
    const self = context || window;
    if(!Array.isArray(item)){
      throw new TypeError("传入的参数类型不正确,传入一个数组");
    }
     self.f = this;
     self.f(...item);
     delete self.f;
}

// 测试
function getAge(age){
    console.log(age)
}
getAge.myApply(null, 24)
手写bind方法
bind与call,apply 不同在于函数执行后将创建一个新函数返回。bind函数可传入两个参数,第一个参数this绑定的对象,
第二个参数是一个数组或者类数组对象,第二个参数将作为实参在新函数执行时被传入。
Function.prototype.myBind = function(context){
    const obj = context || window;
    const self = this;
    let arg = Array.prototype.slice.call(arguments, 1);
    return function(){
        let arg2 = Array.prototype.slice.call(arguments, 1);
        self.apply(obj, arg.concat(arg2));
    }
}
如上mybind创建的新函数作为普通函数调用时this指向你所绑定的对象。当做为构造函数通过new去创建实例对象时this绑定的对象就
会被忽略了。因为构造函数中的会隐式创建一个实例对象,this指向这个实例对象。而不再是指向你所指定的对象。
Function.prototype.myBind = function(context){
    const obj = context || window;
    const self = this;
    let arg = Array.prototype.slice.call(arguments, 1);
    const newFun = function(){
        let arg2 = Array.prototype.slice.call(arguments, 1);
        if(this instanceof newFun) {
            self.apply(this, arg.concat(arg2));
        } else {
            self.apply(obj, arg~~~~.concat(arg2));
        }
    }
    
    //支持 new 创建对象时,实例__proto__指向绑定对象函数的prototype
    newFun.prototype = this.prototype
    return newFun;
}

// 测试
let user = {
        name: 'Jason',
        age: 23,
}
function Fun(school) {
    this.school = school;
    console.log(this.name);
    console.log(this.age);
    console.log(this.school);
}
let fun = Fun.myBind(user, '江南大学');
//  this -> user
fun()

// this -> 对象实例
let obj = new  fun();
console.log(obj.__proto__ === Fun.prototype) // ture
查看原文

赞 0 收藏 0 评论 0

sheep 关注了专栏 · 9月25日

终身学习者

我要先坚持分享20年,大家来一起见证吧。

关注 40749

sheep 关注了专栏 · 9月25日

SegmentFault 行业快讯

第一时间为开发者提供行业相关的实时热点资讯

关注 25196

sheep 关注了专栏 · 9月25日

疯狂的技术宅

本专栏文章首发于公众号:前端先锋 。

关注 24309

sheep 关注了专栏 · 9月25日

前端下午茶公众号

你不能把这个世界,让给你鄙视的人

关注 1510

认证与成就

  • 获得 1 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 9月25日
个人主页被 312 人浏览