随时记|生疏的前端知识点_JS(二)

解决遍历对象时,把原型上的属性遍历出来了怎么办?

使用hasOwnProperty判断

function Person(name) {
	this.name = name;
};
Person.prototype.age = 23;
const person = new Person('Katrina');
for (const key in person) {
	console.log(key)  // name age
};

for (const key in person) {
	person.hasOwnProperty(key) && console.log(key);   // name
}

valueOf 与 toString?

  • toString( ):返回对象的字符串表示。
  • valueOf( ):返回对象的字符串、数值或布尔值表示
  • valueOf比较偏向于计算,toString偏向于显示
  • 对象转换时,优先调用toString
  • 强转字符串时优先调用toString,强转数字时优先调用valueOf
  • 正常情况下,优先调用toString
  • 运算操作符情况下优先调用valueOf
    在这里插入图片描述

JavaScript变量在内存中具体存储形式?

基本数据类型:存在栈内存里
引用数据类型:指针存栈内存,指向堆内存中一块地址,内容存在堆内存中
也有说法说其实JavaScript所有数据都存堆内存中,我也比较赞同这种说法

讲一讲JavaScript的装箱和拆箱?

装箱:把基本数据类型转化为对应的引用数据类型的操作

看以下代码,s1只是一个基本数据类型,他是怎么能调用indexOf的呢?

const s1 = 'Katrinasayhello'
const index = s1.indexOf('t')
console.log(index) // 2

原来是JavaScript内部进行了装箱操作
1、创建String类型的一个实例
2、在实例上调用指定的方法
3、销毁这个实例

var temp = new String('Katrinasayhello');
const index = temp.indexOf('t');
temp = null;
console.log(index)   // 2

拆箱:将引用数据类型转化为对应的基本数据类型的操作

通过valueOf或者toString方法实现拆箱操作

var objNum = new Number(123);  
var objStr =new String("123");   
console.log( typeof objNum ); //object
console.log( typeof objStr ); //object 
console.log( typeof objNum.valueOf() ); //number
console.log( typeof objStr.valueOf() ); //string

console.log( typeof objNum.toString() ); // string 
console.log( typeof objStr.toString() ); // string

[] == ![] 为什么是 true ?

[] 转为Boolean是true,所以不能通过if ([]) 来判断数组为空,需要用[].length

  • 转为[] == false
  • 转为[] == 0
  • 转为'' == 0
  • 转为0 == 0

0.1 + 0.2 === 0.3,对吗?

不对,JavaScript存在精度丢失问题,由于有些小数无法用二进制表示,所以只能取近似值,解决方法有:

  • 先转大数,再变小数
  • 使用toFixed

什么是匿名函数?

匿名函数就是没有名字的函数

(function(x,y){
	alert(x + y)
})(2,3)

绑定点击事件有几种方式?

  • xxx.onclick = function (){}
  • <xxx onclick=""></xxx>
  • xxx.addEventListener('click', function(){}, false)

addEventListener的第三个参数是干嘛的?

决定事件是捕获阶段执行还是冒泡阶段执行

  • true:捕获
  • false: 默认,冒泡

JavaScript的事件流模型有哪些?

  • 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
  • 目标阶段(Target phase)—— 事件到达目标元素。
  • 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡
    下面是在表格中点击 的图片,摘自规范:
    在这里插入图片描述
    也就是说:点击 ,事件首先通过祖先链向下到达元素(捕获阶段),然后到达目标(目标阶段),最后上升(冒泡阶段),在途中调用处理程序
    参考:事件冒泡与捕获

什么是事件委托?

当子元素都需要绑定相同事件时,可以将事件绑在父元素上,优点有:

  • 绑定在父元素,则只需绑定一次,节省性能
  • 后续新增的子元素也可以触发父元素绑定的事件

如何实现数组去重?

map

let arr = [1,2,3,2,3,4];
function quchong1(arr) {
  const newArr = []
  arr.reduce((pre, next) => {
    if (!pre.get(next)) {
      pre.set(next, 1)
      newArr.push(next)
    }
    return pre
  }, new Map())
  return newArr
}

quchong1(arr)

set

let arr = [1,2,3,2,3,4];

console.log([...new Set(arr)]);

Set与Array的区别是什么?

  • Set使用has判断有无元素,数组使用索引
  • Set添加元素使用方法add,数组用push、unshift
  • Set长度为size,数组为length
  • Set会自动把同样的基础数据类型去重,数组不能
  • Set删除元素用delete,数组用splice、pop、shift
  • Set可以使用clear清空,数组需要重新赋值[]
  • 数组可以传入new Set(array),实现数组转Set
  • Set可以使用keys、value方法,转数组
  • Set自带forEach方法进行遍历

Map与Object的区别是什么?

  • Map使用set设置属性,对象使用obj[key] = value
  • Map使用get获取属性值,对象使用obj[key]
  • Map使用has判断属性存在与否,对象只能obj[key]
  • Map删除元素使用delete方法,对象使用delete关键字
  • Map使用clear进行情空,对象需要重新赋值{}
  • Map和对象都可以使用entries方法转数组键值对
  • Map自带forEach方法进行遍历

JavaScript继承方式有几种?

看下面这个例子:

// 定义一个动物类
function Animal (name) {
    // 属性
    this.name = name || 'Animal';
    // 实例方法
    this.sleep = function(){
      console.log(this.name + '正在睡觉!');
    }
  }
  
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};

1. 原型链继承

核心:将父类的实例作为子类的原型

function Cat(){ 
}

Cat.prototype = new Animal();  // Cat的原型是Animal构造函数
Cat.prototype.name = 'cat';    // 并且指定name为cat

var cat = new Cat();    // 创建cat的实例对象
console.log(cat.name); // cat
cat.eat('fish') // cat正在吃:fish
cat.sleep() // cat正在睡觉!
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

优点:
1、非常纯粹的继承关系,实例是子类的实例,也是父类的实例
2、父类新增原型方法/属性,子类都能访问到
3、简单,易于实现 缺点:
1、要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放构造器中
2、来自原型对象的所有属性被所有实例共享
3、创建子实例时,无法向父类构造函数传参
4、不支持多继承

2. 构造继承

核心:使用父类的构造器来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

function Cat(name) {
  Animal.call(this);
  this.name = name || 'Tom';
}

var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡觉!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

优点:
1、解决了原型链继承中,子类实例共享父类引用属性的问题
2、创建子类实例时,可以向父类传递参数
3、可以实现多继承(call多个父类对象) 缺点:
1、实例并不是父类的实例,知识子类的实例
2、是能继承父类的实例属性和方法,不能继承原型属性/方法
3、无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3. 实例继承

核心:为父类实例添加新特性,作为子类实例返回

function Cat(name){
  var instance = new Animal();
  instance.name = name || 'Tom';
  return instance;
}

var cat = new Cat();
console.log(cat.name) // Tom
cat.sleep() // Tom正在睡觉!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

优点:
1、不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同效果 缺点:
1、实例是父类的实例,不是子类的实例
2、不支持多继承

4. 拷贝继承

核心:就一个一个拷贝

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  this.name = name || 'Tom';
}

var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡觉!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

优点:
1、支持多继承 缺点:
1、效率低,内存占用高(因为要拷贝父类的属性)
2、无法获取父类不可枚举方法(不可枚举方法,不能使用for in访问到)

5、组合继承

核心:通过父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡觉!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

优点:
1、弥补了构造继承的缺陷,可以继承实例属性/方法,也可继承原型属性/方法
2、既是子类的实例,也是父类的实例
3、不存在引用属性共享问题
4、可传参
5、函数可复用
缺点:
1、调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

6、寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造时,就不会初始化两次实例方法/属性,避免继承组合的缺点

function Cat(name) {
  Animal.call(this);
  this.name = name || 'Tom';
}
// 创建一个没有实例方法的类
var Super = function () { };
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();

// Test Code
var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡觉!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

优点:
1、堪称完美
缺点:
1、实现复杂

BOM 和 DOM 的关系

  • BOM全称Browser Object Model,即浏览器对象模型,主要处理浏览器窗口和框架
  • DOM全称Document Object Model,即文档对象模型,是 HTML 和XML 的应用程序接口(API),遵循W3C 的标准,所有浏览器公共遵守的标准
  • JS是通过访问BOM(Browser Object Model)对象来访问、控制、修改客户端(浏览器),由于BOM的window包含了document,window对象的属性和方法是直接可以使用而且被感知的,因此可以直接使用window对象的document属性,通过document属性就可以访问、检索、修改XHTML文档内容与结构。因为document对象又是DOM的根节点
  • 可以说,BOM包含了DOM(对象),浏览器提供出来给予访问的是BOM对象,从BOM对象再访问到DOM对象,从而js可以操作浏览器以及浏览器读取到的文档

substr() 和 substring

substr() 函数的形式为substr(startIndex,length)。它从startIndex返回子字符串并返回’length’个字符数
substring() 函数的形式为substring(startIndex,endIndex)。它返回从startIndex到endIndex - 1的子字符串

var s = "hello";
console.log(s.substr(1,4))  // ello

var s = "hello";
console.log(s.substring(1,4))  // ell
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值