zoukankan      html  css  js  c++  java
  • js练习题

    1 JS 之基础题目 在三大框架盛行的时代, 基本上会个Vue就能在小公司浑水摸鱼。但是当想突破的时候就会意识到基础的重要性。 JavaScript中有很多重要特性及概念。比如原型,原型链,this,闭包,作用域,隐式转换等等。如果不能熟练掌握,在进阶中级前端开发工程师的道路上必定是困难重重。 用一个小时把这些题做完。检测一下你的基础掌握程度。 进入正题 第 1 题
    if(false){
    var a = 1;
    let b = 2;
    }
    console.log(a);
    console.log(b);
    解析:
    // 输出
    undefined
    ReferenceError: b is not defined
    var不会产生块级作用域,let会产生块级作用域。伪代码相当于:
    var a;
    if(false){
    a = 1;
    let b = 2;
    }
    console.log(a);
    console.log(b);
    第 2 题
    var a = 1;
    if(true){
    console.log(a);
    let a = 2;
    }
    解析:
    // 输出
    ReferenceError: Cannot access 'a' before initialization
    let声明的变量不会提升,并且会产生暂存死区。在let声明变量之前访问变量会抛出错误。 第 3 题
    var a = {n: 1}
    var b = a
    a.x = a = {n: 2}
    console.log(a.n, b.n);
    console.log(a.x, b.x);
    解析:
    // 输出
    2 1
    undefined {n: 2}
    var b = a,此时a和b指向同一个对象。
    .运算符比 = 运算符高,先计算`a.x`,此时
    b = {
    n:1,
    x:undefined
    }
    相当于给对象添加了x属性。
    a.x = a = {n:2};
    计算完a.x,再计算 = ,赋值是从右向左,此时a指向一个新对象。
    a = {
    n:2
    }
    a.x已经执行过了,此时对象的x属性赋值为a,此时
    对象 = {
    n:1,
    x:{
    n:2
    }
    }
    即:
    a = {
    n:2
    }
    b = {
    n:1,
    x:{
    n:2
    }
    }
    第 4 题
    console.log(c);var c;function c(a) { console.log(a); var a = 3; function a(){ }}c(2);
    解析:

    // 输出 function c(a){ console.log(a); var a = 3; function a(){ }}function a(){}
    变量提升也有优先级, 函数声明 > arguments > 变量声明。 第 5 题
    var c = 1;
    function c(c) {
    console.log(c);
    var c = 3;
    }
    console.log(c);
    c(2);
    解析:
    //  输出1TypeError: c is not a function
    由于函数声明会提升,当函数外的console.log©执行时,c已经被赋值为1。因此,执行c(2)时会抛出TypeError,因为1不是函数。 第 6 题
    var name = 'erdong';
    (function () {
    if (typeof name === 'undefined') {
    var name = 'chen';
    console.log(name);
    } else {
    console.log(name);
    }
    })();
    解析:
    // 输出
    chen
    自执行函数执行时,会先进行变量提升(这里涉及到执行上下文不过多说,一定要搞懂执行上下文),在自执行函数执行时,伪代码为:
    var name = 'erdong';
    (function () {
    var name; // 变量name会提升到当前作用域顶部
    if (typeof name === 'undefined') {
    name = 'chen'
    console.log(name)
    } else {
    console.log(name)
    }
    })();
    所以会执行if中的console.log(name) 第 7 题
    var a = 10;
    function test() {
    a = 100;
    console.log(a);
    console.log(this.a);
    var a;
    console.log(a);
    }
    test();
    解析:
    // 输出10010100
    test()为函数独立调用,作用域中的this绑定为全局对象window。 test函数执行时,var a被提升到了作用域顶部,因此函数作用域中存在一个变量a。所以在函数中访问的a都是局部作用域中的a。 第 8 题
    if (!('a' in window)) {
    var a = 1;
    }
    console.log(a);
    解析:
    // 输出
    undefined
    由于if后的{}不会产生块级作用域(不包含let,const时),此时的伪代码为:
    var a;
    if (!(a in window)) {
    a = 1;
    }
    console.log(a);
    var a相当于window.a。因此!(a in window)转成布尔值为false,不会执行a = 1。所有console.log(a)输出undefined。 第 9 题
    var a = 1;function c(a, b) { console.log(a); a = 2; console.log(a);}c();
    解析:
    //输出
    undefined
    2
    跟第4题类似。 第 10 题
    var val=1;
    var obj={
    val:2,
    del:function(){
    console.log(this);
    this.val*=2;
    console.log(val);
    }
    }
    obj.del();
    解析:
    // 输出
    obj(指向的值)
    1
    当通过obj.del()调用del函数时,del函数作用域中的this绑定为obj。 在函数作用域中访问val时,由于函数中并没有变量val,因此实际上访问的是全局作用域中的val,即 1。 这里考察的是this的指向,一定要熟练掌握。 第 11 题:
    var name = "erdong";var object = { name: "chen", getNameFunc: function () { return function () { return this.name; } }}console.log(object.getNameFunc()());
    解析:
    // 输出
    erdong
    object.getNameFunc()(),先执行object.getNameFunc()返回一个函数:
    function () {
    return this.name;
    }
    返回的函数再执行,相当于
    (function () {
    return this.name;
    })();
    此时的this绑定为window。因此输出全局变量name的值erdong。 第 12 题
    var name = "erdong";
    var object = {
    name: "chen",
    getNameFunc: function () {
    var that = this;
    return function () {
    return that.name;
    }
    }
    }
    console.log(object.getNameFunc()());
    解析:
    //输出chen
    object.getNameFunc()执行时,此时getNameFunc中的this绑定为object,因此that = object。object.getNameFunc()返回的函数再执行时,产生闭包,因此返回的函数也能访问到外层作用域中的变量that,因此object.name为object.name,即 chen。 第 13 题
    (function() { var a = b = 3;})();console.log(typeof a === 'undefined');console.log(typeof b === 'undefined');
    解析:
    // 输出truefalse
    首先要明白var a = b = 3是怎样执行的,伪代码:
    b = 3;var a = b;
    因此在自执行函数执行时,b由于未经var等操作符声明,为全局变量。a为函数作用域中的局部变量。因此在外面访问a和b时,其值分别为ReferenceError: a is not defined和3。但是typeof检测未声明的变量不会抛出错误,会返回’undefined’。因此typeof a和typeof b分别返回’undefined’和’number’。 第 14 题
    var a = 6;
    setTimeout(function () {
    a = 666;
    }, 0)
    console.log(a);
    解析:
    //输出6
    setTimeout为宏任务。即使设置延迟为0ms,也是等待同步代码执行完才会执行。因此console.log(a)输出 6 第 15 题
    function fn1() { var a = 2; function fn2 () { a++; console.log(a); } return fn2;}var f = fn1();f();f();
    解析:
    // 输出34
    由于fn1函数执行后返回函数fn2,此时产生了闭包。因此fn2中a访问的是fn1作用域中的变量a,因此第一次a++,之后a为3,第二次之后a为4。 第 16 题
    var a = (function(foo){ return typeof foo.bar;})({foo:{bar:1}});console.log(a);
    解析:
    //输出undefined
    实参foo的值为{foo:{bar:1},因此typeof foo.bar为undefined。 typeof foo.foo.bar为number。 第 17 题
    function f(){ return f;}console.log(new f() instanceof f);
    解析:
    //输出false
    由于构造函数f的返回值为f。因此new f()的值为f。所以console.log(new f() instanceof f)为console.log(f instanceof f),即 false。 第 18 题
    function A () {
    }
    A.prototype.n = 1;
    var b = new A();
    A.prototype = {
    n: 2,
    m: 3
    }
    var c = new A();
    console.log(b.n, b.m);
    console.log(c.n, c.m);
    解析:
    // 输出
    1,undefined
    2,3
    var b = new A(); 实例化b时,A的prototype为
    A.prototype = {
    constructor:A,
    n:1
    }
    当访问b.n和b.m时,通过原型链找到A.prototype指向的对象上,即b.n = 1,b.m = undefined。 var c = new A(); 实例化c时,A的prototype为
    A.prototype = {
    n: 2,
    m: 3
    }
    当访问a.n和a.m时,通过原型链找到A.prototype指向的对象上,此时A.prototype重写,因此a.n = 2,b.m = 3。 第 19 题
    var F = function(){};
    var O = {};
    Object.prototype.a = function(){
    console.log('a')
    }
    Function.prototype.b = function(){
    console.log('b')
    }
    var f = new F();
    F.a();
    F.b();
    O.a();
    O.b();
    解析:
    // 输出
    a
    b
    a
    TypeError: O.b is not a function
    F为函数,它也能访问Object原型上的方法,O为对象,不能访问Function原型上的方法。 F的原型链为:
    F => F.__proto__ => Function.prototype => Function.prototype.__proto__ => Object.prototype
    由于Object.prototype在F的原型链上,所以F能访问Object.prototype上的属性和方法。即: F.a(),F.b()能正常访问。 O的原型链为:
    O => O.__proto__ => Object.prototype
    由于Function.prototype不在O的原型链上,因此O不能访问Function.prototype上的方法,即O.b()抛出错误。 如果你对原型和原型链掌握的好,试着理解下面的示例:
    console.log(Object instanceof Function);
    console.log(Function instanceof Object);
    console.log(Function instanceof Function);
    第 20 题
    function Person() {
    getAge = function () {
    console.log(10)
    }
    return this;
    }
    Person.getAge = function () {
    console.log(20)
    }
    Person.prototype.getAge = function () {
    console.log(30)
    }
    var getAge = function () {
    console.log(40)
    }
    function getAge() {
    console.log(50)
    }
    Person.getAge();
    getAge();
    Person().getAge();
    new Person.getAge();
    getAge();
    new Person().getAge();
    解析:
    // 输出
    20
    40
    10
    20
    10
    30
    Person.getAge();此时执行的是Person函数上getAge方法。
    Person.getAge = function () {
    console.log(20)
    }
    所以输出:20。 getAge();此时执行的是全局中的getAge方法。此时全局getAge方法为:
    function () {
    console.log(40)
    }
    所以输出:40。 Person().getAge();由于Person()单独执行所以,作用域中的this绑定为window,相当于window.getAge()。同上,执行的都是全局getAge 方法,但是Person执行时,内部执行了。
    getAge = function () {
    console.log(10)
    }
    因此全局getAge方法现在为:
    function () {
    console.log(10)
    }
    所以输出:10。 new Person.getAge();此时相当于实例化Person.getAge这个函数,伪代码:
    var b = Person.getAge;
    new b();
    所以输出:20 getAge();执行全局getAge方法,由于在Person().getAge()执行时把全局getAge方法赋值为:
    function () {
    console.log(10)
    }
    所以输出:10。 new Person().getAge();此时调用的是Person原型上的getAge方法:
    Person.prototype.getAge = function () {
    console.log(30)
    }
    所以输出:30。 // 这里要注意:1.变量提升及提升后再赋值。2.调用构造函数时,带()和不带()的区别。 第 21 题
    console.log(false.toString());
    console.log([1, 2, 3].toString());
    console.log(1.toString());
    console.log(5..toString());
    解析:
    // 输出
    'false'
    '1,2,3'
    Uncaught SyntaxError: Invalid or unexpected token
    '5'
    当执行1.toString();时,由于1.也是有效数字,因此此时变成(1.)toString()。没有用.调用toString方法,因此抛出错误。 正确的应该是:
    1..toString();1 .toString();(1).toString();
    第 22 题
    console.log(typeof NaN === 'number');
    解析:
    //输出
    true
    NaN为 不是数字的数字。虽 然它不是数字,但是它也是数字类型。 第 23 题
    console.log(1 + "2" + "2");
    console.log(1 + +"2" + "2");
    console.log(1 + -"1" + "2");
    console.log(+"1" + "1" + "2");
    console.log( "A" - "B" + "2");
    console.log( "A" - "B" + 2);
    解析:
    //输出'122''32''02''112''NaN2'NaN
    首先要明白两点:
    +a,会把a转换为数字。-a会把a转换成数字的负值(如果能转换为数字的话,否则为NaN)。
    字符串与任何值相加都是字符串拼接。
    console.log(1 + “2” + “2”);简单的字符串拼接,即结果为:‘122’。console.log(1 + +“2” + “2”);这里相当于console.log(1 + 2 + “2”);,然后再字符串拼接。即结果为:‘32’。console.log(1 + -“1” + “2”);这里相当于console.log(1 + -1 + “2”);,然后再字符串拼接。即结果为:‘02’。console.log(+“1” + “1” + “2”);这里相当于console.log(1 + “1” + “2”);,然后再字符串拼接。即结果为:‘112’。console.log( “A” - “B” + “2”);,由于’A’ - ‘B’ = NaN,所以相当于console.log( NaN + “2”);, 然后再字符串拼接。即结果为:‘NaN2’。console.log( “A” - “B” + 2);同上,相当于console.log(NaN + 2),由于NaN+任何值还是NaN,即结果为:NaN。 第 24 题
    var a = 666;console.log(++a);console.log(a++);console.log(a);
    解析:
    // 输出
    667
    667
    668
    ++a先执行+1操作,再执行取值操作。此时a的值为667。因此输出667。 a++先执行取值操作,再执行+1。此时输出667,随后a的值变为668。 –a和a–同理。 使用这类运算符时要注意: 1)这里的++、–不能用作于常量。比如
    1++; // 抛出错误
    2)如果a不是数字类型,会首先通过Number(a),将a转换为数字。再执行++等运算。 第 25 题
    console.log(typeof a);
    function a() {}
    var a;
    console.log(typeof a);
    解析:
    // 输出
    'function'
    'function'
    跟第4题类似。函数会优先于变量声明提前。因此会忽略var a。 第 26 题
    var a;
    var b = 'undefined';
    console.log(typeof a);
    console.log(typeof b);
    console.log(typeof c);
    解析:
    // 输出
    'undefined'
    'string'
    'undefined'
    a为声明未赋值,默认为undefined,b的值为字符串’undefined’,c为未定义。 typeof一个未定义的变量时,不会抛出错误,会返回’undefined’。注意typeof返回的都是字符串类型。 第 27 题
    var x = 1;
    if(function f(){}){
    x += typeof f;
    }
    console.log(x);
    解析:
    //输出
    1undefined
    function f(){}当做if条件判断,其隐式转换后为true。但是在()中的函数不会声明提升,因此f函数在外部是不存在的。因此typeof f = ‘undefined’,所以x += typeof f,相当于x = x + ‘undefined’为’1undefined’ 第 28 题
    var str = "123abc";
    console.log(typeof str++);
    解析:
    // 输出
    'number'
    在24题解析时提到,使用++运算符时(无论是前置还是后置),如果变量不是数字类型,会首先用Number()转换为数字。因此typeof str++相当于typeof Number(str)++。由于后置的++是先取值后计算,因此相当于typeof Number(“123abc”)。即typeof NaN,所以输出’number’。 第 29 题
    console.log('b' + 'a' + +'a'+'a');
    解析:
    // 输出
    baNaNa
    ‘b’ + ‘a’ + +‘a’+‘a’相当于’ba’ + +‘a’+‘a’,+‘a’会将’a’转换为数字类型,即+‘a’ = NaN。所以最终得到’ba’ + NaN +‘a’,通过字符串拼接,结果为:baNaNa 第 30 题
    var obj = {n: 1};
    function fn2(a) {
    a.n = 2;
    }
    fn2(obj);
    console.log(obj.n);
    解析:
    // 输出
    2
    函数传递参数时,如果是基本类型为值传递,如果是引用类型,为引用地址的值传递。其实都是值传递。因此形参a和obj引用地址相同,都指向同一个对象。当执行a.n,实际上共同指向的对象修改了,添加了个n属性,因此obj.n为2。 第 31 题
    var x = 10;
    function fn() {
    console.log(x);
    }
    function show(f) {
    var x = 20;
    f();
    }
    show(fn);
    解析:
    // 输出
    10
    JavaScript采用的是词法作用域,它规定了函数内访问变量时,查找变量是从函数声明的位置向外层作用域中查找,而不是从调用函数的位置开始向上查找。因此fn函数内部访问的x是全局作用域中的x,而不是show函数作用域中的x。 第 32 题
    Object.prototype.bar = 1;
    var foo = {
    goo: undefined
    };
    console.log(foo.bar);
    console.log('bar' in foo);
    console.log(foo.hasOwnProperty('bar'));
    console.log(foo.hasOwnProperty('goo'));
    解析:
    //输出
    1
    true
    false
    true
    in操作符:检测指定对象(右边)原型链上是否有对应的属性值。 hasOwnProperty方法:检测指定对象自身上是否有对应的属性值。两者的区别在于in会查找原型链,而hasOwnProperty不会。 示例中对象foo自身上存在goo属性,而它的原型链上存在bar属性。 通过这个例子要注意如果要判断foo上是否有属性goo,不能简单的通过if(foo.goo){}判断,因为goo的值可能为undefined或者其他可能隐式转换为false的值。 第 33 题
    Object.prototype.bar = 1;
    var foo = {
    moo: 2
    };
    for(var i in foo) {
    console.log(i);
    }
    解析:
    // 输出
    'moo'
    'bar'
    for…in…遍历对象上除了Symbol以外的可枚举属性,包括原型链上的属性。 第 34 题
    function foo1() {
    return {
    bar: "hello"
    };
    }
    function foo2() {
    return
    {
    bar: "hello"
    };
    }
    console.log(foo1());
    console.log(foo2());
    解析:
    // 输出
    { bar: "hello" }
    undefined
    两个函数唯一区别就是return后面跟的值,一个换行一个不换行。 当我们书写代码时忘记在结尾书写;时,JavaScript解析器会根据一定规则自动补上;。
    return
    {
    bar: "hello"
    }
    => 会被解析成
    return;
    {
    bar: "hello"
    };
    因此函数执行后会返回undefined。 第 35 题
    console.log((function(){ return typeof arguments; })());
    解析:
    // 输出'object'
    arguments为类数组,类型为object。因此typeof arguments = ‘object’。 第 36 题
    console.log(Boolean(false));
    console.log(Boolean('0'));
    console.log(Boolean(''));
    console.log(Boolean(NaN));
    解析:
    //输出falsetruefalsefasle
    只有下面几种值在转换为布尔值时为false:
    +0,-0,NaN,false,'',null,undefined。
    除此之外的值在转换为布尔值的时候全部为true。 第 37 题
    console.log(Array(3));
    console.log(Array(2,3));
    解析:
    // 输出[empty × 3] [2,3]
    使用Array()创建数组时,要注意传入的值的类型和数量。 第 38 题
    console.log(0.1 + 0.2 == 0.3);
    解析:
    // 输出
    false
    第 39 题
    var a=[1, 2, 3];
    console.log(a.join());
    解析:
    //输出
    1,2,3
    join方法如果省略参数,默认以,分隔。 第 40 题
    var a = [3];
    var b = [1];
    console.log(a - b);
    解析:
    // 输出
    2
    在执行a - b时,a和b都要转换为数字。首先a先转换为字符串,[3] => [3].toString() => ‘3’,然后Number(3) => 3。b同理。因此转换之后为3 - 1 = 2。

  • 相关阅读:
    MyBatis 框架系列之基础初识
    从零开始实现在线直播
    面试中关于Redis的问题看这篇就够了
    Spring Boot 中使用 MyBatis 整合 Druid 多数据源
    MyBatis的foreach语句详解
    小结:“服务器端跳转”和“客户端跳转”的区别
    Centos7.3安装vsftp服务
    Spring 注解@Value详解
    Spring中@Bean与@Configuration
    数据结构之LinkList
  • 原文地址:https://www.cnblogs.com/wsj1/p/14864339.html
Copyright © 2011-2022 走看看