美文网首页
不积跬步--JavaScript面试题整理学习(一)

不积跬步--JavaScript面试题整理学习(一)

作者: 雨飞飞雨 | 来源:发表于2019-04-14 22:04 被阅读0次

这个是学习javascript面试视频整理学习的笔记,感觉自己一直在用es6写代码,反而对基础的东西又所欠缺,所以就学习了这个视频,后续还会整理更多打出来。

JS基础

typeof 运算符可以算出来的类型?

typeof undefined // undefined
typeof 'abc'     // string
typeof 123       // number
typeof true      // boolean 
typeof {}        // object
typeof []        // object
typeof null      // object
typeof console.log // function

typeof只能判断值类型,无法具体判断具体的引用类型。

发生强制类型转换的地方

  1. 字符串拼接
  2. == 运算符
  3. if 语句
  4. 逻辑运算
1.字符串拼接
    var a = 100+'10' //'10010'
2. == 运算符
    100 == '100' // true
    0 == ''      // true
    null == undefined // true
    
    他们转换为false 或者转为true
3.if 语句
    var a = true
    if(a){
        //...执行
    }
    var b = 100
    if(b){
        //...执行
    }
    var c = ''
    if(c){
        //...不执行,会转为false
    }
4.逻辑运算符
    console.log(10 && 0)     //0
    console.log('' || 'abc') // 'abc'
    console.log(!window.abc) // true

判断一个变量会被当做true还是false?

var a  =100
console.log(!!a)

何时使用 =====

if(obj.a == null){
    //这里相当于 obj.a === null || obj.a === undefined
    //这是Jquery源码中推荐的写法
}

其他地方通通用===,而不用==,因为它会自动类型转换

JS中的内置函数

Object
Array
Boolean
Number
String
Function
Date
RegExp
Error

JS按存储方式区分变量类型

值类型

var a = 10
var b = a 
a = 11
console.log(b);  // 10

值类型不占用空间,每一次赋值都是深度拷贝
引用类型

var obj1 = {x:100}
var obj2 = obj1
obj1.x = 200
console.log(obje2.x)

引用类型赋值的时候,只复制了对象的引用,多个引用指向一个对象,这样可以节省内存。

如何理解JSON

JSON现在就是一个JS对象,常用的API:

JSON.stringify({a:20,b:20})
JSON.parse('{'a':10,'b':10}')

原型和原型链

构造函数

//构造函数的一个特点就是 函数首字母大写
function Foo(name,age){
    this.name = name
    this.age = age
    this.class = 'class-1'
    //return this //默认有这一行
}
var f = new Foo('zhangsan',20);
//var f1 = new Foo('lisi',22); //创建过个对象

new一个对象的时候,会首先创建一个this的空对象,然后进行赋值,最后默认会返回this

构造函数--扩展

  • var a = {} 其实是var a = new Object()的语法糖
  • var a = [] 其实是 var a = new Array()的语法糖
  • function Foo(){...}其实是 var Foo = new Function(...)
  • 使用instanceof判断一个函数是否是一个变量的构造函数

原型规则和示例

5条原型规则:原型规则是学习原型链的基础

  1. 所有的引用类型(数组,对象,函数),都具有对象特性,即可自由扩展属性(除了null以外)
  2. 所有的引用类型(数组,对象,函数),都有一个__proto__属性,属性值是一个普通的对象,隐式原型
    var obj = {a:10}
    undefined
    console.log(obj.__proto__)
    
    
  3. 所有的函数,都有一个prototype属性,属性值也是一个普通的对象,显示类型
    function fun(){}
    console.log(fn.prototype)
    
  4. 所有的引用类型(数组,对象,函数),__proto__属性值指向它的构造函数的prototype属性值
    var obj = {};
    console.log(obj.__proto__ === Ojbect.prototype)
    
  5. 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数prototype)中寻找
    //构造函数
    function Foo(name){
        this.name = name
    }
    Foo.prototype.alertName = function(){
        alert(this.name)
    }
    //创建示例
    var f = new Foo('zhangsan');
    f.printName = function(){
        console.log(this.name)
    }
    //测试
    f.printName()
    f.alertName()//找不到,调用构造函数prototype的
    
    这里的this无论是原型链中的还是对象中的,都是指向对象本身的

循环便利对象自身的属性

var item
for(item in f){
    //for in 便利的时候会便利原型中的属性,所以我们需要判断它是否属性当前对象的
    if(f.hasOwnProperty(item)){
        console.log(item)   
    }
}

原型链

这里看下面的f.toString()函数,我们并没有在构造函数的prototype中定义,那么应该去哪里找呢?
根据上面定义的第五条规则:
**当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数prototype)中寻找。 **

我们没有在f.__proto__这个对象中找到,那么我们就去它的__proto__中去找,也就是
f.__proto__.__proto__中去找,这就是原型链。

   //构造函数
   function Foo(name){
       this.name = name
   }
   Foo.prototype.alertName = function(){
       alert(this.name)
   }
   //创建示例
   var f = new Foo('zhangsan');
   f.printName = function(){
       console.log(this.name)
   }
   //测试
   f.printName()
   f.alertName()//找不到,调用构造函数prototype的
   f.toString() //

我们看下面的图:

QQ图片20190311101626.png

instanceof

判断一个对象是否数一个构造函数,

f instanceof Foo的判断逻辑是:
f__proto__一层一层往上,能否对应到Foo.prototype
我们在判断 f instanceof Object,同样也是正确的

如何准确判断一个变量是数组类型

```
var arr = [];
arr instanceof Array //true
typeof arr //object typeof判断引用类型除了函数,都是object,无法区分数组
```

写一个原型链继承的例子

//动物
function Animal(){
    this.eat = function(){
        console.log('animal eat');
    }
}
//狗
function Dog(){
    this.bark = function(){
        console.log('dog bark');
    }
}

Dog.prototype = new Animal();
//哈士奇
var hashiqi = new Dog();
//面试的时候写一个实战的例子,这个比较`low`

描述new 一个对象的过程

1.创建一个新对象
2.this指向这个新对象
3.执行代码,即对this赋值
4.返回this

作用域和闭包

常见面试题:

  • 说一下对变量提升的理解
  • 说明this 几种不同的使用场景
  • 创建10个<a>标签,点击的时候弹出对应的序号
  • 如何理解作用域
  • 实际开发中闭包的应用

知识点

执行上下文--变量提升

范围:一段<script>或者一个函数
全局:变量定义,函数声明
函数:变量定义,函数声明,this,arguments

注意:函数声明和函数表达式的区别,函数表达式并不会提前声明哦。

什么意思呢?你知道javaScript是解释型语言,它不会被编译,而是在浏览器里解释执行。所以它在执行之前会把全局里面的变量定义,函数声明,函数里面的变量定义,函数声明,this,arguments摘出来,先把他们都声明了,进行占位。

console.log(a) //undefined
var a  = 100

fn('zhangsan') //'zhangsan' 20
function fun(name){
    age = 20
    console.log(name,age);
    var age
}

所以看上面的代码:上面的代码中,在执行之前,我们会把var afunction fn先拿出来占位,因为是声明,所以会先把他们的值设定为undefined.这个就是变量提升

函数上下文和全局的一样,在函数上下文执行之前,同样也是需要先把变量定义提前声明,拿出来占位了,所以在赋值的时候age=20并没有报错,因为它已经执行之前就声明了。

函数声明和函数表达式
fn()//不会报错
function fn(){
    
}
fn1()//会报错
var fn1 = function(){
    
}

函数声明会变量提升,提前注册,而函数表达式并不会,所以会报错

this

记住一句话: this要在执行时才能确认之,定义时无法确认。

var a = {
    name:"A,
    fn:function (){
        console.log(this.name)
    }
}

a.fn() //this === a
a.fn.call({name:'B'}) // this === {name:'B'}
var fn1 = a.fn
fn1() //this === window

javaScript是解释型语言,它不会进行编译,所以我们在上面定义的对象a,它仅仅只是并定义了,并没有执行,而在执行的时候,才会有它具体的上下文。
在上面列出的代码中有它当时的具体的执行环境,造成了this的指向不同。

总结一下:

  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind

作用域

1.没有块级作用域,所有后来有了letconst
if(true){ var name = "zhangsan" } console.log(name)
因为函数提升的原因,所以我们可以直接打印出来。所以没有块级作用域
2.只有函数和全局作用域
var a = 100 function fn(){ var a = 200 console.log('fn',a) } console.log('global',a) fn()
在第一行中var a = 100,声明后,它是一个全局的变量,任何地方都可以修改它。而如果你不想你声明的变量被被人修改,那么就在你的函数里声明,函数外面是无法修改你的变量的。

作用域链

什么叫自由变量?

var a = 100;
function fn(){
    var b = 200
    //当前作用域没有定义的变量,即“自由变量”
    console.log(a);
    console.log(b);
}
fn();

当我们在函数中打印console.log(a)的时候,在当前函数作用域中并没有定义a,那么它会去函数定义的父级作用域中寻找,当前函数的父级作用域就是全局,所以寻找到的a100.

var a = 100
function F1(){
    var b = 200
    function F2(){
        var c = 300
        console.log(a);
        console.log(b);
        console.log(c);
    }
    F2()
}
F1()

在上面的代码中,当我们在函数F2中执行打印console.log(a);的时候,因为当前函数作用域中并没有定义a,所以就去它定义的父级作用域中寻找,也就是F1,然后发现F1中也没有,那么就继续往上寻找,直到找到。
这就是作用域链。

闭包

看一段代码:

function F1(){
    var a = 100
    //返回一个函数 函数作为返回值
    return function(){
        console.log(a) //a 自由变量,向父级作用域去寻找  ---函数定义的地方
    }
}

var f1 = F1()
var a = 200
f1()

ES5中,由于没有块级作用域,在外部的定义的变量都会变成全局变量,造成了变量的污染,而函数作用域的关系,我们可以通过函数作用域来模拟块级作用域,通过在函数中定义变量,然后在函数中定义函数来访问函数中的变量,可以达到我们的封装变量的目的。这个就是闭包。在上面的代码中,我们定义了一个函数,然后在它的里面定义了一个变量,然后返回一个函数,返回的函数里访问F1中的变量。这样就达到了访问函数中的变量的目的。

闭包的使用场景:

  • 函数作为返回值(例如上面的代码)
  • 函数作为参数传递
function F1(){
    var a = 100
    return function(){
        console.log(a)
    }
}
var f1 = F1()
function F2(fn){
    var a = 300
    fn();
}
F2(f1); //100

创建10个<a>标签,点击的时候弹出来对应的序号

这是个错误的写法:

var i,a
for(i=0;i<10;i++){
    
}

这是正确的写法

var i
for(i=0;i<10;i++){
    (function(i){
        a = document.createElement('a')
    a.innerHTML = i +'<br>'
    a.addEventListener('click',function(){
        e.preventDafault()
        alert(i)
    });
    document.body.appendChild(a)
    })(i)
}

相关文章

  • 不积跬步--JavaScript面试题整理学习(一)

    这个是学习javascript面试视频整理学习的笔记,感觉自己一直在用es6写代码,反而对基础的东西又所欠缺,所以...

  • 不积跬步,可以至千里

    文/《格言》整理 荀子劝世人:不积跬步,无以至千里。 殊不知,驴子日复一日拉磨积跬步,却走不出方寸天地间。 习惯变...

  • 不积跬步

    2018/10/25 星期四 晴 没想到二姐的高价小收音机比手机的辐射要强,放在床边睡觉,...

  • 不积跬步

    “不积跬步无以至千里”常用来激励。 可在自己身上发掘这句名言,却只有垃圾、肥肉和慢。 一个上午,断断续续收拾了两个...

  • 不积跬步

    生活中看起不起眼的事情,对一些人来说就是财富机遇 朋友在我们单位上班,也属于从别的单位挖过来的,老板慧眼识珠,两人...

  • 机器学习-集成学习

    积跬步以致千里,积怠惰以致深渊 注:本篇文章在整理时主要参考了 周志华 的《机器学习》。

  • 不积跬步之JavaScript的数组

    为学习<数据结构与算法>做准备,我们有必要梳理一下数组,因为我们需要它来模拟各种数据结构,如栈,列表,队列等。而实...

  • 盘点初中语文常见易错字辨别,提高知识储备为考试加分

    导语 不积跬步,无以至千里,不积小流,无以成江海。文艺馥心整理为大家整理了中考语文常见初中常见易错字辨别,提高你们...

  • 用坚持丈量成长的厚度

    荀子曰:“不积跬步,无以至千里,不积小流,无以至江海。”学习这件事,贵在坚持,坚持学习,必定收获喜悦。 很...

  • 机器学习-初探

    积跬步以致千里,积怠惰以致深渊 注:本篇文章在整理时主要参考了 周志华 的《机器学习》。 主要内容 对机器学习进行...

网友评论

      本文标题:不积跬步--JavaScript面试题整理学习(一)

      本文链接:https://www.haomeiwen.com/subject/sfjewqtx.html