Home  >  Article  >  Web Front-end  >  Compilation and sharing of some frequent errors in JavaScript

Compilation and sharing of some frequent errors in JavaScript

小云云
小云云Original
2018-03-30 09:23:071094browse

1. Foreword

During this period of time, there are many people interviewing and sharing interview questions. Some time ago, I also served as an interviewer temporarily. In order to roughly understand the level of the interviewers, I also wrote a question and interviewed several front-end developers. During this period of time, I was learning and writing about some knowledge about design patterns. Unexpected knowledge about design patterns was the test point that frequently tripped people up in interview questions.

So, today I will summarize the test points that make people fall into traps. Not much to say below, let’s take a look at the detailed introduction.

2. Object-oriented programming

Regarding object-oriented and process-oriented, I personally feel that the two are not absolutely independent. , but a mutually reinforcing relationship. As for when to use object-oriented and when to use process-oriented, specific situations require detailed analysis.

For object-oriented programming. There is a highly praised answer on Zhihu:

Object-oriented: Dog. Eat (shit)

Process-oriented: Eat. (Dog, shit)

But This example seems not very elegant, so I changed it and gave a more elegant example to illustrate the difference between object-oriented and process-oriented.

Requirements: Definition of 'waiting to eat hot pot'

The object-oriented thinking is: waiting. Action (eating hot pot)

The process-oriented thinking is: action (waiting, eating Hot pot)

Code implementation:


//面向对象
//定义人(姓名)
let People=function(name){
 this.name=name;
}
//动作
People.prototype={
 eat:function(someThing){
 console.log(`${this.name}吃${someThing}`);
 }
}
//守候是个人,所以要创建一个人(new一次People)
let shouhou=new People('守候','男',24);
shouhou.eat('火锅');

//面向过程
let eat=function(who,someThing){
 console.log(`${who}吃${someThing}`);
}
eat('守候','火锅');

The results are the same, they all output 'Waiting to eat hot pot'. But what if I'm full now and ready to code. How to achieve this? Looking at the code


//面向对象
shouhou.coding=function(){
 console.log(this.name+'写代码');
}
shouhou.coding();
//面向过程
let coding=function(who){
 console.log(who+'写代码');
}
coding('守候');

The result is the same: 'Waiting to write code'

But it is not difficult to find that object-oriented is more flexible, reusable and scalable . Because object-oriented is to perform certain actions against objects (in the example: 'waiting'). These actions can be customized and extended.

Process-oriented defines many actions to specify who will perform the action.

Okay, that’s it for the simple explanation of object-oriented. As for the three major characteristics of object-oriented: inheritance, encapsulation, and polymorphism, you can search the Internet for information by yourself.

3.this

When developing using JavaScript, many developers will be more or less confused by the pointer of this , but in fact, regarding the pointing of this, remember the most core sentence: which object calls the function, and this in the function points to which object.

Let’s talk about it in several cases

3-1. Ordinary function call

There is no special surprise in this case, it just points to the global object-window.


let username='守候'
function fn(){
 alert(this.username);//undefined
}
fn();

You may be confused as to why it is not an output wait, but after a closer look, I declared it as a let, not a window object

If the output is waiting, write like this


var username='守候'
function fn(){
 alert(this.username);//守候
}
fn();
//---------------
window.username='守候'
function fn(){
 alert(this.username);//守候
}
fn();

3-2. Object function call

this I believe it is not difficult to understand, it is the function call, where this points to


window.b=2222
let obj={
 a:111,
 fn:function(){
 alert(this.a);//111
 alert(this.b);//undefined
 }
}
obj.fn();

Obviously, the first time is to output obj.a, which is 111. The second time, obj does not have the attribute b, so the output is undefined, because this points to obj.

But you have to pay attention to the following situation


let obj1={
 a:222
};
let obj2={
 a:111,
 fn:function(){
 alert(this.a);
 }
}
obj1.fn=obj2.fn;
obj1.fn();//222

I believe this is not difficult to understand. Although obj1.fn is assigned from obj2.fn, but calling The function is obj1, so this points to obj1.

3-3. Constructor call


let TestClass=function(){
 this.name='111';
}
let subClass=new TestClass();
subClass.name='守候';
console.log(subClass.name);//守候
let subClass1=new TestClass();
console.log(subClass1.name)//111

This is not difficult to understand, recall (the four of new steps) and that’s it!

But there is a pitfall. Although it generally does not appear, it is necessary to mention it.

Returning an object in the constructor will return the object directly instead of the object created after executing the constructor

3-4 .apply and call call

apply and call simply change the this passed into the function.


let obj1={
 a:222
};
let obj2={
 a:111,
 fn:function(){
  alert(this.a);
 }
}
obj2.fn.call(obj1);

Although obj2 calls the method at this time, call is used to dynamically point this to obj1. Equivalent to this obj2.fn, the execution environment is obj1. The details of apply and call are mentioned below.

3-5. Arrow function call

First of all, I have to say that ES6 provides arrow functions, which increases our development efficiency, but in arrow functions Inside, there is no this. This inside the arrow function inherits the external environment.

An example


let obj={
 a:222,
 fn:function(){ 
  setTimeout(function(){console.log(this.a)})
 }
};
obj.fn();//undefined

It is not difficult to find that although this in fn() points to obj, what is passed to setTimeout is an ordinary function, this The pointer is window, and there is no a below window, so undefined is output here.

Replace with arrow function


let obj={
 a:222,
 fn:function(){ 
  setTimeout(()=>{console.log(this.a)});
 }
};
obj.fn();//222

这次输出 222 是因为,传给 setTimeout 的是箭头函数,然后箭头函数里面没有 this ,所以要向上层作用域查找,在这个例子上, setTimeout 的上层作用域是 fn。而 fn 里面的 this 指向 obj ,所以 setTimeout 里面的箭头函数的 this ,指向 obj 。所以输出 222 。

4.call和apply

call 和 apply 的作用,完全一样,唯一的区别就是在参数上面。

call 接收的参数不固定,第一个参数是函数体内 this 的指向,第二个参数以下是依次传入的参数。

apply接收两个参数,第一个参数也是函数体内 this 的指向。第二个参数是一个集合对象(数组或者类数组)


let fn=function(a,b,c){
console.log(a,b,c);
}
let arr=[1,2,3];


如上面这个例子


let obj1={
 a:222
};
let obj2={
 a:111,
 fn:function(){
  alert(this.a);
 }
}
obj2.fn.call(obj1);

call 和 apply 两个主要用途就是

1.改变 this 的指向(把 this 从 obj2 指向到 obj1 )

2.方法借用( obj1 没有 fn ,只是借用 obj2 方法)

5.闭包

闭包这个可能大家是迷糊,但是必须要征服的概念!下面用一个例子简单说下


let add=(function(){
let now=0;
return {
 doAdd:function(){
 now++;
 console.log(now);
}
}
})()

然后执行几次!

上图结果看到,now 这个变量,并没有随着函数的执行完毕而被回收,而是继续保存在内存里面。

具体原因说下:刚开始进来,因为是自动执行函数,一开始进来会自动执行,这一块

然后把这个对象赋值给 add 。由于 add 里面有函数是依赖于 now 这个变量。所以 now 不会被销毁,回收。这就是闭包的用途之一(延续变量周期)。由于 now 在外面访问不到,这就是闭包的另一个用途(创建局部变量,保护局部变量不会被访问和修改)。

可能有人会有疑问,闭包会造成内存泄漏。但是大家想下,上面的例子,如果不用闭包,就要用全局变量。把变量放在闭包里面和放在全局变量里面,影响是一致的。使用闭包又可以减少全局变量,所以上面的例子闭包更好!

6.小结

在学设计模式的时候,遇到的知识点就是这一些了,这些知识点,也是我在群聊,社区里面,让人掉坑比较多的考点。这些知识,可以说是开发常用,面试常考的知识,还是建议大家深入些学习。上面那里也是简单的过一下而已。不算深入。如果大家对文章有什么建议,欢迎指点。

相关推荐:

JavaScript面试基础知识题分享


The above is the detailed content of Compilation and sharing of some frequent errors in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn