javascript

 

 JavaScript 有哪些数据类型

原始数据类型:

Boolean: 布尔表示一个逻辑实体,可以有两个值:true 和 false

Number: 用于表示数字类型

String: 用于表示文本数据

Null: Null 类型只有一个值: null,特指对象的值未设置

Undefined: 一个没有被赋值的变量会有个默认值 undefined

Symbol: 符号(Symbols)是ECMAScript第6版新定义的。符号类型是唯一的并且是不可修改的

引用类型:Object

 

介绍一下 JS 有哪些内置对象

Object 是 JavaScript 中所有对象的父对象

数据封装类对象:Object、Array、Boolean、Number、String

其他对象:Function、Argument、Math、Date、RegExp、Error

 

讲讲JS的语言特性

 

JavaScript脚本语言具有以下特点:

脚本语言

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

基于对象

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

简单

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

动态性

JavaScript是一种采用事件驱动的脚本语言,它不需要经过Web服务器就可以对用户的输入做出响应。在访问一个网页时,鼠标在网页中进行鼠标点击或上下移、窗口移动等操作JavaScript都可直接对这些事件给出相应的响应。

跨平台性

JavaScript脚本语言不依赖于操作系统,仅需要浏览器的支持。因此一个JavaScript脚本在编写后可以带到任意机器上使用,前提上机器上的浏览器支 持JavaScript脚本语言,目前JavaScript已被大多数的浏览器所支持。不同于服务器端脚本语言,例如PHP与ASP,JavaScript主要被作为客户端脚本语言在用户的浏览器上运行,不需要服务器的支持。所以在早期程序员比较青睐于JavaScript以减少对服务器的负担,而与此同时也带来另一个问题:安全性。而随着服务器的强壮,虽然程序员更喜欢运行于服务端的脚本以保证安全,但JavaScript仍然以其跨平台、容易上手等优势大行其道。同时,有些特殊功能(如AJAX)必须依赖Javascript在客户端进行支持。随着引擎如V8和框架如Node.js的发展,及其事件驱动及异步IO等特性,JavaScript逐渐被用来编写服务器端程序。

 

 

JS数组有哪些常用方法?

 修改器方法:

pop(): 删除数组的最后一个元素,并返回这个元素

push():在数组的末尾增加一个或多个元素,并返回数组的新长度

reverse(): 颠倒数组中元素的排列顺序

shift(): 删除数组的第一个元素,并返回这个元素

unshift(): 在数组的开头增加一个或多个元素,并返回数组的新长度

sort(): 对数组元素进行排序,并返回当前数组

splice(): 在任意的位置给数组添加或删除任意个元素

访问方法:

concat(): 返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组

join(): 连接所有数组元素组成一个字符串

slice(): 抽取当前数组中的一段元素组合成一个新数组

indeOf(): 返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1

lastIndexOf(): 返回数组中最后一个(从右边数第一个)与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1

迭代方法:

forEach(): 为数组中的每个元素执行一次回调函数,最终返回 undefined

every(): 如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false

some(): 如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false

filter(): 将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回

map(): 返回一个由回调函数的返回值组成的新数组

 

JS字符串有哪些常用方法?

https://www.cnblogs.com/hcxy/p/7376648.html

截取字符串方法:

slice()     提取字符串的某个部分,并以新的字符串返回被提取的部分。

split()    用于把一个字符串分割成字符串数组。

substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。

substring() 方法用于提取字符串中介于两个指定下标之间的字符。

其他方法:

charAt()         返回指定位置的字符。

charCodeAt()       返回在指定的位置的字符的 Unicode 编码。

concat()      用于连接两个或多个字符串。

indexOf() 方法          返回指定字符串在字符串中首次出现的位置。匹配不到则返回-1。

lastIndexOf()            返回指定字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。

 replace()    用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

trim()  去除 str 开头和结尾处的空白字符,返回 str 的一个副本,不影响字符串本身的值

toLocaleUpperCase() / toLocaleLowerCase()   用于字符串转换大小写(与下面的方法方法仅在某些外国小语种有差别)

match()               在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。匹配不到返回Null。

search()    用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。无匹配返回-1。

fromCharCode()       接受一个指定的 Unicode 值,然后返回一个字符串。

substr()和 substring()有什么区别? 

 

什么是命令式编程?什么是声明式编程?

https://www.jianshu.com/p/7316e3288fd0

  • 命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
  • 声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。
例:将一个数组的每个值乘2;
命令式:
var numbers = [1,2,3,4,5] var doubled = [] for(var i = 0; i < numbers.length; i++) { var newNumber = numbers[i] * 2 doubled.push (newNumber) } console.log (doubled) //=> [2,4,6,8,10]
声明式:
var numbers = [1,2,3,4,5] var doubled = numbers.map (function (n) { return n * 2 }) console.log (doubled) //=> [2,4,6,8,10]

 

什么是面向对象编程?

https://baike.baidu.com/item/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1/24792?fromtitle=%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B&fromid=254878&fr=aladdin

面向对象程序设计(英语:Object-oriented
programming,缩写:OOP)是种具有对象概念的程序编程范型,同时也是一种程序开发的方法。它可能包含数据、属性、代码与方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。
面向对象主要特征:封装性、继承性、多态性

面向对象编程具有以下优点:

易维护
采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。

易扩展
通过继承,我们可以大幅减少多余的代码,并扩展现有代码的用途;
我们可以在标准的模块上(这里所谓的”标准”指程序员之间彼此达成的协议)构建我们的程序,而不必一切从头开始。这可以减少软件开发时间并提高生产效率;

模块化
封装可以定义对象的属性和方法的访问级别,通过不同的访问修饰符对外暴露安全的接口,防止内部数据在不安全的情况下被修改。这样可以使程序具备更高的模块化程度,方便后期的维护和修改。
同时,面向对象语言允许一个对象的多个实例同时存在,而且彼此之间不会相互干扰;

方便建模
虽然面向对象语言中的对象与现实生活中的对象并不是同个概念,但很多时候,往往可以使用现实生活中对象的概念抽象后稍作修改来进行建模,这大大方便了建模的过程。(但直接使用现实中的对象来建模有时会适得其反)。

 

JS判断数据类型的各种方法?

https://blog.csdn.net/mozuncangtianbaxue/article/details/77151598

①typeof

typeof是一个运算符,它返回一个用来表示表达式的数据类型的字符串。

语法:typeof(表达式)和typeof 变量名,第一种是对表达式做运算,第二种是对变量做运算。语法中的圆括号是可选项

typeof的运算数未定义,返回的就是 “undefined”.

运算数为数字 typeof(x) = “number”

字符串 typeof(x) = “string”

布尔值 typeof(x) = “boolean”

对象,数组和null typeof(x) = “object”

函数 typeof(x) = “function”

特殊情况:

  • 对于基本类型,除 null 以外,均可以返回正确的结果。
  • 对于引用类型,除 function 以外,一律返回 object 类型。
  • 对于 null ,返回 object 类型。
  • 对于 function 返回  function 类型。

②instanceof

instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。通常来讲,使用 instanceof 就是判断一个实例是否属于某种类型。

语法:obj instanceof Object;//true

③constructor 

constructor 属性返回对创建此对象的数组函数的引用。

语法:object.constructor

细节问题:

  • null和undefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
  • JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object

javascript_第1张图片

为什么变成了Object?

prototype被重新赋值的是一个{}, {}是new Object()的字面量,因此new Object()会将Object原型上的constructor传递给{},也就是Object本身。

因此,为了规范,在重写对象原型时一般都需要重新给constructor赋值,以保证实例对象的类型不被改写。

④Object.prototype.toString.call

toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型。

返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。

需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。

⑤jquery.type()

jQuery.type() === "undefined"

jQuery.type( /test/ ) === "regexp"

 

源码分析:

var class2type = {};
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); });

type: function( obj ) {
// 当obj为undefined或null时,直接返回对应的字符串形式
  if ( obj == null ) {
    return obj + "";
  }
// Support: Safari <= 5.1 (functionish RegExp)
// 当obj的类型为object或function时,执行class2type[ toString.call(obj) ]
// 如果是自己创建了数据类型的话,那么就会统一返回"object"
// 否则执行 typeof obj
  return typeof obj === "object" || typeof obj === "function" ?
    class2type[ toString.call(obj) ] || "object" :
    typeof obj;
},

 

undefined 和 null 有什么区别

http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html

javaScript权威指南: null 和 undefined 都表示“值的空缺”,你可以认为undefined是表示系统级的、出乎意料的或类似错误的值的空缺,而null是表示程序级的、正常的或在意料之中的值的空缺。

null表示代表“空值”,代表一个空对象指针

null的典型用法:

作为函数的参数,表示该函数的参数不是对象

作为对象原型链的终点

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义

undefined的典型用法:

变量被声明了,但没有赋值时,就等于undefined

调用函数时,应该提供的参数没有提供,该参数等于undefined

对象没有赋值的属性,该属性的值为undefined

函数没有返回值时,默认返回undefined 

 

请指出document load和document ready的区别?

https://zhidao.baidu.com/question/432820456183363324.html

DOM文档加载的步骤:

(1) 解析HTML结构。
(2) 加载外部脚本和样式表文件。
(3) 解析并执行脚本代码。
(4) 构造HTML DOM模型。//ready
(5) 加载图片等外部文件。
(6) 页面加载完毕。//load
load:是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),执行一个函数
  问题:如果图片资源较多,加载时间较长,onload后等待执行的函数需要等待较长时间,所以一些效果可能受到影响
$(document).ready():是当DOM文档树加载完成后执行一个函数 (不包含图片,css等)所以会比load较快执行
在原生的jS中不包括ready()这个方法,只有load方法就是onload事件 

 

 

Js 有哪些创建对象的方式?

https://www.cnblogs.com/zczhangcui/p/6389023.html

https://blog.csdn.net/zpcqdkf/article/details/80401999

①{}

②new Object()

③使用字面量

④工厂模式:

function createPerson(name, age) {

    var o = new Object()

    o.name = name;

    o.age = age;

    o.sayName = function() {

        console.log(name)

    }

    return o;

}

var p1 = createPerson(...);

不足:每次通过Person创建对象的时候,所有的say方法都是一样的,但是却存储了多次,浪费资源

⑤构造函数模式(constructor):

function Person(name, age) {

    this.name = name

    this.age = age

    this.sayName = function() {

        console.log(name)

    }

}

var p1 = new Person(...);

与工厂模型相比,具有以下特点:

  1.没有显示创建对象;

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

  3.没有return语句;

  4.要创建新实例,必须使用new操作符;(否则属性和方法将会被添加到window对象)

  5.可以使用instanceof操作符检测对象类型

不足:

  构造函数模式隐试的在最后返回return this 所以在缺少new的情况下,会将属性和方法添加给全局对象,浏览器端就会添加给window对象,可以根据return this 的特性调用call或者apply指定this

  构造函数内部的方法会被重复创建,不同实例内的同名函数是不相等的。可通过将方法移到构造函数外部解决这一问题,但面临新问题:封装性不好。

⑥原型模式(prototype):

function Person() {};

Person.prototype = {

  name: 'xiaoming',

  friend: ['xiaoli'],

  sayName: function () {

    aleri(this.name);

  }

}

var p1 = new Person();

console.log(p1 instanceof Person);  //true

console.log(p1.prototype.constructor);  //Object

console.log(p1.constructor);  //Object

p1.constructor不再指向Person,而是指向了Object。如果constructor很重要,则需要特意将其设为适当的值,如:

Person.prototype  = {

  constructor: Person,  

  name: 'xiaoming',

  friend: ['xiaoli','xiaohong'],

  sayName: function () {

    aleri(this.name);

  }

}

但是这种方式会导致constructor属性变成可枚举。
如果想设置为不可枚举的(默认不可枚举),可以使用Object.defineProperty(Person.prototype, “constructor”, { 
  enumerable: false, 
  value: Person 
}); 

特点:实现了方法与属性的共享,可以动态添加对象的属性和方法。

不足:

  1.对于包含基本值的属性可以通过在实例上添加一个同名属性隐藏原型中的属性。然后,对于包含引用数据类型的值来说,会导致问题;

  2.没有办法创建实例自己的属性和方法,也没有办法传递参数。

⑦构造函数+原型模式:

function Person(name, age) {

  this.name = name;

  this.age = age;

}

Person.prototype  = {

  constructor: Person,  

  sayName: function () {

    aleri(this.name);

  }

}

特点:构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。

⑧动态原型模式:

function Person (name, age) {

  this.name = name;

  this.age = age;

  if(typeof this.sayName != 'function') {

    Person.prototype.sayName = function () {

      alert(this.name);

    };

  };

}

特点:在第一次调用构造函数时,将方法赋给原型对象的相应属性,其他示例的处理方式同构造函数模式;

⑨Object.create()

⑩寄生构造函数模式:

特点:仅仅封装创建对象的代码,然后再返回新创建的对象,仍使用new操作符调用;

    稳妥构造函数模式:

特点:没有公共属性,只有私有变量和方法,以及一些get/set方法,用以处理私有变量。

new一个对象经历了哪些步骤?

要创建person的实例,必须使用new操作符,以这种方式调用构造函数会经历4个步骤: 
1、创建一个新对象 
2、将构造函数的作用域(this)赋给新对象 
3、执行构造函数中的代码 
4、返回新对象 

 

对 this 的理解?

http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

this为作用域上下文

一般情况下函数执行时,this总是指向调用该函数的对象。

当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域,由上下文确定。

使用场景:

①在全局环境中,this 永远指向 window。

  普通函数在调用时候(注意不是构造函数,前面不加 new),其中的 this 也是指向 window

  匿名函数中的this指向全局对象window

  setInterval和setTimeout定时器中的this指向全局对象window

②构造函数:如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象。

③方法调用:如果函数作为对象的方法时,方法中的 this 指向该对象。

④构造函数 prototype 属性:在整个原型链中,this 代表的也是当前对象的值。

⑤call/apply/bind调用:当一个函数被 call、apply 或者 bind 调用时,this 的值就取传入的对象的值。

⑥DOM绑定事件:在一个 HTML DOM 事件处理程序里,this 始终指向这个处理程序所绑定的 HTML DOM 节点

⑦箭头函数:当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域。

函数执行时,this总是指向调用该函数的对象(即:判断this所在的函数属于谁)。

 

apply()、call()和 bind() 的区别及使用?

https://segmentfault.com/a/1190000018017796

三者的相同点:都是用来改变this的指向

call 和 apply 的主要作用,是改变对象的执行上下文,并且是立即执行的。它们在参数上的写法略有区别。

call 的语法:

Function.call(obj,[param1[,param2[,…[,paramN]]]])
注意点:
  • 调用 call 的对象,必须是个函数 Function。
  • call 的第一个参数,是一个对象。 Function 的调用者,将会指向这个对象。如果不传,则默认为全局对象 window。
  • 第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。但是如果将所有的参数作为数组传入,它们会作为一个整体映射到 Function 对应的第一个参数上,之后参数都为空。

apply 的语法:

Function.apply(obj[,argArray])
注意点:
  • 调用 apply 的对象,必须是个函数 Function。
  • 第二个参数,必须是数组或者类数组,它们会被转换成类数组,传入 Function 中,并且会被映射到 Function 对应的参数上。这也是 call 和 apply 之间,很重要的一个区别。

bind 方法也能改变函数体内的 this 指向。不同的是,bind 方法的返回值是函数,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。

bind语法:

Function.bind(thisArg[, arg1[, arg2[, ...]]])

使用场景:

call

  对象的继承

  判断数据类型

    Object.prototype.toString.call();

  将类数组变为数组

    Array.prototype.slice.call(arguments);

apply

  求数组最大值

    let max = Math.max.apply(null, array);

  实现两个数组合并

    let arr1 = [1, 2, 3];     let arr2 = [4, 5, 6];     Array.prototype.push.apply(arr1, arr2);

 

new 操作符具体干了什么

https://cloud.tencent.com/developer/article/1195936?from=10680

https://www.jianshu.com/p/e7015984f608

https://www.jianshu.com/p/db4ae33d1e53

// ①新建一个空对象obj
let obj  ={}; // ②obj的__proto__属性指向原型对象 obj.__proto__ = A.prototype; // ③将构造函数的this绑定obj,传入构造函数的参数,并将返回结果赋值给result let result = A.apply(obj, arguments); // ④如果result存在且result是对象或者函数,则构造函数返回result,否则将返回obj return (result && (typeof(result) === 'object' || typeof(result) === 'function')?result:obj);

使用关键字new创建新实例对象经过了以下几步:

1、创建一个新对象,如:var person = {};

2、新对象的proto属性指向构造函数的原型对象。

3、将构造函数的作用域赋值给新对象。(也所以this对象指向新对象)

4、执行构造函数内部的代码,将属性添加给person中的this对象。

5、返回新对象person。

  var person = {};  
  person._proto_ = Person.prototype;//引用构造函数的原型对象  
  Person.call(person);//将构造函数的作用域给person,即:this值指向person Function.methos("new", function () { //新创建一个对象,它继承了构造器的原型对象。 var that = Object.create(this.prototype); //此时,this是指向Function构造器的。 //调用构造器,绑定this对象到新对象that上 var other = this.apply(that, argument); //此时,this对象指向that对象。 //如果它的返回值不是一个对象,就返回新的对象。 return (typeof other === "object" && other) || that; }); 

先看代码

var Func = function(){ }; 

var func = new Func ();  

new共经过了4几个阶段

1、创建一个空对象

var obj = new Object();  

2、设置原型链

obj.__proto__ = Func.prototype;  

3、让Func中的this指向obj,并执行Func的函数体。

var result = Func.call(obj);  

4、判断Func的返回值类型:

如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。

if (typeof(result) == "object"){  

func = result;  

}  else{  

func = obj;  

}  

可以看出new省略了哪几步:

 

1.不用手动新建一个obj ,new会帮你创建

 

2.不用把新建的obj的__proto__指向构造函数Common的prototype,new会帮你做。

 

3.构造函数this的作用域会指向实例本身。

 

4.不用手动return新建的obj,new会帮你return。

 

5.new出来的实例的__proto__会指向构造函数的prototype。构造函数的方法,实例可以直接调用。

 

 

JS如何实现对对象的拷贝(浅拷贝与深拷贝)?

https://blog.csdn.net/yaodebian/article/details/82778403

JS中对象分为基本类型和复合(引用)类型,基本类型存放在栈内存,复合(引用)类型存放在堆内存。

堆内存用于存放由new创建的对象,栈内存存放一些基本类型的变量和对象的引用变量。

  • 浅拷贝:浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响;
  • 深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响;

浅拷贝分两种情况,一是直接拷贝源对象的引用,二是源对象拷贝实例,但其属性(类型为Object、Array的属性)拷贝引用。

源对象拷贝实例,其属性对象拷贝应用

这种情况下,外层源对象是拷贝实例,如果其属性元素为复杂数据类型时,内层元素拷贝引用。

对于对象实例的拷贝,常用的方法有:Array.prototype.slice(), Array.prototype.concat(), jQuery的$.extend({},obj)和ES6中的拓展运算符(...)

例:

var a = [{c:1}, {d:2}];

var b = a.slice();

console.log(a === b); // 输出false,说明外层数组拷贝的是实例

a[0].c = 3;

console.log(b[0].c); // 输出 3,说明其元素拷贝的是引用

深拷贝方法:

①JSON.parse(JSON.stringify(目标对象); ( 即JSON.parse()和JSON.stringify() )

var a = {...};

var temp = JSON.stringify(a);

var b = JSON.parse(temp);

不足:只能拷贝符合JSON数据标准类型的对象,对于包含有function或者正则类型值解析时会报错

②使用递归

var clone = function (obj) {

  if (obj === null) return null;

  if (typeof obj !=== 'object') return obj;

  if (obj.custructor === Date) return new Date(obj);

  var newObj = new obj.constructor();  //  保持继承链

  for (var key in obj) {

    if (obj.hasOwnProperty(key)) {  //不遍历其原型链上的属性

      var val = obj[key];

      //使用arguments.callee解除与函数名的耦合

      newObj[key] = typeif val === 'object' ? arguments.callee(val) : val;  

    }

  }

  return newObj;

}

这里有三点需要注意:

1、用new obj.constructor ()构造函数新建一个空的对象,而不是使用{}或者[],这样可以保持原形链的继承;
2、用obj.hasOwnProperty(key)来判断属性是否来自原型链上,因为for..in..也会遍历其原型链上的可枚举属性。
3、上面的函数用到递归算法,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,需要使用 arguments.callee。

③lodash —— _.cloneDeep()

很好地兼容了ES6的新引用类型,而且处理了环型对象的情况

 

JS如何实现继承?

http://www.php.cn/js-tutorial-411754.html

 

JS中的类型转换规则?

https://cloud.tencent.com/developer/article/1186778

转换为字符型方法:

1、利用引号(“”)转换为字符型

2、利用函数String();转换为字符型 var num=10; console.log(String(num));//输出为字符型

布尔型:true和false

1、利用!!转换为布尔型 var num=20; console.log(!!num)

2、利用Boolean()转换

3、var num="0"; num++; console.log(num);//1

var num="0"; num=num+1; console.log(num);//01

转换为数值型

1、-、*、/可以强制转换

2、利用Number();

parseInt(10,2)//2(将10这个二进制转换为十进制数) parseInt(值,进制数)parseFloat()

NAN,不是一个数字

 

什么是闭包?

https://cloud.tencent.com/developer/article/1054445

https://cloud.tencent.com/developer/article/1390165

https://cloud.tencent.com/developer/article/1009285

https://cloud.tencent.com/developer/article/1407782

remember 词法作用域的基础规则:函数被执行时(executed)使用的作用域链(scope chain)是被定义时的scope chain,而不是执行时的scope chain

闭包:其实就是将函数内部和函数外部连接起来的一座桥梁,可以让函数外部的代码访问函数内容变量,可以把闭包简单理解成“定义在一个函数内部的函数”

function Person() {

    var name = 'hello'

    function say () {

        console.log(name)

    }

    return say()

}

Person() // hello

由于 JavaScript 特殊的作用域,函数外部无法直接读取内部的变量,内部可以直接读取外部的变量,从而就产生了闭包的概念

闭包有三个特性:

1.函数嵌套函数 

2.函数内部可以引用外部的参数和变量 

3.参数和变量不会被垃圾回收机制回收

用途:

最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

使用场景:

闭包经典使用场景一:通过循环给页面上多个dom节点绑定事件

闭包使用场景二:封装变量和方法

闭包使用场景三:延续局部变量的寿命

闭包使用场景四:采用函数引用方式的setTimeout调用

闭包使用场景五:将函数关联到对象的实例方法

 

注意点:

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露

 

介绍一下 JavaScript 原型?原型链?它们有何特点

(1)原型

首先明确一点,JavaScript是基于原型的

每个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针。

(2)原型链

JavaScript中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链。

所有原型链的终点都是Object函数的prototype属性。Objec.prototype指向的原型对象同样拥有原型,不过它的原型是null,而null则没有原型

1.JS中每个函数都存在有一个原型对象属性prototype。并且所有函数的默认原型都是Object的实例。

2.原型链,简单理解就是原型组成的链,对象的__proto__它的是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__想上找,这就是原型链,当向上找找到Object的原型的时候,这条原型链就算到头了。

javascript_第2张图片

instanceof是判断实例对象的__proto__和生成该实例的构造函数的prototype是不是引用的同一个地址。

javascript_第3张图片

3.原型链实现了继承。原型链存在两个问题:

(1)、包含引用类型值的原型属性会被所有实例共享。

(2)、 在创建子类型时,无法向超类型的构造函数中传递参数。

 

Ajax是什么? 如何创建一个Ajax?

  ajax的全称:AsynchronousJavascript And XML。

  异步传输+js+xml。

  所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。

  (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象

  (2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息

  (3)设置响应HTTP请求状态变化的函数

  (4)发送HTTP请求

  (5)获取异步调用返回的数据

  (6)使用JavaScript和DOM实现局部刷新

同步和异步的区别?怎么异步加载 JavaScript?

(1)

  同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,j进行下一步操作。

  异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

(2)

动态添加 script 标签

defer

async

defer属性和async都是属于 script 标签上面的属性,两者都能实现 JavaScript 的异步加载。不同之处在于:async 在异步加载完成的时候就马上开始执行了,defer 会等到 html 加载完毕之后再执行

 

 

什么是内存泄漏?哪些操作会造成内存泄漏?

http://www.ruanyifeng.com/blog/2017/04/memory-leak.html

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

内存泄漏:是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束

可能造成内存泄漏的操作:

1. 意外的全局变量

2. 闭包

3. 控制台日志

4. 循环引用(在两个对象彼此引用且彼此保留时,就会产生一个循环)

5. DOM清空或删除时,时间未清除导致的内存泄漏

6. 被遗忘的定时器或者回调函数

7. setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。

谈谈垃圾回收机制方式及内存管理

回收机制方式

1、定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。

2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

3、实例如下:

function fn1() {

    var obj = {name: 'hanzichi', age: 10};

}

function fn2() {

    var obj = {name:'hanzichi', age: 10};

    return obj;

}

var a = fn1();var b = fn2();

fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。

垃圾回收策略:标记清除(较为常用)和引用计数。

标记清除:

  定义和用法:当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境"。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。

  到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。

引用计数:

  定义和用法:引用计数是跟踪记录每个值被引用的次数。

基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。

什么时候触发垃圾回收?

垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。

IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。

IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。

2、合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象。

3、GC缺陷:(1)、停止响应其他操作;

4、GC优化策略:(1)、分代回收(Generation GC);(2)、增量GC

 

AMD(Modules/Asynchronous-Definition)、CMD(Common ModuleDefinition)规范区别?

  AsynchronousModule Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。

  区别:

  1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

  2. CMD 推崇依赖就近,AMD 推崇依赖前置。

对AMD和CMD的理解,它们有什么区别

AMD和CMD都是为了解决浏览器端模块化问题而产生的,AMD规范对应的库函数有 Require.js,CMD规范是在国内发展起来的,对应的库函数有Sea.js

AMD和CMD最大的区别是对依赖模块的执行时机处理不同

1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块

2、CMD推崇就近依赖,只有在用到某个模块的时候再去require

 

 

 

什么冒泡与捕获?事件委托的原理是什么?它的使用场景有哪些?

https://www.cnblogs.com/diver-blogs/p/5649270.html

事件冒泡:当一个子元素的事件被触发的时候(如onclick事件),该事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件。

事件委托:即是事件代理:事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。

将事件处理器绑定到一个父级元素上,避免了频繁的绑定多个子级元素,依靠事件冒泡机制与事件捕获机制,子级元素的事件将委托给父级元素。

原理:利用事件冒泡和事件捕获机制实现的

优点:只需要将同类元素的事件委托给父级或者更外级的元素,不需要给所有元素都绑定事件,减少内存空间占用,提升性能; 动态新增的元素无需重新绑定事件

阻止事件冒泡:

w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

阻止元素默认的行为(如链接的跳转、表单的提交):

w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;

 

拖拽会用到哪些事件被拖拽元素

dragstart 按下鼠标键并开始移动鼠标时 
drag 在dragstart事件之后,在元素被拖动期间会持续触发该事件 
dragend 当拖动停止时,会触发dragend事件 
放置目标元素
dragenter 有元素被拖动到放置目标上 
dragover 紧随dragenter发生,在被拖动的元素
还在放置目标范围内移动时,会持续触发该事件 
dragleave 在元素被拖出放置目标时触发 
drop 元素被放到了放置目标中触发 
注释:拖拽发生过程:dragstart->drag->dragenter->dragover->dragleave/drop->dragend

 

Javascript中的定时器有哪些?他们的区别及用法是什么?

setTimeout 只执行一次
setInterval 会一直重复执行

 

如何使用ajax?

第一步,创建xmlhttprequest对象,var xmlhttp =new XMLHttpRequest();XMLHttpRequest对象用来和服务器交换数据。

var xhttp;

if (window.XMLHttpRequest) {

xhttp = new XMLHttpRequest();                              //现代主流浏览器

} else {

xhttp = new ActiveXObject("Microsoft.XMLHTTP");   // 针对浏览器,比如IE5或IE6

}

第二步,使用xmlhttprequest对象的open()和send()方法发送资源请求给服务器。

第三步,使用xmlhttprequest对象的responseText或responseXML属性获得服务器的响应。

第四步,onreadystatechange函数,当发送请求到服务器,我们想要服务器响应执行一些功能就需要使用onreadystatechange函数,每次xmlhttprequest对象的readyState发生改变都会触发onreadystatechange函数

 

json和xml的区别?

https://www.cnblogs.com/SanMaoSpace/p/3139186.html

JSON的定义

一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换。JSON采用兼容性很高的文本格式,同时也具备类似于C语言体系的行为。

XML的定义

扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。

区别:
  1. 数据体积方面,JSON相对XML来讲,数据的体积小,传递的速度更快些
  2. 数据交互方面,JSON与JavaScript的交互更加方便,更容易解析处理,更好地进行数据交互
  3. 数据描述方面,JSON对数据的描述性比XML较差
  4. 传输速度方面,JSON的速度要远远快于XML

json字符串如何转json对象JSON.stringify(),json对象如何转json字符串JSON.parse()

 

请解释JSONP的工作原理,以及它为什么不是真正的AJAX?

https://segmentfault.com/a/1190000009742074

https://www.cnblogs.com/soyxiaobi/p/9616011.html

 

JSONP (JSON with Padding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标记来动态加载其他域的资源。例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在 pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。

AJAX是不跨域的,而JSONP是一个是跨域的,还有就是二者接收参数形式不一样!

  

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

1)创建新节点

createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点

2)添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入

3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性

 

有多个请求第一个完成后才执行第二,第二个完成后才执行第三个,你有几种方法实现?

  方法一:设置ajax的async:false

  方法二:用es6的promise

 

如何防止表单重复提交?有几种方法?

方法一:定义一个flag=false,改变flag的值

方法二:设置button的禁用属性

方法三:利用session

 

WEB应用从服务器主动推送Data到客户端有那些方式?

html5提供的Websocket

不可见的iframe

WebSocket通过Flash

XHR长时间连接

XHR Multipart Streaming

你可能感兴趣的:(javascript)