JS面试题之——数组转置与螺旋矩阵

JavaScript013

JS面试题之——数组转置与螺旋矩阵,第1张

输入 :一个二维数组,例如:

    [ [1,2,3] , [4,5,6] , [7,8,9] ]

输出 :二维数组的转置

    [ [1,4,7] , [2,5,8] , [3,6,9] ]

    矩阵的转置就是行列互换

function arrayT(sArray){

    var tArray = []

    //对目标数组初始化

    for(var i = 0i <sArray[0].lengthi++){

        tArray[i] = []

    }

    //转置数组

    for(var i = 0i <sArray.lengthi++){

        for(var j = 0j <sArray[i].lengthj++){

            tArray[j][i] = sArray[i][j]

        }

    }

    return tArray

}

注:

    这是一道本人经历的面试题,题目要求是给一个字符串,"abc def ghi",输出为"adg beh cfi"。

    通过这个面试题,我想到了数组的转置操作。

该题是在数组转置的基础上,我想到了之前leetcode上的一道题目,就重温一下。

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

输入:

[

    [ 1 , 2 , 3 ] ,

    [ 4 , 5 , 6 ] ,

    [ 7 , 8 , 9 ]

]

输出:

[ 1 , 2 , 3 , 6 , 9 , 8 , 7 , 4 , 5]

其实是相当于每次遍历完外圈,然后遍历内圈;

我们可以把遍历每一圈作为一个完整的事件,然后不断去重复遍历每一圈就可以解决这个问题。

其实就是递归的运用。

arr =>{

    // map函数用来完成当前矩阵最外一圈的遍历

    // 二维数组 arr 表示当前矩阵

    // 一维数组 result 用来保存遍历结果 

    let map = (arr, result) =>{

        // 矩阵的高度即行数

        let n = arr.length

        // 遍历矩阵的每一行

        for(let i = 0i <ni++){

            // 若第一行 按顺序插入

            if(i === 0){

                result = result.concat(arr[i])

            } else if (i === n-1){

                // 若最后一行 倒序插入

                result = result.concat(arr[i].reverse())

            } else {

                // 若中间行 插入该行最后一个元素 并将该元素从矩阵中删除

                result.push(arr[i].pop())

            }

        }

        // 将已经遍历的第一行和最后一行从矩阵中删除

        arr.pop()

        arr.shift()

        // 遍历插入最左侧一列 此时删除首位两行后矩阵高度已变为n-2

        for(let j = n - 3j >= 0j--){

            // 避免arr[j]长度为空时插入undefined

            if(arr[j].length){

                result.push(arr[j].shift())

            }

        }

        // 截止条件 矩阵有元素就继续递归

        if(arr.length){

            // 把已将遍历元素删除的矩阵进行递归

            return map(arr, result)

        }else{

            return result

        }

    }

    // 将初始矩阵传入, 保存结果的数组初始为空

    return map(arr, [])

}

1.document load 和 document ready 的区别

参考答案:文档解析过程中,ready在加载图片等外部资源前触发,load在之后触发。如果页面中要是没有图片之类的媒体文件的话ready与load是差不多的,但是页面中有文件就不一样了,所以还是推荐大家在工作中用ready

解析:

DOM文档解析:

页面加载完成有两种事件

1.load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),执行一个函数

缺点:如果图片资源较多,加载时间较长,onload后等待执行的函数需要等待较长时间,所以一些效果可能受到影响

代码形式:

2.$(document).ready()是当DOM文档树加载完成后执行一个函数 (不包含图片,css等)所以会比load较快执行

在原生的jS中不包括ready()这个方法,Jquery才有,jquery中有 $().ready(function)。

代码形式为:

参与互动

2.JavaScript 中如何检测一个变量是一个 String 类型?

参考答案:三种方法(typeof、constructor、Object.prototype.toString.call())

解析:

参与互动

3.请用 js 去除字符串空格?

参考答案:replace 正则匹配方法、str.trim()方法、JQ 方法:$.trim(str)方法

解析:

方法一:replace 正则匹配方法

去除字符串内所有的空格:str = str.replace(/s*/g, "")

去除字符串内两头的空格:str = str.replace(/^s*|s*$/g, "")

去除字符串内左侧的空格:str = str.replace(/^s*/, "")

去除字符串内右侧的空格:str = str.replace(/(s*$)/g, "")

示例:

方法二:str.trim()方法

trim()方法是用来删除字符串两端的空白字符并返回,trim 方法并不影响原来的字符串本身,它返回的是一个新的字符串。

缺陷:只能去除字符串两端的空格,不能去除中间的空格

示例:

方法三:JQ 方法:$.trim(str)方法

$.trim() 函数用于去除字符串两端的空白字符。

注意:$.trim()函数会移除字符串开始和末尾处的所有换行符,空格(包括连续的空格)和制表符。如果这些空白字符在字符串中间时,它们将被保留,不会被移除。

示例:

参与互动

4.js 是一门怎样的语言,它有什么特点

参考答案:

1.脚本语言。JavaScript 是一种解释型的脚本语言, C、C++等语言先编译后执行, 而 JavaScript 是在程序的运行过程中逐行进行解释。

2.基于对象。JavaScript 是一种基于对象的脚本语言, 它不仅可以创建对象, 也能使用现有的对象。

3.简单。JavaScript 语言中采用的是弱类型的变量类型, 对使用的数据类型未做出严格的要求, 是基于 Java 基本语句和控制的脚本语言, 其设计简单紧凑。

4.动态性。JavaScript 是一种采用事件驱动的脚本语言, 它不需要经过 Web 服务器就可以对用户的输入做出响应。

5.跨平台性。JavaScript 脚本语言不依赖于操作系统, 仅需要浏览器的支持。

参与互动

5.== 和 === 的不同

参考答案: == 是抽象相等运算符,而 === 是严格相等运算符。 == 运算符是在进行必要的类型转换后,再比较。 === 运算符不会进行类型转换,所以如果两个值不是相同的类型,会直接返回 false 。使用 == 时,可能发生一些特别的事情,例如:

如果你对 == 和 === 的概念不是特别了解,建议大多数情况下使用 ===

参与互动

6.怎样添加、移除、移动、复制、创建和查找节点?

参考答案:

1)创建新节点

2)添加、移除、替换、插入

3)查找

参与互动

7.事件委托是什么

参考答案:利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!

解析:

1、那什么样的事件可以用事件委托,什么样的事件不可以用呢?

2、为什么要用事件委托

3、事件冒泡与事件委托的对比

4、事件委托怎么取索引?

拓展:

参考

参与互动

8.require 与 import 的区别

参考答案:两者的加载方式不同、规范不同

第一、两者的加载方式不同,require 是在运行时加载,而 import 是在编译时加载

require('./a')()// a 模块是一个函数,立即执行 a 模块函数

var data = require('./a').data// a 模块导出的是一个对象

var a = require('./a')[0]// a 模块导出的是一个数组 ======>哪都行

import $ from 'jquery'

import * as _ from '_'

import {a, b, c} from './a'

import {default as alias, a as a_a, b, c} from './a'======>用在开头

第二、规范不同,require 是 CommonJS/AMD 规范,import 是 ESMAScript6+规范

第三、require 特点:社区方案,提供了服务器/浏览器的模块加载方案。非语言层面的标准。只能在运行时确定模块的依赖关系及输入/输出的变量,无法进行静态优化。

import 特点:语言规格层面支持模块功能。支持编译时静态分析,便于 JS 引入宏和类型检验。动态绑定。

参与互动

9.javascript 对象的几种创建方式

参考答案:

第一种:Object 构造函数创建

这行代码创建了 Object 引用类型的一个新实例,然后把实例保存在变量 Person 中。

第二种:使用对象字面量表示法

对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程。也就是说,第一种和第二种方式创建对象的方法其实都是一样的,只是写法上的区别不同

在介绍第三种的创建方法之前,我们应该要明白为什么还要用别的方法来创建对象,也就是第一种,第二种方法的缺点所在:它们都是用了同一个接口创建很多对象,会产生大量的重复代码,就是如果你有 100 个对象,那你要输入 100 次很多相同的代码。那我们有什么方法来避免过多的重复代码呢,就是把创建对象的过程封装在函数体内,通过函数的调用直接生成对象。

第三种:使用工厂模式创建对象

在使用工厂模式创建对象的时候,我们都可以注意到,在 createPerson 函数中,返回的是一个对象。那么我们就无法判断返回的对象究竟是一个什么样的类型。于是就出现了第四种创建对象的模式。

第四种: 使用构造函数创建对象

对比工厂模式,我们可以发现以下区别:

1.没有显示地创建对象

2.直接将属性和方法赋给了 this 对象

3.没有 return 语句

4.终于可以识别的对象的类型。对于检测对象类型,我们应该使用 instanceof 操作符,我们来进行自主检测:

同时我们也应该明白,按照惯例,构造函数始终要应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。

那么构造函数确实挺好用的,但是它也有它的缺点:

就是每个方法都要在每个实例上重新创建一遍,方法指的就是我们在对象里面定义的函数。如果方法的数量很多,就会占用很多不必要的内存。于是出现了第五种创建对象的方法

第五种:原型创建对象模式

使用原型创建对象的方式,可以让所有对象实例共享它所包含的属性和方法。

如果是使用原型创建对象模式,请看下面代码:

当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。

这时候我们就可以使用构造函数模式与原型模式结合的方式,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

第六种:组合使用构造函数模式和原型模式

解析: 参考

参与互动

10.JavaScript 继承的方式和优缺点

参考答案:六种方式

今天遇到关于javascript原型的一道面试题,现分析下:

原题如下:

function

A(){

}

function

B(a){

this.a

=

a

}

function

C(a){

if(a){

this.a

=

a

}

}

A.prototype.a

=

1

B.prototype.a

=

1

C.prototype.a

=

1

console.log(new

A().a)

console.log(new

B().a)

console.log(new

C(2).a)

分析:

console.log(new

A().a)//new

A()为构造函数创建的对象,本身没有a属性,所以向它的原型去找,发现原型的a属性的属性值为1,故该输出值为1;

console.log(new

B().a)//new

B()为构造函数创建的对象,该构造函数有参数a,但该对象没有传参,故该输出值为undefined

console.log(new

C(2).a)//new

C()为构造函数创建的对象,该构造函数有参数a,且传的实参为2,执行函数内部,发现if为真,执行this.a

=

2,故属性a的值为2;

故这三个的输出值分别为:1、undefined、2.

以上就是小编为大家带来的关于js原型的面试题讲解的全部内容了,希望对大家有所帮助,多多支持脚本之家~