Fork me on GitHub

JS-原理

总结一些 js 函数原理,手写

JavaScript是什么

  1. 脚本编程语言
  2. 弱类型语言
    变量可以被隐式转换成另一个类型。
    • 二元运算+会把两个操作数转换成字符串,除非两个操作数都是数字类型
    • 二元操作符-会把两个操作数转换成数字类型
    • 操作符,包括+-,会把操作数转换成数字。
  3. 动态类型
    变量可以赋值不同类型的值
  4. 单线程
  5. 单线程 - JavaScript 需要与用户交互,操作 DOM,如果多线程的话会带来复杂的同步问题。比如一个线程删除节点,一个线程添加内容,浏览器不知道以哪个线程为准。
  6. 解释型语言 - 会将代码一句一句直接运行,不需要像编译型语言(Compiled language)一样,经过编译器先行编译为机器代码,之后再运行。
    具有良好的跨平台性 - 可以在 Windows、Linux、Android、IOS 等平台运行。

JavaScript 和 ECMAScript 的区别,以及和 DOM 、BOM 的关系

  • ECMAScript
    JavaScript 的语法和基本对象,是 JavaScript 的规范,
  • DOM
    文档对象模型,提供了与网页内容交互的方法接口
  • BOM
    浏览器对象模型,提供了与浏览器交互的方法接口

为什么函数被称为一等公民

在 JS 中,函数可以像传统函数一样声明和调用,也可以像简单值一样:

  • 赋值 var fun=function(){}
  • 传参 function fun(a,callback){callback()}
  • 返回 function(){return function(){}}
    不仅如此,JavaScript 中的函数还充当了类的构造函数的作用,同时又是一个 Function 类的实例(instance)。

手写 call、apply、bind 函数

非严格模式:

  1. 不传入第一个参数,上下文默认为window
  2. 改变this指向,让新的对象可以执行该函数,并能接受参数

call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function mySymbol(obj) {
let unique = (Math.floor(Math.random() * 10) + new Date().getTime()).toString(32).slice(0, 8);
if (obj.hasOwnProperty(unique)) {
return mySymbol(obj) //递归调用
} else {
return unique
}
}
Function.prototype.myCall = function (context) {
// 如果没有传或传的值为空对象 context指向window
context = context || window;
let fnName = mySymbol(context); //保证方法名唯一
context[fnName] = this; //为context添加一个方法,指向this,
//调用方法,去掉第一个参数
let arg = [...arguments].slice(1);
context[fnName](...arg);
delete context[fnName]; //删除方法
}

验证

1
2
3
4
5
6
7
8
9
10
11
 let Person = {
name: 'Tom',
say(age) {
console.log(this);
console.log(`I am ${this.name},my age is ${age}.`)
}
}
let another = {
name: 'John'
}
Person.say.myCall(another, 18)//I am John,my age is 18.

apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function.prototype.myApply = function (context) {
// 如果没有传或传的值为空对象 context指向window
context = context || window;
let fnName = mySymbol(context); //保证方法名唯一
context[fnName] = this; //为context添加一个方法,指向this,
let result;
if (arguments[1]) {
result = context[fnName](...arguments[1])
} else {
result = context[fnName]()
}
delete context[fnName]
return result
}
Person.say.myApply(another, [18]);//I am John,my age is 18.

bind

  1. 函数调用,改变 this
  2. 返回一个绑定 this 的函数
  3. 接收多个参数
  4. 支持柯里化形式传参 fn(1)(2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function.prototype.myBind = function (context) {
//返回一个绑定this的函数,先保存this
let self = this;
//保存参数
let args = [...arguments].slice(1);
//返回一个函数
return function () {
//因为支持柯里化形式传参我们需要再次获取存储参数
let newArg = [...arguments];
console.log(newArg);
// 返回函数绑定this,传入两次保存的参数
//考虑返回函数有返回值做了return
return self.apply(context, args.concat(newArg))
}
}
let fn = Person.say.myBind(another, 118)
fn(18);////I am John,my age is 118.

instanceof 的原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//判断left是不是right的实例
function myInstanceof(left, right) {
let prototype = right.prototype;
left = left.__proto__;
while (true) {
if (left === null || left === undefined) {
return false
}
if (prototype === left) {
return true
}
left = left.__proto__;
}
}

Object.create 实现原理

1
2
3
4
5
6
function create(prototype,props){
const tmp={}
tmp.__proto__=prototype;
Object.defineProperties(tmp,props)
return tmp
}

实现数组的 Map,filter,reduce 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Array.prototype.myMap = function (fn) {
let self = this;
if (self.length === 0 || typeof fn !== 'function') {
return []
}
let result = [];
for (let i = 0; i < self.length; i++) {
let res = fn(self[i], i, self);
result.push(res);
}
return result
}
Array.prototype.myFilter = function (fn) {
let self = this;
if (self.length === 0 || typeof fn !== 'function') {
return []
}
let result = [];
for (let i = 0; i < self.length; i++) {
let res = fn(self[i], i, self);
if (res) {
result.push(self[i]);
}

}
return result
}
Array.prototype.myReducer = function (fn, init) {
let self = this;
if (self.length === 0 && !init) {
return new TypeError('TypeError: Reduce of empty array with no initial value')
}
let result = init === undefined ? self[0] : init;
for (let i = init === undefined ? 1 : 0; i < self.length; i++) {

result = fn(result, self[i], i, self)
}
return result

}
-------------本文结束感谢阅读-------------