js 中 new call apply bind JSON.stringify 的原理以及模拟实现
1.new的原理和实现
它创建了一个全新的对象。
它会被执行
[[Prototype]]
(也就是__proto__
)链接。它使
this
指向新创建的对象。通过
new
创建的每个对象将最终被[[Prototype]]
链接到这个函数的prototype
对象上。如果函数没有返回对象类型
Object
(包含Functoin,Array,Date,RegExg,Error
),那么new
表达式中的函数调用将返回该对象引用。
var A = function(x, y){
this.x = x;
this.y = y;
this.add = function(){
console.log(this.x + this.y)
}
}
A.prototype.sayHello = function(){
console.log('hello !')
} function New(func) {
var res = {}
if(func.prototype !== null){
res.__proto__ = func.prototype;
}
// Array.prototype.slice.call(arguments, 1) 是获取参数 arguments[0]是 func 去掉不用
// 更多argument的更多说明看这个: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments
// 用apply 不用call 是因为 Array.prototype.slice.call(arguments, 1) 的结果是一个数组。
// 执行一次func的原因是要让 A 函数执行初始化 简单来说就是给 x y add 赋值
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
return ret;
}else {
return res;
}
}
var obj = New(A, 1, 2)
// 或者
var obj = new A(1,2)
2.JSON.stringify的原理和实现
Boolean|Number|String
类型会自动转换成对应的原始值。undefined
、任意函数以及symbol
,会被忽略(出现在非数组对象的属性值中时),或者被转换成null
(出现在数组中时)。不可枚举的属性会被忽略
平常用的用 JSON.parse(JSON.stringify(obj)) 实现深度克隆的时候, value 是 undefined
、函数以及 symbol的 key 都会消失,原因就是上面第二条
// 对于元素是数组的情况还没做处理,有兴趣的可自己试试
function json2str(o) {
let arr = [];
const fmt = function(s) {
if(typeof s == 'object' && s !== null){
return json2str(s);
}
// undefine symbol function的时候 设置为空, 注意区分 '' 与 `"${s}"`, 后者多了 "", 不是真正的空
if(s === null) {
return null
} else if (s === false) {
return false
} else if(/^(undefined|symbol|function)$/.test(typeof s)) {
return ''
} else {
return `"${s}"`
}
}
for (var i in o) {
// 如果是空 就代表是 undefine symbol function 就不用了,去掉
if(fmt(o[i]) === null || fmt(o[i]) === false || fmt(o[i])){
arr.push(`"${i}":${fmt(o[i])}`)
}
}
return `{${arr.join(',')}}`
} var obj = {
name: '唐伯龙',
age: '20',
msg: {
title:'11',
face:'22'
},
a: function func(){alert('1')},
b: false,
c: null,
d: undefined, e: Symbol(),
e: ''
}
// 下面两个打印的结果是一样的
console.log(JSON.stringify(obj))
console.log(json2str(obj))
console.log(JSON.stringify(obj)) 与 console.log(json2str(obj))的结果如下,一模一样:
3.call apply 的原理和实现
更详细的解释看这里https://www.jianshu.com/p/af3f41d8ef99
call
语法:
fun.call(thisArg,arg1,arg2,...)
,调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
apply
语法:
func.apply(thisArg,[argsArray])
,调用一个函数,以及作为一个数组(或类似数组对象)提供的参数。
call 代码实现如下:
Function.prototype.call2 = function (context) {
var context = context || window; // 当context是null 的时候 this 指向window
context.fn = this; var args = [...arguments].slice(1); var result = context.fn(args); delete context.fn
return result;
} // 测试一下
var value = 2; var obj = {
value: 1
} function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
} bar.call(null); // 当传入null的时候 this指向window, 所以输出 2 console.log(bar.call2(obj, 'Cherry', 18));
apply 代码实现如下 (其实就是传入的第二个参数变成了一个数组) :
Function.prototype.call2 = function (context, arr) {
var context = context || window; // 当context是null 的时候 this 指向window
context.fn = this;
var result = ''
if(!arr) {
result = context.fn()
} else {
var args = [];
for(var i = 0; i < arr.length; i++) {
args.push('arr[' + i + ']');
}
result = eval('obj.fn('+args+')');
}
delete context.fn
return result;
} // 测试一下
var value = 2; var obj = {
value: 1
} function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
} bar.call(null); // 当传入null的时候 this指向window, console.log(bar.call2(obj, ['Cherry', 18]));
4.bind 的原理和实现
更详细的说明看这里:https://blog.csdn.net/daimomo000/article/details/72897035
bind()
方法:
会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )
Function.prototype.bind2 = function (context) { if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
} var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {}; var fbound = function () {
self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
} fNOP.prototype = this.prototype;
fbound.prototype = new fNOP(); return fbound; }
js 中 new call apply bind JSON.stringify 的原理以及模拟实现的更多相关文章
- js中的call,apply,bind区别
在JavaScript中,call.apply和bind是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向. call.apply.bind方法的共同点和区别:app ...
- js中call和apply的实现原理
js中call和apply的实现原理 实现call的思路: /* 还有就是call方法是放在Function().prototype上的也就是构造函数才有的call方法 (我门可 ...
- [转]js中几种实用的跨域方法原理详解
转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...
- js中call、apply、bind那些事
前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如- 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...
- js中call、apply和bind的区别
在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢.在说区别之前还是先总结一下三者的相似之处:1.都是用来改变函数的this对象的指向的.2.第一个参数都是this要指向的对 ...
- js中call、apply、bind那些事2
前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如… 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...
- js中call、apply和bind到底有什么区别?
介绍 在js中,每个函数的原型都指向Function.prototype对象(js基于原型链的继承).因此,每个函数都会有apply,call,和bind方法,这些方法继承于Function. 它们的 ...
- js中call,apply,bind方法的用法
call .apply.和bind 以上这三个方法都是js function函数当中自带的方法,用来改变当前函数this的指向. call()方法 语法格式: fun.call(thisArg[,ar ...
- 别真以为JavaScript中func.call/apply/bind是万能的!
自从学会call/apply/bind这三个方法后我就各种场合各种使用各种得心应手至今还没踩过什么坑,怎么用?说直白点就是我自己的对象没有某个方法但别人有,我就可以通过call/apply/bind去 ...
随机推荐
- 正则表达式 re模块的使用
一 正则表达式 首先, 我们在网页上进行行注册或者登陆的时候经常能看到一些格式上的错误提示. 比如:你在注册百度账号的时候 https://passport.baidu.com/v2/?reg&am ...
- 3. Dictionaries and Sets
1. Generic Mapping Types The collections.abc module provides the Mapping and MutableMapping ABCs to ...
- springcloud——学习
构建分布式系统 配置管理 服务发现 断路器.路由.微代理.事件总线 全局锁.决策竞选. springCloud是一个微服务框架, 提供多种功能. 底层封装的HttpClinet springCloud ...
- Collection 和 Collections 有什么区别?(未完成)
Collection 和 Collections 有什么区别?(未完成)
- css hack的理解
什么是CSS hack 由于不同厂商的流览器或某浏览器的不同版本(如IE6-IE11,Firefox/Safari/Opera/Chrome等),对CSS的支持.解析不一样,导致在不同浏览器的环境中呈 ...
- crontab踩坑(一)
因为 我们用conda托管了python虚拟环境,我自身的环境是wqbin,本来crontab脚本的命令是如下: 发生了如下的报错: 因为这里的环境是启动的是base的 所以找不相应的模块.于是我在执 ...
- Codeforces Round #588 (Div. 2) C. Anadi and Domino(思维)
链接: https://codeforces.com/contest/1230/problem/C 题意: Anadi has a set of dominoes. Every domino has ...
- Spring中,请求参数处理
Spring中,Controller里,获取请求数据有多种情况 在使用@RequestParam的方式获取请求中的参数时, 如果没有设置required这个属性,或者主动设置为true,则意味着这个参 ...
- BZOJ 4070: [Apio2015]雅加达的摩天楼 根号分治+spfa
此题卡Dijkstra... Code: #include <bits/stdc++.h> #define N 30005 #define M 4000000 #define ll lon ...
- C#+Entity Frame work+MVC+Mysql+Apicloud共享汽车管理系统【论文】+Apicloud开发实例
摘要: 共享汽车管理系统主要分为后台管理PC端和手机App端,后台管理可以对指定停车点.车辆基本信息.用户注册信息.用户订单信息.推送消息进行管理和维护,而手机app用户可以通过手机号进行短信注册,根 ...