前端面试的套路貌似越来越深了,尤其是当面试官向你抛来各种JS原理性的问题时,蒙蒙的感觉就上来了。所以是时候准备些反套路了……
注:本文仅提供了相应的核心原理及思路,部分细节未处理。 [h3]一、call、apply与bind的实现[/h3]- 由于、与都是属于对象下的方法,所以每个实例都拥有有、与属性。
- 相同点:都是为改变指向而存在的。
- 异同点:使用方法时,传递给函数的参数必须逐个列举出来,使用方法时,传递给函数的是参数数组。和很相似,第一个参数是的指向,从第二个参数开始是接收的参数列表。方法不会立即执行,而是返回一个改变了上下文后的函数,用于稍后调用。、则是立即调用。
1、call实现原理:- Function.prototype.mycall = function (context) {
复制代码- // 当context为null时,其值则为window
复制代码- context = context || window;
复制代码- // this为调用mycall的函数。将this赋值给context的fn属性
复制代码- // 将arguments转为数组,并从下标1位置开如截取
复制代码- let arg = [...arguments].slice(1);
复制代码- // 将arg数组的元素作为fn方法的参数执行,结果赋值给result
复制代码- let result = context.fn(...arg);
复制代码 测试:
- return this.a + this.b + c + d;
复制代码- console.log(add.mycall(obj, 3, 4)); // 10
复制代码 2、apply实现原理
- Function.prototype.myapply = function (context) {
复制代码- // 当context为null时,其值则为window
复制代码- context = context || window
复制代码- // this为调用myapply的函数。将this赋值给context的fn属性
复制代码- let arg = arguments[1] || [];
复制代码- // 将arg数组的元素作为fn方法的参数执行,结果赋值给result
复制代码- let result = context.fn(...arg);
复制代码 测试:
- return this.a + this.b + c + d;
复制代码- console.log(add.myapply(obj, [5, 6])); // 14
复制代码- [/code]
- [/list]3、bind实现原理[list][*][*][*][*][*][*][*][*][*][*][*][/list][code]Function.prototype.mybind = function (context) {
复制代码- // this为调用mybind的函数。将this赋值给变量_this
复制代码- // 将arguments转为数组,并从下标1位置开如截取
复制代码- let arg = [...arguments].slice(1);
复制代码- return _this.apply(context, arg.concat(...arguments));
复制代码 测试:
- siteName: "zhangpeiyue.com"
复制代码- function printSiteName() {
复制代码- console.log(this.siteName);
复制代码- var site = printSiteName.mybind(obj);
复制代码- console.log(site) // function () { … }
复制代码- site();// zhangpeiyue.com
复制代码 [h3]二、浅拷贝与深拷贝[/h3]- 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用。
- 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”。
- 我们希望在改变新的数组(对象)的时候,不改变原数组(对象)时需要使用深拷贝。
1、浅拷贝实现原对象
- console.log(copy1 === obj);// false
复制代码- console.log(copy1.info === obj.info);// true
复制代码- console.log(copy1.siteName);// 张培跃
复制代码- [/code][code]// 2. Object.assign实现
复制代码- let copy2 = Object.assign({},obj);
复制代码- console.log(copy2 === obj);// false
复制代码- console.log(copy2.info === obj.info);// true
复制代码- console.log(copy2.siteName);// 张培跃
复制代码- [/code][code]// 3、for in 实现
复制代码- console.log(copy2 === obj);// false
复制代码- console.log(copy2.info === obj.info);// true
复制代码- console.log(copy2.siteName);// 张培跃
复制代码 原数组- console.log(copy1 === arr);// false
复制代码- console.log(copy1[0].info === arr[0].info);// true
复制代码- console.log(copy1[0].siteName);// 张培跃
复制代码- [/code][code]// 2. Array.from实现
复制代码- let copy2 = Array.from(arr);
复制代码- console.log(copy2 === arr);// false
复制代码- console.log(copy2[0].info === arr[0].info);// true
复制代码- console.log(copy2[0].siteName);// 张培跃
复制代码- [/code][code]// 3、forEach实现
复制代码- arr.forEach(v=>copy3.push(v));
复制代码- console.log(copy3 === arr);// false
复制代码- console.log(copy3[0].info === arr[0].info);// true
复制代码- console.log(copy3[0].siteName);// 张培跃
复制代码- let copy4 = arr.map(v=>v);
复制代码- console.log(copy4 === arr);// false
复制代码- console.log(copy4[0].info === arr[0].info);// true
复制代码- console.log(copy4[0].siteName);// 张培跃
复制代码 2、深拷贝实现- JOSN.stringify()/JSON.parse()
- const copy1 = JSON.parse(JSON.stringify(obj));
复制代码- console.log(copy1 === obj);// false
复制代码- console.log(copy1.info === obj.info);// false
复制代码- console.log(copy1.info.props === obj.info.props);// false
复制代码- console.log(copy1.siteName);// 张培跃
复制代码- function deepClone(obj) {
复制代码- let copy = obj instanceof Array ? [] : {}
复制代码- if (obj.hasOwnProperty(i)) {
复制代码- copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
复制代码- const copy1 = deepClone(obj);
复制代码- console.log(copy1 === obj);// false
复制代码- console.log(copy1.info === obj.info);// false
复制代码- console.log(copy1.info.props === obj.info.props);// false
复制代码- console.log(copy1.siteName);// 张培跃
复制代码- [/code]
- [/list][h3]三、setTimeout模拟setInterval[/h3][list][*][code]setTimeout
复制代码 和的语法相同。它们都有两个参数,一个是将要执行的代码字符串,还有一个是以毫秒为单位的时间间隔。
- setInterval(()=>{}, 1000);
复制代码- setTimeout(()=>{}, 1000);
复制代码- [/code]
- [/list][list][*]区别: [code]setInterval
复制代码 在执行完一次代码之后,经过指定的时间间隔,执行代码,而只执行一次那段代码。
- 注意:假设定时器指定时间为1秒,而函数的执行时间是2秒,则的总运行总时长为3秒。而不会被调用的函数所束缚,它只是简单地每隔一定时间就重复执行一次指定的函数。所以在函数的逻辑比较复杂,所处理的时间较长时,有可能会产生连续干扰的问题。若要避免这一问题,建议通过来模拟一个。
实现:
- // 可避免setInterval因执行时间导致的间隔执行时间不一致
复制代码- setTimeout (function () {
复制代码- setTimeout (arguments.callee, 500)
复制代码 四、 new本质
new 构造函数的执行流程:- 创建对象,并给予属性名为,值为构造函数原型()的属性。
- 将构造函数的指向为刚创建的对象。
- 执行构造函数的语句。
- 将创建的对象进行返回。
- // 创建一个新对象且将其隐式原型指向构造函数原型
复制代码- __proto__ : fun.prototype
复制代码- fun.call(obj, ...arguments);
复制代码- [/code][code]function Site(siteName, siteUrl) {
复制代码- this.siteName = siteName;
复制代码- let obj = myNew(Site)("张培跃","http://www.zhangpeiyue.com");
复制代码- console.log(obj);// { siteName: '张培跃', siteUrl: 'http://www.zhangpeiyue.com' }
复制代码 五、 instanceof的原理来判断对象的具体类型,当然,也可以判断一个实例是否是其父类型或者祖先类型的实例。先来看几个示例:
- [/code][code]function Desk(){}
复制代码- [/code][code]var desk1 = new Desk();
复制代码- console.log(desk1 instanceof Desk);// true
复制代码- console.log(desk1 instanceof Object);// true
复制代码- [/code][code]Desk.prototype = Box.prototype;
复制代码- console.log(desk1 instanceof Desk);// false
复制代码- console.log(desk1 instanceof Box);// false
复制代码- console.log(desk1 instanceof Object);// true;
复制代码- [/code][code]var desk2= new Desk();
复制代码- console.log(desk2 instanceof Desk);// true
复制代码- console.log(desk2 instanceof Box);// true
复制代码- console.log(desk2 instanceof Object);// true
复制代码- [/code][code]Desk.prototype = null;
复制代码- console.log(desk3 instanceof Box);// false
复制代码- console.log(desk3 instanceof Object);// true
复制代码- console.log(desk3 instanceof Desk); // error
复制代码- [/code]
- [/list][list][*][code]instanceof
复制代码 的原理是:右边变量的原型是否存在于左边变量的原型链上。如果在,返回,如果不在则返回false。不过有一个特殊的情况,当右边的为将会报错(类似于空指针异常)。
- 实现:
- function instanceOf(left, right) {
复制代码- let leftProto = left.__proto__
复制代码- let rightPrototype = right.prototype
复制代码- if(rightPrototype === null){
复制代码- throw new TypeError('Function has non-object prototype null in instanceof check');
复制代码- if (leftProto === rightPrototype)
复制代码- leftProto = leftProto.__proto__;
复制代码- [/code][code]function Desk(){}
复制代码- [/code][code]var desk1 = new Desk();
复制代码- console.log(instanceOf(desk1,Desk));// true
复制代码- console.log(instanceOf(desk1,Object));// true
复制代码- [/code][code]Desk.prototype = Box.prototype;
复制代码- console.log(instanceOf(desk1,Desk));// false
复制代码- console.log(instanceOf(desk1,Box));// false
复制代码- console.log(instanceOf(desk1,Object));// true;
复制代码- [/code][code]var desk2= new Desk();
复制代码- console.log(instanceOf(desk2,Desk));// true
复制代码- console.log(instanceOf(desk2,Box));// true
复制代码- console.log(instanceOf(desk2,Object));// true
复制代码- [/code][code]Desk.prototype = null;
复制代码- console.log(instanceOf(desk3,Box));// false
复制代码- console.log(instanceOf(desk3,Object));// true
复制代码- console.log(instanceOf(desk3,Desk));// error
复制代码 未完,待续!
—————END—————
喜欢本文的朋友们,欢迎长按下图关注公众号
张培跃,收看更多精彩内容
|
|