js基础知识点及常考知识点(一)

原始(Primitive)类型

涉及面试题:原始类型有哪几种?null 是对象嘛?

在js中,存在着6中原始值,分别是:

  • boolean
  • null
  • undefind
  • number
  • string
  • symbol(如果不懂symbol的,可以来这里看看)
    首先原始类型存储的值是没有函数可以调用的,例如undefind.toString()
    在这里插入图片描述
    此时,你一定有疑问,'1'.toString()是可以使用的.其实这种情况下'1'已经不是原始类型了,而是被强制转成了String类型,也就是对象类型,所以可以调用toString函数.
    (此处插播一条短消息,JS中String与string的区别String是构造函数,而"string"是变量的一种类型.)
typeof String     // "function"
typeof string     // "undefined"
typeof "string"   // "string"

除了会在必要的情况下强转类型以外,原始类型还有一些坑。
最为明显的就是js的0.1 + 0.2 !== 0.3的精度小数问题了.
另外对与null来说,很多人会认为他是个对象类型,其实他是错误的,虽然typeof null会输出Object,但是这只是JS存在的历史悠久BUG.在JS的最初版本中使用的是32位系统,为了性能考虑,使用低频存储变量的类型信息,000开头表示对象,然而null表示为全零,所以他错误的判断为Object.虽然现在内部类型判断代码已经改变了,但是这个bug却一直流传了下来.

对象Object)类型

涉及面试题:对象类型和原始类型的不同之处?函数参数是对象会发生什么问题?
在JS中除了,除了原始类型,其他就是对象类型了.对象类型和原始类型不同的是,原始类型存储的是值,对象类型存储的是地址(指针),当你创建了一个对象类型的时候,内存会开辟一个空间来存放值,但是我们需要找到这个空间,这个空间会拥有一个地址(指针).

const a = []

对于常量a来说,假设内存地址为#001,那么在地址(指针)#001上存放了值[],常量a存放了地址(指针)#001,再看下面的代码:

const a = []
const b = a
b.push(1)

当我们将变量赋值给另一个变量时,其实赋予的是原本变量的地址(指针),也就是说变量b存放的地址(指针)是#001,所以我们进行数据修改时,修改的是地址(指针)#001下面的值,因而地址的值改变了,所以两个变量的值都发生了变化.

console.log(a) ---[1]
console.log(b) --[1]

接下来我们看函数参数是对象的变化情况

function test(person) {
  person.age = 26
  person = {
    name: 'yyy',
    age: 30
  }

  return person
}
const p1 = {
  name: 'yck',
  age: 25
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?

对于以上代码:

  • 首先,函数传参是传递对象的副本.
  • 到函数内部修改参数的属性这步,我相信大家都知道了p1的值被改变了
  • 但是我们重新为person分配了一个对象时就出现了分歧,请看下图
    在这里插入图片描述
    所以最后person拥有了一个新的地址(指针),也就和p1没什么关系了,导致了最终两个变量是不同的.归根结底,就是在函数内person的地址被改变了,导致值被改变了(this指向).

typeof vs instanceof

涉及面试题:typeof 是否能正确判断类型?instanceof 能正确判断对象的原理是什么?
typeof对于原始类型来说,除了null都可以正确显示类型

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'

typeof对于对象来说,除了函数都会显示object,所以说typeof并不能准确判断变量到底是什么类型.
如果我们想判断一个对象的准确类型,这时候可以用instanceof,因为内部机制是通过原型链来判断的.

const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true

var str = 'hello world'
str instanceof String // false

var str1 = new String('hello world')
str1 instanceof String // true

对于原始类型来说,你想直接通过 instanceof 来判断类型是不行的,当然我们还是有办法让 instanceof 判断原始类型的

class PrimitiveString {
  static [Symbol.hasInstance](x) {
    return typeof x === 'string'
  }
}
console.log('hello world' instanceof PrimitiveString) // true

你可能不知道Symbol.hasInstance是什么,其实就是自定义一个instanceof行为的东西,以上这段代码,就等同于 typeof 'hello world' === 'string',所以结果自然就是true了

类型转换

涉及面试题:该知识点常在笔试题中见到,熟悉了转换规则就不惧怕此类题目了
在js转化类型中,基本为

  • 转化为布尔值
  • 转化为数字
  • 转化为字符串

转化类型大致表格如下:
生活

转Boolean

在条件判断时,除了undefined、null、0、-0、false、NaN,其他所有值都会为true,包括所有对象.

对象转原始类型

对象在转原始类型时会调用内置的[[ToPrimitive]]函数,对于该函数来说,算法逻辑来说一般如下:

  • 如果已经是原始类型了,就不需要转化了
  • 调用x.indexOf()方法,如果转换为基本类型,就返回转换的值.
  • 调用x.toString()方法,如果转化为基本类型,就返回转换的值.
    当然你也可以重写Symbol.toPrimitive,该方法在转换原始类型时优先级最高
lat a = {
	valueOf(){
		return 1
	},
	toString(){
		 return '1'
	},
	[Symbol.toPrimitive](){
		return 2
	}
}
1 + a = // =>3

四则运算符

加法运算符不同于其他运算符,具备以下特点:

  • 运算中有一方是字符串就会把另一方也转换为字符串
  • 如果一方不是字符串或是数字,会把他转化成数字或字符串
1 + ‘1’ // 11
true + true // 2
4 + [1,2,3] // 41,2,3

如果你对答案有疑问的?,请看下面解释:

  • 第一行触发特点一,将左侧数字转化成字符串,故字符串进行拼接,得到答案11
  • 第二行触发特点二,将两侧布尔值转换为数字true => 1,故得到答案1
  • 第三行触发特点二,稍加理解(字符串=> 数字, 数字=>字符串),将数组包含的数字,调用数组的toString方法转换为字符串,'4' + '1,2,3' // => 41,2,3

对于加法还需要注意 这类表达式 'a' + + 'b' // => 'aNaN'
首先我们先执行+ 'b',尝试把字符串'b'转换成数字,结果失败了,转化不了真实的数字,返回NaN,所以得到答案aNaN
那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字

4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN

this

涉及面试题:如何正确判断 this?箭头函数的 this 是什么

普通函数
function foo() {
  console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo: foo
}
obj.foo()

const c = new foo()

简单对上面例子进行分析,

  • 对于直接调用foo()来说,无论在何处调用,this永远指向window.
  • 对于obj.foo(),我们只需要记住谁调用了函数,谁就是this,(例1,foo() = window.foo())
  • 对于new来说(js继承),this永远被绑定在了c上面,不会别任何地方改变.
箭头函数
function a() {
  return () => {
    return () => {
      console.log(this)
    }
  }
}
console.log(a()()())

对于箭头函数来说,是没有this指向的,this永远指向外层的this,所以包裹箭头函数的a()函数的this就是函数内部的this,此处指向window,另外对箭头函数使用bind这类函数是无效的

call apply bind
call apply

在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。

function fruits() {}
 
fruits.prototype = {
    color: "red",
    say: function() {
        console.log("My color is " + this.color);
    }
}
 
var apple = new fruits;
apple.say();    //My color is red

但是如果我们有一个对象banana= {color : “yellow”} ,我们不想对它重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法:

banana = {
    color: "yellow"
}
apple.say.call(banana);     //My color is yellow
apple.say.apply(banana);    //My color is yellow

所以,可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 object 没有某个方法(本栗子中banana没有say方法),但是其他的有(本栗子中apple有say方法),我们可以借助call或apply用其它对象的方法来操作。
apply和call的区别:
对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。例如,有一个函数定义如下:

var func = function(arg1, arg2) {
     
};
调用如下:
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])

获取数组中的最大值和最小值

var  numbers = [5, 458 , 120 , -215 ]; 
var maxInNumbers = Math.max.apply(Math, numbers),   //458
    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。

bind
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
bar(); // undefined
var func = bar.bind(foo);
func(); // 3

这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值