释一下为何[ ]==![ ] // ---> true
首先看一张图
![ ] 是 false
原式:[ ]==false
根据第八条,false通过tonumber()转换为0
原式:[ ]==0
根据第十条,[ ]通过ToPrimitive()转换为' '
原式:' '==0
根据第六条
原式:0==0
尝试实现new
function ObjectClass() {//对象
console.log(arguments[0])
}
ObjectClass.prototype.constructor=ObjectClass
function create() {
// 创建一个空的对象
var obj={}
// 获得构造函数
var _constructor=this
// 链接到原型
obj.__proto__=_constructor.prototype
// 绑定 this,执行构造函数
var result=_constructor.apply(obj, arguments)
// 确保 new 出来的是个对象
return typeof result==='object' ? result : obj
}
create.call(ObjectClass, 'hello world')//实例化
拓展typeof功能使其支持更多类型(array,object,null区分),并解释一下typeof null为何是object
function myTypeOf(target) {
var _type=typeof (target)
var temp={
"[object Object]": 'object',
"[object Array]": 'array',
"[object Number]": 'number',
"[object String]": 'string',
"[object Boolean]": 'boolean'
}
if (target===null) {
return 'null'
} else if (_type=='object') {
var str=Object.prototype.toString.call(target)//根据toString区分
return temp[str]
} else {
return _type
}
}
console.log(myTypeOf('hello')) //string
console.log(myTypeOf(111)) // number
console.log(myTypeOf(true)) // boolean
console.log(myTypeOf({})) // object
console.log(myTypeOf([])) // array
console.log(myTypeOf(null)) // null
console.log(myTypeOf(undefined)) // undefined
console.log(myTypeOf(Symbol())) // symbol
typeof null为何是object
因为在早期js初版本中,操作系统使用的是32位,出于性能考虑,使用低位存储变量类型,object的类型前三位是000,而null是全0,从而系统将null误判为object
instanceof是什么?尝试实现一下
用官话来讲:instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
通俗来讲,a instanceof b也就是判断a是否是由b实例化得来的
实现:
function ObjectClass() {}
ObjectClass.prototype.constructor=ObjectClass
var _objectClass=new ObjectClass()
function myInstanceof(orgProto, tag) { //org前者,实例化对象, tag后者,类
var tagProto=tag.prototype
orgProto=orgProto.__proto__
for (;;) { //死循环查询原型链上是否有类的原型
if (orgProto===null) {
return false
}
if (orgProto===tagProto) {
return true
}
orgProto=orgProto.__proto__
}
}
console.log(myInstanceof(Object, Function)) // true
console.log(myInstanceof(Object, Object)) // true
console.log(myInstanceof(String, Object)) // true
console.log(myInstanceof(_objectClass, Object)) // true
console.log(myInstanceof(String, String)) // false
console.log(myInstanceof(Boolean, Boolean)) // false
解释以下代码分别在控制台显示什么,并简单说明
有一个对象Car,分别对以下四种情况进行作答
Car.prototype.name='BMW'
function Car() {}
1.实例化对象时打印BMW,因为Car.prototype.name='BMW',实例化的car本身没有name属性,于是会在Car的原型上找。此时将Car.prototype.name='Benz',实例化后的car.name也会等于Benz,因为name是基本数据类型(原始值),当值发送变化,实例化后的对象也会改变
var car=new Car()
console.log(car.name) //BMW
Car.prototype.name='Benz'
console.log(car.name) //Benz
2.实例化对象时打印Benz,因为在实例化之前就已经改变构造函数原型上的name值
Car.prototype.name='Benz'
var car=new Car()
console.log(car.name) //Benz
3.第一个log的BMW与上述一样,第二个log依然打印BMW的原因是,这里将Car.prototype直接改变成另一个对象,由于对象是引用数据类型(引用值),指向的是内存地址而不是值,new之前和new之后的实例对象引用的name地址不同
var car=new Car()
console.log(car.name) //BMW
Car.prototype={
name: 'Benz'
}
console.log(car.name) //BMW
4.和上述相同,原因是修改了prototype,改变的是引用地址,new之前和new之后的实例对象引用的name地址不同
Car.prototype={
name: 'Benz'
}
var car=new Car()
console.log(car.name) //Benz
写一个函数,计算字符串Unicode总长度(例如:abcd,打印4,qwerdf,打印6)
需要注意的是,英文字符占1个字节,中文字符占两个字节
function unicodeLength(str) {
for (var i=0, count=0; i < str.length; i++) {
console.log(str.charCodeAt(i))
if (str.charCodeAt(i) > 255) { //中文字符
count +=2
} else { //英文字符
count++
}
}
return count
}
console.log(unicodeLength('hello,1024,你好')) //17
实现一下js中window自带的isNaN()函数
注意点:如果直接使用NaN==NaN来判断,会返回false,需要将NaN转换成字符串,再来判断
isNaN('asda') //window下的原函数
console.log(isNaN(13)) //false
console.log(isNaN('aaa')) //true
function myIsNaN(number) {
return "" + Number(number)=="NaN" ? true : false
}
console.log(myIsNaN(32323)) //false
console.log(myIsNaN('aaa')) //true
实现数组push()方法
function myPush() {
for (var i=0; i < arguments.length; i++) {
this[this.length]=arguments[i]
}
return this.length
}
Array.prototype.myPush=myPush
var list=[1, 2, 3, 4, 5]
var item=6
console.log(list.myPush(item)) //6
console.log(list) //[1, 2, 3, 4, 5, 6]
实现数组乱序(提示:使用Array.sort)
Array.sort((a,b)=>{})中a-b升序,b-a降序
Array.prototype.random=random
function random() {
this.sort(function () {
return Math.random() - 0.5
})
return this
}
var list=[1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(list.random())//[3, 2, 6, 4, 9, 8, 1, 5, 7] 结果每次都不同
以下代码在控制台显示什么?说明原因
var obj={
"0": 'a',
"1": 'b',
"2": 'c',
"length": 3,
"push": Array.prototype.push
}
obj.push(1, 2, 3)
console.log(obj)
打印结果是
{
0: "a"
1: "b"
2: "c"
3: 1
4: 2
5: 3
length: 6
}
原因:说明原因之前先看一段Array.prototype.push的源码:
function ArrayPush () {
var n=TO_UNIT32(this.length);
var m=%_ArgumentsLength();
for (var i=0; i < m; i++) {
this[i + n ]=%_Arguments(i);
} this.length=n + m;
return this.length;
}
push的原理是在原对象后面将push的内容遍历进去,获取this.length并且在此基础上加上push的个数,这就不难解释为何push了三个数后length为6
解释以下代码打印为undefined的原因
var num=123;
num.item='abc'
console.log(num.item) //undefined
第一步:var num=123
第二步:num.item='abc'//隐式转换,相当于new Number(num).item='abc'(包装类生成引用类型数据),此时底层会判定此时的num是原始值,不存在属性值,所以执行delete(num.item)
第三步:打印undefined
使用JS原生实现function中的call,apply,bind函数
call:
Function.prototype.myCall=function () {
var _this=arguments[0] || window; //第一项是需要this指向的对象
_this._function=this //this是要执行的函数,改变指向为_this
var args=[] //把除this之外的所有参数放在args中
for (var i=1; i < arguments.length; i++) { //i=1,第二项到最后一项是参数
args[i - 1]=arguments[i]
}
return eval("_this._function(" + args + ")") //eval能将数组隐式拆分,效果与join相似,但二者区别很大,return将函数执行结果返回
delete _this._function //执行完成后删除当前_function,这个_function用来放this
}
var a='window'
var obj1={
a: 'obj1',
fn: function () {
console.log(this.a)
console.log(arguments)
}
}
var obj2={
a: 'obj2'
}
obj1.fn.myCall(obj2, 1, 2, 3, 4) //obj2 arguments[1, 2, 3, 4]
obj1.fn.myCall(this, 3, 2, 1) //window arguments[3, 2, 1]
apply(调用上面的myCall实现即可):
Function.prototype.myApply=function () {
var _this=arguments[0] || window; //第一项是需要this指向的对象
_this._function=this //this是要执行的函数,改变指向为_this
return eval("_this._function.myCall(_this, " + arguments[1] + ")") //eval能将数组隐式拆分,效果与join相似,但二者区别很大,return将函数执行结果返回
delete _this._function //执行完成后删除当前_function,这个_function用来放this
}
var a='window'
var obj1={
a: 'obj1',
fn: function () {
console.log(this.a)
console.log(arguments)
}
}
var obj2={
a: 'obj2'
}
obj1.fn.myApply(obj2, [1, 2, 3, 4]) //obj2 arguments[1, 2, 3, 4]
obj1.fn.myApply(this, [3, 2, 1]) //window arguments[3, 2, 1]
bind(继续调用上面myApply):
Function.prototype.myBind=function () {
var t=this;
var _this=arguments[0] || window; //第一项是需要this指向的对象
var args=Array.prototype.slice.myApply(arguments, [
1], ) //这项的目的是为了去除第一项arguments[0],就与上面的myCall中的遍历作用相同,Array.prototype.slice传一个参数,slice(start,end)表示删除第start到end项并返回删除后的数组,这里我们只用截取,不用删除,这里是删除第一项(由于用的是myApply,第二个参数是数组所以用[1])并返回删除后的数组
return function () {
return t.myApply(_this, args)
}
}
var a='window'
var obj1={
a: 'obj1',
fn: function () {
console.log(this.a)
console.log(arguments)
}
}
var obj2={
a: 'obj2'
}
obj1.fn.myBind(obj2, 1, 2, 3, 4)() //obj2 arguments[1, 2, 3, 4]
obj1.fn.myBind(this, 3, 2, 1)() //window arguments[3, 2, 1]
对mvvm,mvp和mvc的理解
Model–View–ViewModel(MVVM),Model-View-Presenter(MVP)和Model–View-Controller(MVC) 都是软件架构设计模式
相同的地方
不同的地方
谈谈对前端页面渲染的理解(过程,原理,性能,重绘和回流)
页面渲染分为以下步骤
1. 处理HTML语句标签并构建 DOM 树
2. 处理CSS语句并构建CSSOM树
3. 将处理好的DOM与CSSOM合并成一个渲染树
4. 根据渲染树来布局,计算每个节点的位置样式等等
5. 调 GPU(显卡)绘制页面,合成图层,最后显示在浏览器
在处理CSSOM时,会暂时堵塞DOM渲染,并且扁平层级关系有利于渲染速度,越详细的样式选择器,会导致页面渲染越慢
CSS加载会影响JS文件或语句加载,JS需要等待CSS解析完毕后运行
document中的DOMContentLoaded和Load的区别?:前者只需HTML加载完成后,就会触发,后者需要等HTML,CSS,JS都加载完成才会触发?????
图层概念:普通文档流就是一个图层,特定的属性可以生成一个新的图层。 不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议单独生成一个新图层,提高性能。但也不能生成过多的图层,会引起反作用
以下CSS属性可以生成新图层:
重绘(Repaint)和回流(Reflow)
重绘是当节点需要更改外观而不会影响布局的,比如改变color就叫称为重绘回流是布局或者几何属性需要改变就称为回流。
回流必定会发生重绘,重绘不一定会引发回流。
回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流。
所以以下几个动作可能会导致性能问题:
如何减少重绘和回流
谈谈对前端继承的理解
原型链继承,子类实例继承的属性有,子类构造函数的属性,父类构造函数的属性,父类原型上的属性
缺点:无法向父类传参,当父类原型上的属性改变时,所以子类实例相对应的属性都会对应改变
function Father() {
this.name="father";
this.sex="man"
}
Father.prototype.hobby='fish'
function Son() {
this.name="son";
}
// 原型链继承
Son.prototype=new Father()
var son1=new Son()
var son2=new Son()
Father.prototype.hobby='dog' //缺点,修改父类prototype上的属性时,所有子类都会随之修改
console.log(son1.hobby) // dog
console.log(son2.hobby) // dog
console.log(son1 instanceof Father) // true
构造函数继承(通过call,apply),子类可继承多个父类,可传参给父类
缺点:每个实例都有父类的构造函数,父类prototype上的属性无法继承
// 构造函数继承(通过call,apply)
function Father() {
this.name="father";
this.sex="man"
}
Father.prototype.hobby='fish'
function Son(sex) {
Father.call(this, sex) //可继承多个父类,但是每个实例都有父类的构造函数
this.name="son";
}
var son=new Son('woman')
console.log(son.sex) //woman,可传参给父类
console.log(son.hobby) //undefined,缺点,父类prototype上的属性无法继承
console.log(son instanceof Father) // false
组合继承,上述两者的结合,解决了上面的缺点和问题(常用)
缺点:Father.call()和new Father()执行了两次父类构造函数,增加了性能损耗,父类的原型上的constructor指向了子类,此时需要在实例化父类(new Father)后在实例化子类(new Son)之前添加一句话:Father.prototype.constructor=Father
// 组合继承
function Father(sex) {
this.name="father";
this.sex=sex
}
Father.prototype.hobby='fish'
function Son(sex) {
Father.call(this, sex) //可继承多个父类
this.name="son";
}
Son.prototype=new Father()
Father.prototype.constructor=Father //解决父类的原型上的constructor指向了子类
var son=new Son('woman')
console.log(son.sex) //woman,可传参给父类
console.log(son.hobby) //fish
console.log(son instanceof Father) // true
原型式继承,和Object.create相似,通过函数进行继承,会继承父类所有属性
缺点:父类原型上的属性发生变化时,所有子类对应属性都会改变,子类无法直接修改属性,复用性较差
// 原型式继承
function Father() {
this.name="father";
this.sex='man'
}
Father.prototype.hobby='fish'
function Son() {
this.name="son";
}
function inherit(father) {
function Fn() {}
Fn.prototype=father;
return new Fn() //类似于复制了father这个对象
}
var father=new Father()
var son1=inherit(father)
Father.prototype.hobby='dog' //缺点,修改父类prototype上的属性时,所有子类都会随之修改
var son2=inherit(father)
console.log(son1.sex) //man
console.log(son1.hobby) //dog
console.log(son2.hobby) //dog
console.log(son1 instanceof Father) // true
寄生式继承,继承父类所有属性,并且可以添加子类自己的属性方法
缺点:代码复用率低
function Father(sex) {
this.name="father";
this.sex=sex //实例传参
}
Father.prototype.hobby='fish'
function Son() {
this.name="son";
}
Object.prototype.myCreate=function (obj) {//实现Object.create
function Fn() {}
Fn.prototype=obj;
return new Fn()
}
function inherit(father) {
var _father=Object.myCreate(father)//克隆对象
_father.getInfo=function () {//增强子类,修改属性,产生子类独有的方法和属性,但是耦合高,复用性差,不同子类的写法各不同
console.log(_father.name)
console.log(_father.hobby)
console.log(_father.sex)
}
return _father;
}
var father=new Father('woman')
var son=inherit(father)
son.getInfo() //father,fish,woman
寄生式组合继承,继承父类所有属性,解决调用两次父类构造函数问题:一次是在创建子类型原型,一次在子类内部(理论上是最理想的继承)
// 寄生式组合继承
function Father(sex) {
this.name="father";
this.sex=sex //实例传参
}
Father.prototype.hobby='fish'
Father.prototype.getName=function () {
console.log(this.name)
}
function Son(sex) {
console.log(this.superClass) //Father
Father.call(this, sex); //构造函数继承传递参数
this.name="son";
this.hobby="dog";
}
Son.prototype.getName=function () {
console.log(this.name)
}
function Grandson(sex) {
console.log(this.superClass) //Son
Son.call(this, sex); //构造函数继承传递参数
this.name="grandson";
this.hobby="cat";
}
var inherit=(function () {
function F() {} //使用闭包产生私有函数,使每个子类继承的父类属性无引用关系
return function (father, son) {
F.prototype=father.prototype; //私有函数取出父类的原型
son.prototype=new F();
son.prototype.superClass=father; //子类的超类指向父类,子类通过this.superClass调用Father
son.prototype.constructor=son;
}
}())
inherit(Father, Son)
inherit(Son, Grandson)
var father=new Father('fatherMan')
var son=new Son('sonMan')
var grandson=new Grandson('grandsonMan')
console.log(son instanceof Father) //true
console.log(grandson instanceof Son) //true
console.log(grandson instanceof Father) //true
console.log(father.sex) //fatherMan
console.log(son.sex) //sonMan
console.log(grandson.sex) //grandsonMan
console.log(father.hobby) //fish
console.log(son.hobby) //dog
console.log(grandson.hobby) //cat
father.getName() //father
son.getName() //son
grandson.getName() //grandson
原文链接:https://blog.csdn.net/time_____/article/details/109525973?utm_medium=distribute.pc_category.none-task-blog-hot-5.nonecase&depth_1-utm_source=distribute.pc_category.none-task-blog-hot-5.nonecase
作者:DieHunter1024
出处:CSDN
记得刚开始学习编程时,我就在想:“Java和JavaScript是同一种语言吗?”。就是因为看到它们名称中都带“java”,所以才会误以为它们有关系。实际上,它们并没有太大的联系。
这两者的关系,就和英语与斯瓦希里语「非洲语言使用人口最多的语言之一,简称斯语」类似。两者都是语言,但是语法、用词甚至语音都完全不同。与英语和斯语相比,Java和JavaScript的区别其实更大。英语和斯语是大部分人日常互相交流沟通的语言。但是,java和JavaScript是计算机语言,具有不同的交流方式。
>>不同之处
1、命名
JavaScript是由Netscape公司设计实现而成的。JavaScript最初被称为Mocha,然后更名为LiveScript。Netscape公司与Sun公司合作,Netscape高层希望它看上去能够像Java,因此才取名为JavaScript。其实JavaScript走的一直是依靠大IP普及的营销策略,正如一开始我们所疑惑的地方一样,JavaScript就是依靠类似java的名称才被大众所熟知。就是靠着这一点,现在JavaScript已经是世界上第三流行的语言,并且人气还在不断上升。
Java是由Oracle公司(以前由Sun Microsystems)提供支持。而Java最初被称为Oak,然后更名为Green,后来才改成当前的名称Java。而java虽说是使用最广泛的语言之一,但近年来人气却在缓慢下降。
2、应用范围
Java具有极广的通用性,几乎在任何地方都可以使用;而JavaScript主要用于带有一些牵引服务器端「Node」,移动端「React Native」和桌面端「Electron」的前端Web开发。
3、语言特性
JavaScript是一种脚本语言,很多知名的浏览器都对Js有非常良好的本地支持,所以它成为了最受欢迎的前端语言之一;而Java是一种面向对象的高级编程语言,不适合作前端开发。
4、基于对象和面向对象
Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序。它是一种真正的面向对象(Object Oriented)的语言,即便是开发简单的程序,也必须设计对象。
JavaScript是一种网络脚本语言,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。它可以使网页具有交互性;并提供及时反馈节省用户时间;还可以根据用户的操作,动态的创建页面。它是一种基于对象(Object Based)和事件驱动(Event Driver)的编程语言。
5、解释和编译
Java是一种编译语言,即Java代码被转换为在语言虚拟机中执行字节码。Java的源代码在执行之前,必须经过编译。
JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行。(目前的浏览器几乎都使用了JIT(即时编译)技术来提升JavaScript的运行效率)
6、检测代码
Java是强类型的静态语言,每个变量必须预先指定其类型。JavaScript是弱类型的动态语言,其变量可以根据赋值而改变类型,如:var s=10;那么s为int型。JavaScript使用动态类型检查,即它是在执行JavaScript代码时检查变量的类型。这样做有一个好处就是可以使程序员更容易编码。而Java使用静态类型检查,即它是在编译时验证变量的类型。也就是说,它要检测的错误代码更少!
7、代码格式
JavaScript与Java代码格式不一样。JavaScript的代码是一种文本字符格式,可以直接嵌入HTML文档中,并且可动态装载。Java是一种与HTML无关的格式,必须通过像HTML中引用外媒体那样进行装载,其代码以字节代码的形式保存在独立的文档中,其独立文件的格式为*.class。
8、线程
JavaScript不支持多线程,因为浏览器中的JavaScript解释器是单线程的。而Java则支持多线程。
9、图文操作
Java可以直接对文本和图形进行操作。而JavaScript是通过在Web页面中与HTML元素组合来发挥作用的,但JaveScrit可以控制浏览器,让浏览器直接对文本和图形进行处理。
10.工作机会
Java比JavaScript有更多的工作机会。根据数据,在中国Java开发发布了21094个职位,而JavaScript开发只发布了8486个职位。相比较而言,Java更适合你寻找工作。
了解java和JavaScript的不同之处,其实并没有其他的意义,重要的是要通过清楚他们不同之处,明白什么时候更适合用JavaScript,而哪些情况下则使用java。
那么,什么时候使用JavaScript和Java?
举个例子来说,如何用java和JavaScript的方法实现让孩子跳跃的操作?
按Java的方法:因为孩子听不懂“跳”,所以你要在他大脑的部分区域插入了一个控制跳跃功能的电极装置。当电极冲击大脑时,他就会不由自主地跳动。机器可以将你的指令转化为脑信号,你只需要将其安装在他身上,不需要借助其他的东西,就可以控制他完成“跳跃”动作。
按JavaScript的方法:实现“跳跃”,其实只要教孩子如何跳跃。教完以后,当你说“跳”时,他便知道要开始跳了。所以在JavaScript中,主要的还是你需要教他如何理解“跳”一词。毕竟程序必须先知道如何解释命令才能执行。
回到我们的示例当中,除了本身无法在大脑中插入电极装置以外,将机器安装在人身上,让他遵循命令的行为是非常不可取的。而如果你教他理解命令,这样的话,下次他一听到这个命令,就能在没有其他东西辅助的情况下工作。
人是如此,计算机亦是。为什么一直在强调解释型的重要性,主要还是因为这样相比较而言更容易编写,但并不是所有时间都要使用JavaScript。
平日里遇到要用java或JavaScript进行编写时,我个人的建议是,JavaScript固然十分好用,但一定要是自律性很高的人才更适用,因为,当你需要维护混乱无规则的JavaScript代码时,就会发现,那简直是一场噩梦。所以,我还是建议你优先使用java来编写程序。因为,日常工作当中,你大可使用java编写不受限的程序浏览器。
凡事都有局限性,了解了java和JavaScript的不同之处,分清他们具体使用的时机,你就会更有效的完成手头工作。
好啦,关于java和JavaScript不同之处的介绍就到此结束了。感谢你的阅读!一味地在网络上寻求学习方式和工作技巧,是不足以静下心来完成学习和工作的。放下手机,着手开始执行你制定好的计划,相信自己一定会成功的。
者:诀九 前端名狮
转发链接:https://mp.weixin.qq.com/s/BMg8bFUwa4gmm6v2acAe7Q
*请认真填写需求信息,我们会在24小时内与您取得联系。