梁山网站建设【梁山网络公司】梁山做网站、梁山微信公众号开发、梁山网站设计、梁山小程序制作-小程序制作-网站建设【企业网站制作|网页设计】- 高端网站建设 - 书生商友信息科技-

全国热线:400-111-6878

网站建设推广专家

梁山网站建设【梁山网络公司】梁山做网站、梁山微信公众号开发、梁山网站设计、梁山小程序制作

发表日期: 2021-05-20 10:29:14 浏览次数:101

梁山网站建设【梁山网络公司】梁山做网站、梁山微信公众号开发、梁山网站设计、梁山小程序制作

网站建设.jpg

梁山县位于鲁西南,处于山东省的泰安、济宁、菏泽和河南省的濮阳四地市交界处。

梁山建县于1949年8月,下辖13个乡镇、1个省级经济开发区、1个风景名胜区,672个行政村,77.6万人,地域面积964平方千米。

梁山县是古典名著《水浒传》故事发祥地,是全国首批命名的武术之乡, [1]  亦是中国专用汽车生产基地, [2]  2016年,地区生产总值(GDP)265.04亿元。


 1 . 原始类型有哪几种?null 是对象吗?原始数据类型和复杂数据类型存储有什么区别?

 2.typeof 是否正确判断类型? instanceof 呢? instanceof 的实现原理是什么?

首先 typeof 能够正确的判断基本数据类型,但是除了 null, typeof null 输出的是对象。

但是对象来说,typeof 不能正确的判断其类型, typeof 一个函数可以输出 'function', 而除此之外,输出的全是 object, 这种情况下,我们无法准确的知道对象的类型。

instanceof 可以准确的判断复杂数据类型,但是不能正确判断基本数据类型。正确判断数据类型请戳:

https://github.com/YvetteLau/Blog/blob/master/JS/data-type.js

instanceof 是通过原型链判断的,A instanceof B, 在 A 的原型链中层层查找,是否有原型等于 B.prototype,如果一直找到 A 的原型链的顶端 (null; 即Object.prototype.__proto__), 仍然不等于 B.prototype,那么返回 false,否则返回 true。

instanceof 的实现代码:

// L instanceof R
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
    var O = R.prototype;// 取 R 的显式原型
    L = L.__proto__;    // 取 L 的隐式原型
    while (true) {
        if (L === null) // 已经找到顶层
            return false;
        if (O === L)   // 当 O 严格等于 L 时,返回 true
            return true;
        L = L.__proto__;  // 继续向上一层原型链查找
    }
}
 3.for of , for in 和 forEach,map 的区别。

PS: Object.keys():返回给定对象所有可枚举属性的字符串数组。

关于 forEach 是否会改变原数组的问题,有些小伙伴提出了异议,为此我写了代码测试了下 (注意数组项是复杂数据类型的情况)。除了 forEach 之外,map 等 API,也有同样的问题。

let arry = [1, 2, 3, 4];

arry.forEach((item) => {
    item *= 10;
});
console.log(arry); //[1, 2, 3, 4]

arry.forEach((item) => {
    arry[1] = 10; // 直接操作数组
});
console.log(arry); //[ 1, 10, 3, 4 ]

let arry2 = [
    { name: "Yve" },
    { age: 20 }
];
arry2.forEach((item) => {
    item.name = 10;
});
console.log(arry2);//[ { name: 10 }, { age: 20, name: 10 } ]

如还不了解 iterator 接口或 for...of, 请先阅读 ES6 文档:Iterator 和 for...of 循环:

http://es6.ruanyifeng.com/#docs/iterator

更多细节请戳: 

https://github.com/YvetteLau/Blog/blob/master/JS/for.js

 4 . 如何判断一个变量是不是数组?

function fn() {
    console.log(Array.isArray(arguments));   //false; 因为 arguments 是类数组,但不是数组
    console.log(Array.isArray([1,2,3,4]));   //true
    console.log(arguments instanceof Array); //fasle
    console.log([1,2,3,4] instanceof Array); //true
    console.log(Object.prototype.toString.call(arguments)); //[object Arguments]
    console.log(Object.prototype.toString.call([1,2,3,4])); //[object Array]
    console.log(arguments.constructor === Array); //false
    arguments.constructor = Array;
    console.log(arguments.constructor === Array); //true
    console.log(Array.isArray(arguments));        //false
}
fn(1,2,3,4);

 5. 类数组和数组的区别是什么?
 类数组:

1)拥有 length 属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);

2)不具有数组所具有的方法;

类数组是一个普通对象,而真实的数组是 Array 类型。

常见的类数组有: 函数的参数 arugments, DOM 对象列表 (比如通过 document.querySelectorAll 得到的列表), jQuery 对象 (比如 $("div"))。

类数组可以转换为数组:

// 第一种方法
Array.prototype.slice.call(arrayLike, start);
// 第二种方法
[...arrayLike];
// 第三种方法:
Array.from(arrayLike);

PS: 任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组。

Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象。

 6.== 和 === 有什么区别?

=== 不需要进行类型转换,只有类型相同并且值相等时,才返回 true.

== 如果两者类型不同,首先需要进行类型转换。具体流程如下:

  1. 首先判断两者类型是否相同,如果相等,判断值是否相等;

  2. 如果类型不同,进行类型转换;

  3. 判断比较的是否是 null 或者是 undefined, 如果是, 返回 true;

  4. 判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number;

  5. 判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断;

  6. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断。

let person1 = {
    age: 25
}
let person2 = person1;
person2.gae = 20;
console.log(person1 === person2); //true, 注意复杂数据类型,比较的是引用地址

 思考: [] == ![]

我们来分析一下: [] == ![] 是 true 还是 false?

1. 首先,我们需要知道 ! 优先级是高于 == (更多运算符优先级可查看: 运算符优先级):

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence

2.![] 引用类型转换成布尔值都是 true, 因此![]的是 false

3. 根据上面的比较步骤中的第五条,其中一方是 boolean,将 boolean 转为 number 再进行判断,false 转换成 number,对应的值是 0.

4. 根据上面比较步骤中的第六条,有一方是 number,那么将 object 也转换成 Number, 空数组转换成数字,对应的值是 0.(空数组转换成数字,对应的值是 0,如果数组中只有一个数字,那么转成 number 就是这个数字,其它情况,均为 NaN)

5.0 == 0; 为 true

 7.ES6 中的 class 和 ES5 的类有什么区别?

1.ES6 class 内部所有定义的方法都是不可枚举的;

2.ES6 class 必须使用 new 调用;

3.ES6 class 不存在变量提升;

4.ES6 class 默认即是严格模式;

5.ES6 class 子类必须在父类的构造函数中调用 super(),这样才有 this 对象 ;ES5 中类继承的关系是相反的,先有子类的 this,然后用父类的方法应用在 this 上。

 8. 数组的哪些 API 会改变原数组?

修改原数组的 API 有:

splice/reverse/fill/copyWithin/sort/push/pop/unshift/shift

不修改原数组的 API 有:

slice/map/forEach/every/filter/reduce/entry/entries/find

注: 数组的每一项是简单数据类型,且未直接操作数组的情况下。

 9.let、const 以及 var 的区别是什么?

 10. 在 JS 中什么是变量提升?什么是暂时性死区?

变量提升就是变量在声明之前就可以使用,值为 undefined。

在代码块内,使用 let/const 命令声明变量之前,该变量都是不可用的 (会抛出错误)。这在语法上,称为“暂时性死区”。暂时性死区也意味着 typeof 不再是一个百分百安全的操作。

typeof x; // ReferenceError(暂时性死区,抛错)
let x;
typeof y; // 值是 undefined, 不会报错

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

 11. 如何正确的判断 this? 箭头函数的 this 是什么?

this 的绑定规则有四种:默认绑定,隐式绑定,显式绑定,new 绑定.

  1. 函数是否在 new 中调用 (new 绑定),如果是,那么 this 绑定的是新创建的对象;

  2. 函数是否通过 call,apply 调用,或者使用了 bind (即硬绑定),如果是,那么 this 绑定的就是指定的对象;

  3. 函数是否在某个上下文对象中调用 (隐式绑定),如果是的话,this 绑定的是那个上下文对象。一般是 obj.foo();

  4. 如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到 undefined,否则绑定到全局对象;

  5. 如果把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind, 这些值在调用时会被忽略,实际应用的是默认绑定规则;

  6. 箭头函数没有自己的 this, 它的 this 继承于上一层代码块的 this。

测试下是否已经成功 Get 了此知识点 (浏览器执行环境):

var number = 5;
var obj = {
    number: 3,
    fn1: (function () {
        var number;
        this.number *= 2;
        number = number * 2;
        number = 3;
        return function () {
            var num = this.number;
            this.number *= 2;
            console.log(num);
            number *= 3;
            console.log(number);
        }
    })();
}
var fn1 = obj.fn1;
fn1.call(null);
obj.fn1();
console.log(window.number);

如果 this 的知识点,您还不太懂,请戳: 嗨,你真的懂 this 吗?:

https://github.com/YvetteLau/Blog/issues/6

 12. 词法作用域和 this 的区别。


 13. 谈谈你对 JS 执行上下文栈和作用域链的理解。

执行上下文就是当前 JavaScript 代码被解析和执行时所在环境, JS 执行上下文栈可以认为是一个存储函数调用的栈结构,遵循先进后出的原则。

作用域链: 无论是 LHS 还是 RHS 查询,都会在当前的作用域开始查找,如果没有找到,就会向上级作用域继续查找目标标识符,每次上升一个作用域,一直到全局作用域为止。

题难不难?不难!继续挑战一下难!知道难,就更要继续了!

 14. 什么是闭包?闭包的作用是什么?闭包有哪些使用场景?

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包最常用的方式就是在一个函数内部创建另一个函数。

闭包的作用有:

  1. 封装私有变量;

  2. 模仿块级作用域 (ES5 中没有块级作用域);

  3. 实现 JS 的模块。


 15.call、apply 有什么区别?call,aplly 和 bind 的内部是如何实现的?

call 和 apply 的功能相同,区别在于传参的方式不一样:

 call 核心:

Function.prototype.call = function (context) {
    /** 如果第一个参数传入的是 null 或者是 undefined, 那么指向 this 指向 window/global */
    /** 如果第一个参数传入的不是 null 或者是 undefined, 那么必须是一个对象 */
    if (!context) {
        //context 为 null 或者是 undefined
        context = typeof window === 'undefined' ? global : window;
    }
    context.fn = this; //this 指向的是当前的函数 (Function 的实例)
    let args = [...arguments].slice(1);// 获取除了 this 指向对象以外的参数, 空数组 slice 后返回的仍然是空数组
    let result = context.fn(...args); // 隐式绑定, 当前函数的 this 指向了 context.
    delete context.fn;
    return result;
}

// 测试代码
var foo = {
    name: 'Selina'
}
var name = 'Chirs';
function bar(job, age) {
    console.log(this.name);
    console.log(job, age);
}
bar.call(foo, 'programmer', 20);
// Selina programmer 20
bar.call(null, 'teacher', 25);
// 浏览器环境: Chirs teacher 25; node 环境: undefined teacher 25

 apply

apply 的实现和 call 很类似,但是需要注意他们的参数是不一样的,apply 的第二个参数是数组或类数组。

Function.prototype.apply = function (context, rest) {
    if (!context) {
        //context 为 null 或者是 undefined 时, 设置默认值
        context = typeof window === 'undefined' ? global : window;
    }
    context.fn = this;
    let result = context.fn(...rest);
    delete context.fn;
    return result;
}
var foo = {
    name: 'Selina'
}
var name = 'Chirs';
function bar(job, age) {
    console.log(this.name);
    console.log(job, age);
}
bar.apply(foo, ['programmer', 20]);
// Selina programmer 20
bar.apply(null, ['teacher', 25]);
// 浏览器环境: Chirs programmer 20; node 环境: undefined teacher 25

 bind

bind 和 call/apply 有一个很重要的区别,一个函数被 call/apply 的时候,会直接调用,但是 bind 会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。

Function.prototype.bind = function(context) {
    if(typeof this !== "function"){
        throw new TypeError("not a function");
    }
    let self = this;
    let args = [...arguments].slice(1);
    function Fn() {};
    Fn.prototype = this.prototype;
    let bound = function() {
        let res = [...args, ...arguments]; //bind 传递的参数和函数调用时传递的参数拼接
        context = this instanceof Fn ? this : context || this;
        return self.apply(context, res);
    }
    // 原型链
    bound.prototype = new Fn();
    return bound;
}

var name = 'Jack';
function person(age, job, gender){
    console.log(this.name , age, job, gender);
}
var Yve = {name : 'Yvette'};
let result = person.bind(Yve, 22, 'enginner')('female');


梁山网站建设梁山网络公司梁山做网站、梁山微信公众号开发、梁山网站设计、梁山小程序制作

上一条:北海申请400电话费用【北海企业全国热线电话办理】北海开通400电话电信价格、北海微信公众号代运营外包托管、北海网店编辑装修美工、北海网站推广优化大概需要多少钱
下一条:梁山网站制作【梁山网站优化】梁山建网站、梁山微信公众号运营、梁山网页设计、梁山微信小程序商城
网站制作
小程序制作
网站优化
网站开发
400电话办理
网络推广
网站建设
网店装修
微信公众号开发
网页设计
网络公司
域名企业邮箱
服务器空间
网站案例报价
百科问答
编辑排版美工
App软件开发
百度推广
代运营托管
logo设计
网络全网营销
网站备案
网站定制
小程序开发公司
首页
电话
立即预约