- 判断回文字符串
- 驼峰命名转下划线命名
- 箭头函数和普通函数区别
- rem原理
- js原型,js继承
- js链表,有什么特点,运用场景
- 原生网络请求是如何实现的
- 跟缓存相关的http请求头
- for in for of的区别
- instanceof和typeof的区别
判断回文字符串
方法一:字符串反转比较
const _isPalindrome = string => {
// 补全代码
string=string.split('')
let str1=string.reverse().join('')
if(str1==string) return true
else{
return false
}
}
这里有一个更省略的做法,就是我们可以不用join,然后利用==只比较值相等,那我只需要reverse就可以了。不需要最后的join,比较字符串和数组的值是否相等即可
方法二:左右指针
const _isPalindrome = string => {
// 补全代码
let left=0
let right=string.length-1
while(left<right){
if(string[left]===string[right]){
left++
right--
}else{
return false
}
}
return true
}
===和==的区别
- ===:严格相等,值和类型都必须一样
- ==相等,值一样就行
驼峰命名转下划线命名
方法一:正则匹配
function camelToUnderscore(str) {
return str.replace(/([A-Z])/g, "_$1").toLowerCase();
}
方法二:遍历数组,如果是大写字母,就将其转换成小写并在前面加上下划线
function camelToUnderscore(str) {
let result = '';
for (let i = 0; i < str.length; i++) {
const char = str[i];
if (char === char.toUpperCase()) {
result += '_' + char.toLowerCase();
} else {
result += char;
} }
return result;
}
下划线转驼峰: 方法一:分割字符串之后逐个转换
function cssStyle2DomStyle(sName) {
// 填写JavaScript
let arr1=sName.split('_').filter(item=>item)
let str=''
arr1.forEach((item,index)=>{
item=item[0].toUpperCase()+item.slice(1)
console.log(item)
str+=item
})
str=str[0].toLowerCase()+str.slice(1)
return str
}
.filter(item=>item)
可以过滤空值,因为在JavaScript中,空字符串、null、undefined等被视为假值(falsy values),因此当
filter
方法传入的函数返回假值时,该元素就会被过滤掉。
方法二:正则匹配,将-x转换成X,并判断第一个字母不大写
function cssStyle2DomStyle(sName) {
return sName.replace(/-([a-z])/g, function (match, letter,index) {
if(index==0) return letter
return letter.toUpperCase();
});
}
replace
str.replace(ext, function(match,letter,index,s){})
- 匹配到的字符串
- 回调函数返回替换的值,如果没有返回,默认为undefined
- 匹配字符串的对应索引位置
- 原始字符串
例如上述输出:
箭头函数和普通函数区别
- 语法:
- 箭头函数使用箭头
=>
来定义函数,语法简洁。例如:(x, y) => x + y
- 普通函数使用关键字
function
来定义函数,语法相对较长。例如:function(x, y) { return x + y; }
- this 的指向:
- 箭头函数没有自己的
this
,它会捕获所在上下文的this
值。换句话说,在箭头函数内部使用的this
是外层作用域的this
。- 普通函数有自己的
this
,其值取决于函数如何被调用。
window.url='00'
let a={ url:'11'}
function init(){
console.log(this.url)
}
init2=()=>{
console.log(this.url)
}
init()
a.init=init
a.init()
a.init2=init2
a.init2()
a.init2()
结果:可以看到箭头函数并没有打印和函数一样的结果,因为他没有自己的this,所以两次访问的都是外部window对象
- arguments 对象:
箭头函数没有自己的
arguments
对象,它会捕获所在上下文的arguments
值。
- 普通函数有自己的
arguments
对象,其中包含了传递给函数的参数。
arguments
对象是一个类数组对象,它包含了函数被调用时传递给函数的所有参数
- 构造函数:
- 箭头函数不能用作构造函数,不能使用
new
关键字来调用。- 普通函数可以用作构造函数,可以使用
new
关键字来创建实例对象。
为什么
- 没有自己的 this 绑定:因为构造函数当中我们期望this指向新创建的对象,但是箭头函数没有自己的this
- 没有prototype:就无法被用于创建基于原型的继承关系
函数对象的一些属性
- caller
用于访问调用当前函数的函数。它是一个非标准属性,不建议在生产代码中使用,因为它已经被废弃,并且在严格模式下会导致错误。
- new.target
用于检查函数是否使用new关键字调用new.target,是就引用这个函数
function Foo() {
if (!new.target) throw "Foo() must be called with new";
console.log("Foo instantiated with new");
}
Foo(); // throws "Foo() must be called with new"
new Foo(); // logs "Foo instantiated with new"
rem原理
- 相对于根元素字体大小的单位
- 如果根元素的字体大小是16px,1rem就等于16px;如果根元素的字体大小改变为20px,1rem也会相应地变为20px
js原型,js继承
构造函数、原型、实例对象的关系
每一个构造函数都有一个原型对象,原型有一个属性指回构造函数,实例也有一个内部指针指向原型
原型链
如下,我们创建了一个Person的构造函数,我们说只要是构造函数就有原型对象,并且我们创建了一个对象实例,那么只要是对象就有_proto_,通过_proto_牵线我们就可以使用原型上的一些方法,但是如果原型找不到,他不会就此停止,因为我们说原型也是一个对象,他也有_proto_指向他的原型对象,就这么一直寻找直至最后返回null,这样一层一层形成链式结构就称为原型链
js继承
原型继承
比如我们创建了一个数组对象,那么这个数组对象实例就可以继承数组原型上一些方法,所以我们才能够没有写这些方法但是可以使用这些方法,因为这些方法都是原型上有的方法
构造继承
构造函数来创建对象,并且可以在构造函数的原型对象上定义方法和属性,以便所有由该构造函数创建的对象都可以共享这些方法和属性。
// 使用构造函数和原型实现继承
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}.`);
};
function Student(name, grade) {
//调用Person这个构造函数
Person.call(this, name);
this.grade = grade;
}
//建一个新的对象,该对象的原型指向 Person.prototype。
//这意味着 Student.prototype 对象可以访问 Person.prototype 对象中定义的属性和方法。
//通过这种方式,Student 对象可以继承 Person 对象的属性和方法。
Student.prototype = Object.create(Person.prototype);
//将 Student 构造函数重新指向 Student.prototype。
//因为在前一步中我们将 Student.prototype 设置为 Object.create(Person.prototype),
//这会导致 Student.prototype.constructor 指向 Person 构造函数。
//通过将它重新指向 Student 构造函数,我们可以确保构造新对象时使用正确的构造函数。
Student.prototype.constructor = Student;
Student.prototype.sayGrade = function() {
console.log(`I am in grade ${this.grade}.`);
};
let stu=new Student('梨花',100);
stu.sayHello()
打印结果:
类继承
extends
// 使用 ES6 中的类和继承
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, my name is ${this.name}.`);
}
}
class Student extends Person {
constructor(name, grade) {
super(name);
this.grade = grade;
}
sayGrade() {
console.log(`I am in grade ${this.grade}.`);
}
}
js链表,有什么特点,运用场景
特点:
- 非连续存储: 链表中的元素在内存中不是连续存储的,而是通过指针相互连接起来的。
- 动态大小: 链表在创建时不需要预先指定大小,可以根据需要动态增加或删除元素。
- 插入和删除高效: 由于链表中的元素不需要连续存储,因此在插入和删除元素时,不需要像数组那样移动其他元素,所以操作效率较高。
- 访问速度较慢: 相对于数组,链表的访问速度较慢,因为访问链表中的任何一个元素都需要从头开始逐个遍历。
应用场景:动态内存分配、动态数据集合
原生网络请求是如何实现的
XMLHeepRequest
- 声明new XMLHttpRequest
- onreadystatechange
- readySate
- open
//创建对象
xmlhttp=new XMLHttpRequest();
//发送
xmlhttp.open("GET","url",async(true,false));
xmlhttp.send();
xmlhttp.open("GET","/try/ajax/demo_get2.php?fname=Henry&lname=Ford",true);
xmlhttp.send();
//如果需要像 HTML 表单那样 POST 数据
//请使用 setRequestHeader() 来添加 HTTP 头。
//然后在 send() 方法中规定您希望发送的数据:
//通过调用`setRequestHeader`方法设置`Content-type`请求头的目的是告诉服务器发送的数据的格式和类型。
xmlhttp.open("POST","/try/ajax/demo_post2.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Henry&lname=Ford");
//接收json
//事件绑定
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
// console.log(xhr.response);
// result.innerHTML = xhr.response;
// 1. 手动对数据转化
let data = JSON.parse(xhr.response);
// 2. 自动转换,先设置xhr.responseType='json'
console.log(xhr.response);
result.innerHTML = xhr.response.name;
}
}
}
Fetch
fetch('https://api.example.com/data')
.then(function(response) {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(function(data) {
// 对响应数据进行处理
console.log(data);
})
.catch(function(error) {
// 处理请求过程中的错误
console.log('Fetch error: ', error);
});
跟缓存相关的http请求头
- If-None-Match: 用于条件请求,客户端可以在请求中发送之前获取到的实体标签(ETag),服务器会根据这个值判断资源是否有更新,如果没有更新,服务器会返回 304 Not Modified 状态码,告知客户端使用本地缓存。
- If-Modified-Since: 也是用于条件请求,客户端可以在请求中发送之前获取到的资源的最后修改时间,服务器会根据这个值判断资源是否有更新,如果没有更新,服务器会返回 304 Not Modified 状态码,告知客户端使用本地缓存。
- Cache-Control: 用于控制缓存的行为,例如指示客户端是否可以缓存响应、缓存的有效期等。
- Pragma: 虽然已经被 Cache-Control 取代,但仍然有一些旧的客户端和服务器会使用该头部来控制缓存行为。
for in for of的区别
for in
适用于遍历对象的可枚举属性
const obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
console.log(key); // 输出 a, b, c
console.log(obj[key]); // 输出 1, 2, 3
}
for of
适用于遍历可迭代对象的元素,例如数组、字符串、Map、Set 等。
const arr = [1, 2, 3];
for (let value of arr) {
console.log(value); // 输出 1, 2, 3
}
instanceof和typeof的区别
typeof
typeof
是一个一元操作符,通常用于检查给定变量的数据类型。- 返回一个表示变量类型的字符串,可能的结果包括
"undefined"
、"boolean"
、"number"
、"string"
、"object"
、"function"
和"symbol"
,以及 ES6 新增的"bigint"
。
typeof 42; // 返回 "number"
typeof "hello"; // 返回 "string"
typeof true; // 返回 "boolean"
typeof undefined; // 返回 "undefined"
typeof null; // 返回 "object",这是 typeof 的一个潜在的缺陷
typeof {}; // 返回 "object"
typeof []; // 返回 "object"
typeof function(){}; // 返回 "function"
instanceof
instanceof
是用于**检查对象是否属于某个类(构造函数)**的二元操作符。- 如果对象是指定类(构造函数)或其子类的实例,则返回
true
,否则返回false
。
class Animal {}
class Dog extends Animal {}
const animal = new Animal();
const dog = new Dog();
console.log(animal instanceof Animal); // 返回 true
console.log(dog instanceof Dog); // 返回 true
console.log(dog instanceof Animal); // 返回 true,因为 Dog 是 Animal 的子类