高度なJavaScriptの必要性
无论是学习react还是vue,它们都是js的应用框架。剥去他们的壳子看到的始终是js,所以作为一个前端大厨必须要熟练掌握好js这个大勺,才能烧出一顿好菜
自己改善であろうとインタビューへの対処であろうと、以下の手書き機能はすべてのフロントエンドプログラマーが習得する必要があります
1.手書きの適用、呼び出し、バインド
每个Function对象都存在apply()、call()、bind() 方法,其作用都是可以在特定的作用域
中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
复制代码
適用、呼び出し、バインドの類似点と相違点
1. 三者都可以改变this的指向,第一个参数都是this,如果指向是null或者undefined则指向window
2. apply的参数是数组,call是列表,而bind可以多次传入
3. apply和call是改变this的指向之后直接运行函数,而bind则是返回绑定之后的函数
复制代码
適用実装の参照コード
/**
* 手写apply
*/
window.name='gy' // 全局变量
let obj={
name:'ckx'
}
var func=function(b,c){
console.log(`this=`, this)
console.log(this.name,b,c)
return 1
}
func('24','hz') // gy 24 hz
func.apply(obj,['24','hz']) // ckx 24 hz
let newObj={
name:'xmx',
age:24
}
Function.prototype.myApply=function(base,args){
// 1. 如果指向是null 或者undefined 则指向window
base=base || window
// 2. 根据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性
base.fn=this
// 3.执行函数,调用base.fn时,fn中的函数指向 base对象
let result=base.fn(...args)
// 4. 删除base的fn属性
delete base.fn
// 5. 返回result 结果
return result
}
func.myApply(newObj,['55','yw']) // xmx 55 yw
复制代码
コード実行効果を適用する
呼び出し実装の参照コード
/**
* 手写call
*/
window.name='gy' // 全局变量
let obj={
name:'ckx'
}
var func=function(b,c){
console.log(`this=`, this)
console.log(this.name,b,c)
return 1
}
func('24','hz') // gy 24 hz
func.call(obj,'24','hz') // ckx 24 hz
let newObj={
name:'xmx',
age:24
}
// call 和apply需要注意参数的格式即可
Function.prototype.myCall=function(base,...args){
// 1. 如果指向是null 或者undefined 则指向window
base=base || window
// 2. 根据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性
base.fn=this
// 3.执行函数,调用base.fn时,fn中的函数指向 base对象
let result=base.fn(...args)
// 4. 删除base的fn属性
delete base.fn
// 5. 返回result 结果
return result
}
func.myCall(newObj,'55','yw') // xmx 55 yw
复制代码
コールコード実行効果
バインド実装の参照コード
/**
* 手写bind
*/
window.name = "gy"; // 全局变量
let obj = {
name: "ckx",
};
var func = function (b, c,d) {
console.log(`this=`, this);
console.log(this.name, b, c,d);
return 1;
};
func("24", "hz",26); // gy 24 hz 26
let funcRes = func.bind(obj, "24", "hz");
funcRes(24); // ckx 24 hz 24
let newObj = {
name: "xmx",
age: 24,
};
// 注意bind 返回的时绑定的函数以及可以多次传递参数
Function.prototype.myBind = function (base, ...args1) {
return (...args2) => {
// 1. 如果指向是null 或者undefined 则指向window
base = base || window;
// 2. 根据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性
base.fn = this;
// 3.执行函数,调用base.fn时,fn中的函数指向 base对象
let result = base.fn(...args1,...args2);
// 4. 删除base的fn属性
delete base.fn;
// 5. 返回result 结果
return result;
};
};
let myfuncRes=func.myBind(newObj, "55", "yw")
myfuncRes(24) // xmx 55 yw 24
复制代码
バインドコード実行効果
2.手書きの新しい
新しいキーワードは実行時に何をしますか?
1. 创建了一个新对象
2. 将这个新对象与构造函数用原型链链接起来
3. 将构造函数的this指向新的对象,执行构造函数的代码赋值
4. 如果构造函数没有返回一个对象就返回新创建的对象否则返回构造函数返回的对象
复制代码
手書きの新しい参照コード
/***
* 手写new关键字执行
*/
function Person(name,age) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
let a = new Person('gy');
console.log(a);
console.log(a.getName());
const myNew = (Func, ...args) => {
let newObj = {};
newObj.__proto__=Func.prototype
let result=Func.apply(newObj,args)
return typeof result == Object ? result: newObj
};
let b = myNew(Person,'gy1')
console.log(b);
console.log(b.getName());
复制代码
コード実行結果参照図
プロトタイプチェーンの概略図
3.手書きのinstanceof
typeof 可以判断基本数据类型 但是null 返回的也是object 不能识别 引用数据类型
instanceof 可以准确的判断引用数据类型不可以判断 基本数据类型
instanceof是用于检测构造函数的prototype是否出现某个实例对象的原型链上
复制代码
参照コード
/**
* 手写instanceof
*/
let obj= { label:'gy' }
let arr= ['hello']
let result = obj instanceof Object
let result1 = arr instanceof Array
let result2 = arr instanceof Object
let result3 = obj instanceof Array
console.log('result=',result )
console.log('result1=',result1 )
console.log('result2=',result2 )
console.log('result3=',result3 )
const myInstanceof = (left,right)=>{
if(typeof left != 'object' || left == null ) return false
let proto= Object.getPrototypeOf(left)
while(true){
if(proto==null) return false
if(proto==right.prototype) return true
proto=Object.getPrototypeOf(proto)
}
}
const myResult= myInstanceof(obj,Object)
const myResult1= myInstanceof(arr,Array)
const myResult2= myInstanceof(arr,Object)
const myResult3= myInstanceof(obj,Array)
console.log('myRsult=',myResult )
console.log('myResult1=',myResult1 )
console.log('myResult2=',myResult2 )
console.log('myResult3=',myResult3 )
复制代码
コード実行結果のスクリーンショット
根据上面的代码打印结果 需要注意的是:万物皆对象,包括数组,如果存在一个变量(arrOrObj)可能为array或者object 如果使用instanceof 去判断,一定需要先判断是否为数组先,否则 arrOrObj instanceof Object 一定为true 就无法区分 array和object
4.手書きの安定化とスロットル
持续的触发某一事件,延迟n秒后执行回调,在未到n秒再次触发,会从新出发倒计时
持续的触发某一时间,延迟n秒后执行回调,在未达到n秒再次出发,不会重新计时
复制代码
両方のシナリオを使用する
防抖
サーバーの動的検索結果へのユーザー入力コンテンツなど、予測できないユーザーのアクティブな動作に使用される場合があります。ユーザーの入力速度は予測不可能で不規則です。
节流
これは、ユーザーが製品ウィンドウをスライドするときに埋め込みポイントの要求を送信するなど、一部の非ユーザーアクティブ動作または予測可能なユーザーアクティブ動作に使用できます。スライド固定高さは既知のロジックであり、規則性があります。
节流
防抖
クロージャのアプリケーションでもあります
手書きの防振コードリファレンス
/***
* 手写防抖
*/
const debounce = (func, delay) => {
let timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
func(args);
}, delay);
};
};
const getfn = (data) => {
console.log(data);
};
debounce(getfn, 2000)("gy");
复制代码
手書きの手ぶれ防止コードの実行結果
手書きのスロットル
/***
* 手写节流
* 这里只需要注意和防抖不同的时 不会清除定时器
*/
const throttle = (func, delay) => {
let flag = false;
return function (...args) {
if (flag) return
flag=true
setTimeout(() => {
func(args);
flag=false
}, delay);
};
};
const getfn = (data) => {
console.log(data);
};
throttle(getfn, 2000)("gy");
复制代码
5.ajaxを手動で実装します
AJAX 的全称为 Asynchronous JavaScript + XML, 最重要的要属 XHR(XMLHttpRequest)
XMLHttpRequest通过不刷新页面请求特定URL,获取数据。
复制代码
実装の前提条件
-
XMLHttpRequest()
コンストラクターです -
XMLHttpRequest.onreadystatechange
ステータスコードが変更されたときにイベントをトリガーします(すべてのブラウザーでサポートされています) -
XMLHttpRequest.readyState
リクエストのステータスコード
XMLHttpRequest.status
応答ステータスコードは、標準のHTTPステータスコードを返します
-
その他の要求応答パラメーター
XMLHttpRequest.response 这个是整个响应实体 XMLHttpRequest.responseText 返回 `DOMString` XMLHttpRequest.timeout 超时时间 XMLHttpRequest.upload 上传进度 复制代码
-
一般的な方法を見る
open()
// method/url 是必须的
xhr.open(method, url, async, user, password);
复制代码
send()
// body 可选默认为null
// 可以是 Blob, BufferSource (en-US), FormData,
// URLSearchParams, 或者 USVString 对象.
XMLHttpRequest.send(body);
复制代码
setRequestHeader()
XMLHttpRequest.setRequestHeader(header, value);
// 例如
XMLHttpRequest.setRequestHeader ("content-type", "application/x-www-form-urlencoded" );
复制代码
上記のAPIに基づいてajaxを実装します
1. 构造一个请求 XMLHttpRequest
2. 初始化一个请求 open
3. 监听请求 onreadystatechange
4. 发送该请求 send
复制代码
/**
* 手写一个ajax
*/
const myAjax =(url,methods,header,success,error)=>{
// 创建一个请求
let request=new XMLHttpRequest()
// 设置请求头
for (const key in header) {
request.setRequestHeader(key,header[key])
}
// 初始化请求
request.open(methods,url)
// 发送请求
request.send()
// 监听请求 onreadystatechange
request.onreadystatechange =function(){
if(request.readyState==4){
if(request.status==200){
success(request.response)
}else {
error()
}
}
}
}
复制代码
要約する
欢迎提出更好的思路以及其他必备手写功能
复制代码