试题广场|js、css、html的各种基础知识试错👏👏

107 阅读6分钟

执行顺序

var a = 1;
var b = 2;
let obj = {
    a: 3,
    b: 4,
    getA: function () {
        var a = 5;
        setTimeout(function () {
            console.log('this.a', this.a);
        })
    },
    getB: function () {
        var b = 6;
        return function () {
            console.log('this.b', this.b);
        }()
    }
}
obj.getA() // 1
obj.getB() // 2 // 立即执行
// 输出 2 1

作用域

let name = "张三"
let obj = {
    name
}
console.log(obj.name); // 张三

获取数组的最值

let arr = [1, 2, 3, 4];
let max = Math.max(...arr);
console.log(max); // 4
let arr = [1, 2, 3, 4];
let max = Math.max.apply({}, arr);
console.log(max);

js的传参

js的传参分为值传递和引用传递,简单类型是值传递,复杂类型是引用传递,

函数内部对值传递不会影响外部,对引用传递改变会影响外部

function fn(o, val) {
  o.b = 1;
  val = 1;
}
var obj = { b: 0 };
var num = 0;
fn(obj, num);
console.log(obj, num); // {b:1} 0

匿名函数的this

匿名函数具有全局性,匿名函数的this指向window

var uname = "window";

var object = {
  uname: "object",

  fun: function () {
    console.log(this.uname);

    return function () {
      console.log(this.uname);
    };
  },
};

object.fun()(); // object window

立即执行函数

1.立即执行函数如果有函数名

var a = 10;
(function a() {
  a = 20; //  这里相当于修改函数名,无效
  console.log(a); //  打印函数a [Function: a]
})();

// 2.立即执行函数没有函数名

(function () {
  var a = 100; // 此时的a成为全局变量,挂在到window上!
  console.log(a); // 100
})();

// 3. 普通函数变量无效 立即执行函数变量提升

function add() {
  b = 2;
}
console.log(b); // b is not defined
function add() {
    b = 2;
}
add()
console.log(b); // 2
(function () {
  b = 2; b挂载到window上
})();
console.log(b); // 2
(function () {
    var b = 2;
})();
console.log(b); // b is not defined

// 4. 函数提升大于变量提升

var add = 1;
function add() {
  add = 2;
  console.log(add);
}
add(); //  add is not a function

// 将上面代码转换一下:函数提升大于变量提升 add()内部的变量是函数内部的,无关

// 变量提升

function add() {}
var add = undefined;
// 赋值阶段

function add() {
  add = 2;
  console.log(add);
}
add = 1;
// 调用阶段

add(); // add 已经被变成变量了,不是函数了
// 验证阶段

console.log(typeof add); // number

参数设置默认值

// 参数设置默认值

var a = 1;
function add(a = 2) {
  console.log(a); //2
  var a = 3;
  console.log(a); //3
}
add();
console.log(a); //1

// 参数没有设置默认值

  var a = 1;
function add(a) {
 console.log(a); //88
 var a = 3;
 console.log(a); //3
}
add(88);
console.log(a); //1

// 参数多种形式

var a = 12;
function add(a = 1,b = function () {a = 3;console.log(a);}) { // 输出参数3
  b();
  console.log(a);// 输出参数1
  var a = 10; 
  console.log(a); //10
}

add();
console.log(a);  // 12 

类不会变量提升,和let、const相似,存在暂时性死区

var a = 1;
function test() {
    console.log(a); // 报错,作用域内的a,存在暂时性死区
    class a { }
    console.log(a); // class a{}
}
test();

除以0

任何数值除以0都会导致错误而终止程序执行,但是在 JavaScript 中,会返回出NaN,不影响后面程序

var num = prompt('请输入分母:')
try {
    console.log('a');
    value = 0 / num;
    console.log('b');
}
catch (e) {
    console.log('c');
}
finally {
    console.log('d'); // a b d 不会去catch处理,因为不会报错
}

settimeout内部this指向window

解决settimeout内部this指向window的三种解决方案

  1. that = this
  2. call、apply、bind
function () {
    setTimeout(function () {
        this.disabled = true;
    }.bind(this), 1000)
}
  1. 函数内包含箭头函数
function() {
    setTimeout(() => {
        this.disabled = true;
    }, 1000)
}

NaN

只有set、Object.js、includes能正确识别NaN === NaN


NaN 相关:

NaN == NaN // false
NaN === NaN // false

// indexOf方法无法识别数组的NaN成员
[NaN].indexOf(NaN) // -1

// 向 Set 数据结构中加入值时认为NaN等于自身
let set = new Set();
set.add(NaN);
set.add(NaN);
console.log(set); // Set {NaN}

// Object.is()方法认为NaN等于NaN
Object.is(NaN, NaN) // true
    + 0 === -0 //true
Object.is(+0, -0) // false

// ES7中新增的数组实例方法,includes()方法认为NaN等于自身
[1, 2, NaN].includes(NaN) // true

做数值操作,null会转成0,undefined会转成NaN

console.log(Number(null)) // 0 
console.log(Number(undefined)) // NaN

defineProperty

defineProperty定义的新的属性,默认配置项全是false,修改已经存在的配置项,默认会变成true


var obj = {
  brand: '华为',
  price: 1999
};
Object.defineProperty(obj, 'id', { value: 1 }) // d

// 新增的属性全是false { value: 1, writable: false, enumerable: false, configurable: false }
console.log(Object.getOwnPropertyDescriptor(obj, 'id'));

Object.defineProperty(obj, 'price', { configurable: false })

// 修改已经存在的属性,默认值会变成true,这时候又强制设置configurable的值
// { value: 1999, writable: true, enumerable: true, configurable: false }

console.log(Object.getOwnPropertyDescriptor(obj, 'price'));
console.log('①', Object.keys(obj).length);  // 2
for (var k in obj) {
  console.log('②', obj[k]); //  ② 华为 ② 1999
}

obj.price = 999;
delete obj['price']
console.log('③', obj);  // ③ { brand: '华为', price: 999 }

各种this输出问题

// 箭头函数
function test() {
  this.flag = false;// === button.flag = false
  this.change = () => // === button.change()
    this.flag = true; // === button.flag = true 箭头函数的this由test决定,test的this是button 
  console.log(button.flag);
};
const button = new test(); // test做了构造函数,所以this指向button实例
button.change()
// 调用形式不同,this指向不同
var len = 117;
let func = {
    len: 935,
    showLen: function () {
        console.log(this.len);
    },
    show: function () {
        (function (cb) {
            cb();//以【函数】的形式调用时,this指向window
        })(this.showLen)
    }
}
func.show(); // 117
func.showLen();  //935 以【方法】的形式调用时,this指向被调用的对象(这里是【func】)

window.value = 'v';
function fn() {
    console.log(this.value);
}
function calIArrowFn() {
    const arrowFn = () => {
        console.log(this.value);
    };
    arrowFn();
}
function getArrowFn() {
    const arrowFn = () => {
        console.log(this.value);
    };
    return arrowFn;
}
const objA = {
    value: 'a',
    fn: fn
}
const objB = {
    value: 'b',
    fn: calIArrowFn
}
const objC = {
    value: 'c',
    fn: getArrowFn()
}
fn(); // v
objA.fn(); // a
objB.fn(); // b
objC.fn(); // v


指定原型链

指定原型链,只要有一方更改原型,2方都会受影响

function Father(age) {
  this.age = age
}
function Son(age) {
  Father.call(this);
}
Son.prototype = Father.prototype;
Father.prototype.getAge = function () { console.log(40); }
Son.prototype.getAge = function () { console.log(18); }
var father = new Father(40);
var son = new Son(18);
son.getAge(); // 18
father.getAge(); // 18

console.log(father); // Father { age: 40 }
console.log(son); //  Father { age: undefined } age没有值,因为call的没有参数列表

未命名文件.png

js 的 || 和 && 运算规则

a || b

a是true,不用计算b,直接返回a

a是false,需要计算b,无论b是什么,返回b

a && b

a是true,需要计算b,无论b是什么,返回b

a是false,不用计算b, 返回a

|| 第一true,返第一,第一false,返第二

&& 第一true,返第二,第一false,返第一

var a = 4 >= 6 || true && 1 || false;
console.log(a); // 1
// 4 >= 6 =>false
// true && 1 =>1
// 原式变成 false || 1 || false
// false || 1 => 1
// 1 || false => 1

点运算符高于typeof

console.log(typeof ''.prototype); // undefined ''没有原型,只有函数才有prototype
console.log(typeof ''.__proto__); // object  ''.__proto__是String 
console.log(typeof ''.__proto__ === typeof ''.prototype);  // false

isNaN

判断是否是非数值类型,但是比较恶心的是,在判断之前,会先进行类型转换,转成数值了,就返回false,说明是数值,无法转成的,就返回true,说明是非数值

console.log(isNaN(113)); // false
console.log(isNaN('113')); // false
console.log(isNaN('abc')); // true
console.log(isNaN(true)); // false
console.log(isNaN(false)); // false

svg

svg是html的一个分支

link属于html的范畴 @import属于css的范畴,只能加载css

link加载时并行加载的,加载完的先进行解析 script的加载是加载完一个之后,再加载另一个

css的百分比相对问题

参照父元素宽度的元素:padding margin width text-indent

参照父元素高度的元素:height

参照父元素属性:font-size line-height

特殊:relative,top(bottom) left(right)参照的是父元素的内容区域的高度与宽度,而绝对定位的时候参照的是最近的定位元素包含padding的高度与宽度(包含padding的宽度是clientWidth)

    <style>
        .div-content {
            width: 200px;
            height: 300px;
            background-color: cadetblue;
            /* font-size: 20px; */
        }

        .son-content {
            /* width = 20px 相对父级宽度 */
            width: 10%;
            /* height = 20px 相对父级高度 */
            height: 10%;
            /* padding = 20px 相对父级宽度 */
            padding: 10%;
            /* margin = 10px 相对父级宽度 */
            margin: 5%;
            background-color: antiquewhite;
            /* font-size = 18px 相对父级font-size */
            font-size: 90%
        }
    </style>

width

width:就是width clientWidth = width + padding

offsetWidth = border + width + padding + 滚动条(如果有的话)

scrollWidth = clientWidth + 滚出屏幕外的宽度(如果有的话)

image.png