2021/11/18
第一题
结果:15岁的小红在操场上运动
考点:this指向,call,apply,bind问题
分析:使用了call方法,因此this指向了p2
this指向:
前提:
- this永远指向一个对象
- this的指向完全取决于函数调用的位置
- this指的是函数运行时所在的环境
参考:this的原理
总结:
函数调用模式:
this被绑定为全局对象,在浏览器环境下就是window对象
function a(){
let a = 'hello';
console.log(this.hello);//undefined
console.log(this);//window
}
a();
方法调用模式:
当一个函数被保存为一个对象的属性时,那么这个函数就称为这个对象的方法。当一个方法被调用时,this被绑定到这个对象上
let o={
name: 'hello',
sayName: function(){
console.log(this.name)//hello
console.log(this) //o这个对象
}
}
o.sayName();
this指向的对象为o
let o={
name:'hello',
b:{
name: 'world',
sayName: function(){
console.log(this.name)//world
console.log(this)//b这个对象
}
}
}
o.b.sayName();
this指向的对象为b,因为是o.b调用的这个函数
let name='我是最外面的name';
let o={
name:'hello',
b:{
name: 'world',
sayName: function(){
console.log(this.name)//我是最外面的name
console.log(this)//window
}
}
}
let t=o.b.fn;
t();
t是全局变量,在全局环境下执行,this指向window
构造函数调用模式:
构造函数和普通函数的区别就是调用方式不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
function Person(){
alert(this);
}
//普通函数调用
var per1 = Person();//this是window
console.log(per1);//输出undefined,因为per1接受的是函数Person()的返回值,而Person()没有返回值,所以undefined
//构造函数调用
var per2 = new Person();//this是新建的对象 Person{}
console.log(per2);//输出Person(对象)
function Person(){
this.name = "Tiny Colder";
var age = 22;
window.age = 22;
}
var p = new Person();
alert(p.name)//Tiny Colder;
alert(p.age)//undefined;
alert(window.age)//22;
调用一个构造函数,执行流程分为4步:
- 立刻创建一个新的对象(一个Object对象实例):使用了new关键字,在堆内存开辟了一个新的空间去创建对象
- 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象(将构造函数的执行对象赋给新生成的这个实例)。
- 逐行执行函数中的代码
- 将新建的对象作为返回值返回
因此:在构造函数中,new出一个对象时,this指向这个构造函数,new关键字会改变this的指向。当用new关键字,返回的是一个对象,this指向的就是那个返回的对象;如果返回的不是对象,this还是指向函数的实例,虽然null属于对象,但是返回null依然指向函数实例。
如果被调用的函数没有显式的 return 表达式(仅限于返回对象),则隐式的会返回 this 对象 - 也就是新创建的对象。
可参考 构造函数中this的指向问题
function Fn(){
this.name='hello';
}
let f=new Fn();
console.log(f.name);//hello
没有显示的return表达式,因此this指向的是返回的创建的Fn实例
function Fn(){
this.name='hello';
return {}
}
let f=new Fn();
console.log(f.name);//undefined
function Fn(){
this.name='hello';
return function(){};
}
let f=new Fn();
console.log(f.name);//null
function Fn(){
this.name='hello';
return 1;
}
let f=new Fn();
console.log(f.name);//hello
function Fn(){
this.name='hello';
return undefined;
}
let f=new Fn();
console.log(f.name);//hello
function Fn(){
this.name='hello';
return null;
}
let f=new Fn();
console.log(f.name);//hello
function Fn(){
this.name='hello';
return [];
}
let f=new Fn();
console.log(f.name);//undefined
总结:
显式的返回以下值:undefined, null, boolean, number等基础类型,并不会代替 new 式调用的默认行为。
但显式返回以下值 对象,复杂类型:{},[],RegExp, Date, Function,均会代替 new 调用的默认返回值 this.
call和apply调用模式
JS中,函数也是对象,所有函数对象都有两个方法:apply和call,这两个方法可以让我们构建一个参数数组传递给调用函数,也允许我们改变this的值
var name='obj1';
var o={
name:'obj2'
};
function sayName(){
console.log(this.name);
}
sayName();//obj1
sayName.apply();//obj1
sayName.apply(o);//obj2
sayName.call(o);//obj2
sayName.call();//obj1
call和apply的作用都是改变this作用域,都是在特定作用域中调用函数。当一个对象没有某个方法,而其他对象有,我们就可以使用call或apply实现某个方法的复用。
call和apply使用方法基本相同,唯一不同之处就是它们的参数规则:
call方法接受一个参数列表,将实参在对象之后依次传递fun.call(obj,2,4)
apply方法接受一个包含多个参数的数组,需要将实参封装到数组中统一传递fun.apply(obj,[2,4])
。
第二题
知识点:正则表达式
[]里的内容是或的关系:[ab]意为a或b;所以[0-9a-fA-F]意为可以是数字也可以是大小写字母
{}前面的内容重复多少次
第三题
答案:undefined
解析:
let和var区别:
- 如果在全局作用域中用var声明,此变量会默认成为window的一个属性,let声明的变量是不会添加到window对象中的;
- let声明的范围是块级作用域(用{}包含的区域),var声明的范围是函数作用域;
- var声明的变量有变量提升的特性,而let没有
- var可以允许重复声明相同变量,后者会覆盖前者,而let不能重复声明相同变量
var声明的对象有变量提升的特性,因此a在window上定义了,但没有赋值,a在window里为true,取反为false,因此直接alert(a)。为undefined
第四题
结果为:5 5 5 5 5
解析:requestAnimationFrame为异步执行(宏任务)的,因此for循环中的requestAnimationFrame会在循环退出的时候才执行其中的回调,注意循环退出的时候i的值为5
如果是为let,结果就变为0,1,2,3,4。var为函数作用域,异步函数在for循环结束后还未执行,函数作用域的 i 就变为了5。let为块级作用域,每一次for循环都会产生一个块级作用域
第五题
解析:
Ajax不是新的编程语言,而是一门提供网页局部刷新的技术。
Ajax最大的优点是在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页内容。
Ajax技术核心就是XMLHttpRequest对象。
Ajax技术的工作原理:可以分成3步
-
创建Ajax对象:var xhr = new XMLHttpRequest();
-
xhr 发送请求:
xhr.open(‘get’,‘test.html’,‘true’);
xhr.send(); -
xhr获取响应:
xhr.onreadystatechange = function(){
if(xhr.readystate == 4){//请求的状态码
/*
0:请求还没有建立(open执行前)
1:请求建立了还没发送(执行了open)
2:请求正式发送(执行了send)
3:请求已受理,有部分数据可以用,但还没有处理完成
4:请求完全处理完成
*/
alert(xhr.responseText);//返回的数据
}
}
可以看到,send()前是open()
2021/11/19
第一题
顺序为CBAD
解析:
- 首先,Node在当前目录下查找package.json(CommonJS包规范定义的包描述文件),通过JSON.parse()解析出包描述对象,从中取出main属性指定的文件名进行定位。如果文件缺少扩展名,将会进入扩展名分析的步骤。
- 而如果main属性制定的文件名错误,或者压根没有package.json文件,Node会将index当做默认文件名,然后依次查找index.js、index.node、index.json.
- 如果在目录分析的过程中没有定位成功任何文件,则自定义模块进入下一个模块路径进行查找。如果模块路径数组都被遍历完毕,依然没有查找到目标文件,则会抛出查找失败异常。
- 按照上面的思路,首先应该查找package.json文件,看看里面有没有核心模块,应该是C最先,othermodule不是核心模块,那么接着应该进入扩展名分析的步骤,就应该是查找othermodule. js,对应B,紧接着就是以index为默认文件名,也就是A,再接下来就是上一个文件目录D了,
第二题
总结:
node节点有几个常用的属性
- firstChild
- lastChild
- nextSibling:下一个兄弟节点
- previousSibling:前一个兄弟节点
这些都是属性,都不需要添加括号的。
第三题
总结:
- 两个对象不相等 除非指向同一个对象地址
- 恒等不会进行数据类型转换
- 双等会进行数据类型转换,字符串转换成数值在进行对比
第四题
Object.keys()
该方法返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组。
String.prototype.split()
split() 方法使用指定的分隔符字符串将一个String对象分割成字符串数组,以将字符串分隔为子字符串,以确定每个拆分的位置。
Array.prototype.join()
join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。
Promise.all()
Promise.all(iterable) 方法返回一个 Promise 实例(对象),此实例在 iterable 参数内所有的promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);
如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
第五题
下面哪些方式在同一个窗口下能够检测一个js对象是数组类型?( )
检测数据的类型的方法:
- typeof:只能检测基本的数据类型,注意:正则,{},[],null输出结果都为object
- instanceof:检测当前实例是否属于某个类,返回值为布尔值
- Array 为 js 的原生对象,它有一个静态方法:Array.isArray(),能判断参数是否为数组, isNaN() 判断是否是NaN
- Object.prototype.toString.call([value]);获取 Object.portotype 上的 toString 方法,让方法的 this 变为需要检测的数据类型值,并且让这个方法执行;在Number、String、Boolean、Array、Function、RegExp…这些类的原型上都有一个toString方法:这个方法就是把本身的值转化为字符串;在Object这个类的原型上也有一个方法toString,但是这个方法并不是把值转换成字符串,而是`返回当前值得所属类详细信息,固定结构:’[object 所属的类]’
var obj = {name: '珠穆朗玛峰'}
obj.toString() // "[object Object]"
Object.prototype.toString.call(12) // "[object Number]"
Object.prototype.toString.call(true) // "[object Boolean]"
2021/11/20
第一题
AMD和CMD都是浏览器端的js模块化规范,分别由require.js和sea.js实现。 CommonJS是服务器端的js模块化规范,由NodeJS实现。
第二题
解析:
undefined值是通过null派生出来的,相等时它会自动转化为null,所以返回true。不过如果用严格比较符 ===,不发生转化,将返回false。
es6中的Symbol属于新的js数据类型
第三题
解析:
call()方法和apply()方法的作用相同,他们的区别在于接收参数的方式不同。对于call第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。(在使用call()方法时,传递给函数的参数必须逐个列举出来。使用apply时,传递给函数的是参数数组
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
第四题
解析:
- parseFloat():parseFloat() 函数可解析一个字符串,并返回一个浮点数。A选项的结果为0.6000000000000001
- toFixed :把数字转换为字符串,结果的小数点后有指定位数的数字,按四舍五入取值。
var num = 5.56789;var n=num.toFixed(2);
结果为5.57。B选项的结果为0.6 - Math.round():round() 方法可把一个数字舍入为最接近的整数,按四舍五入取值。C选项的结果为1
- toPrecision():把数字格式化为指定的长度,返回的是一个字符串。
var num = new Number(13.3714);var n=num.toPrecision(2);
结果为13。0.08.toPrecision(1)
结果为‘0.08’,0.8.toPrecision(1)
结果为’0.8’;0.18.toPrecision(1)
结果为0.2;D选项中先使用toPrecision将0.8转为字符0.8,在使用parseFloat进项解析,返回一个浮点数0.8
第五题
解析:
exec() 方法用于检索字符串中的正则表达式的匹配。
返回值:返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。
所以"e".exec(“hello”)中,"e"是正则表达式,“hello"是检索的字符串。在"hello"字符串中,能够匹配到"e”。因此document.write(“e”);最后结果为e。
第六题
- 非严格模式下JavaScript语句中“this”默认指向全局对象(window)。
- this绑定的优先级是new>bind>call(apply)>obj.func()>默认绑定
- obj.log = console.log;//在obj对象中创建了一个函数(即console.log)的引用log,因为是个函数的引用,如果想要执行可以有两种方法,第一种是后边加(),第二种是使用apply()或者call(),二者第一个参数都是this,接下来的参数apply是参数数组或者是"arguments",而call的参数是直接的参数值
- obj.log.call(console,this);//如上所述,call的第二个参数是要被传入obj.log()的参数,这行代码其实可等价于console.log(this),而因为这三行代码都是在global环境下定义的(不是函数中的局部变量),所以this就是window.
第七题
解析:
JS中,可以将对象分为“内部对象”、“宿主对象”和“自定义对象”三种。
内部对象
js中的内部对象包括Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、String以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、SyntaxError和TypeError。其中Global和Math这两个对象又被称为“内置对象”,这两个对象在脚本程序初始化时被创建,不必实例化这两个对象。
宿主对象
宿主对象就是执行JS脚本的环境提供的对象。对于嵌入到网页中的JS来说,其宿主对象就是浏览器提供的对象,所以又称为浏览器对象,如IE、Firefox等浏览器提供的对象。不同的浏览器提供的宿主对象可能不同,即使提供的对象相同,其实现方式也大相径庭!这会带来浏览器兼容问题,增加开发难度。
浏览器对象有很多,如Window和Documen,Element,form,image,等等。
自定义对象
顾名思义,就是开发人员自己定义的对象。JS允许使用自定义对象,使JS应用及功能得到扩充
第八题
解析:
第九题
解析:
静态语言(强类型语言)
静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。
例如:C++、Java、Delphi、C#等。
动态语言(弱类型语言)
动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
例如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等等。