标签:执行顺序 react 语句 针对 乱序 封装 exp asc 表示
字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
对象(Object)、数组(Array)、函数(Function)。
对象(Object)。
注:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
String Number Boolean Array Object
Function Math Date Error Arguments RegExp
是由ECMAScript规范定义的JavaScript内置对象,如 String Number Boolean Array Object Function Math Date Error Arguments RegExp等。
是由运行时的环境(浏览器或node)决定的,如window、XMLHTTPRequest等。
typeof null === ‘object‘ // true
typeof undefined === ‘undefined‘ // true
12 == ‘12‘ // true
true == 1 // true
false == ‘0‘ // true
12 === ‘12‘ // false
12 === 12 // true
true === 1 // false
false === ‘0‘ // false
JS在使用运算符号或者对比符时,会自带隐式转换,规则如下:
-、*、/、% :一律转换成数值后计算
+:
数字 + 字符串 = 字符串, 运算顺序是从左到右
数字 + 对象, 优先调用对象的valueOf -> toString
数字 + boolean/null -> 数字
数字 + undefined -> NaN
[1].toString() === ‘1‘
{}.toString() === ‘[object object]‘
NaN !== NaN 、+undefined 为 NaN
"Attribute"是在HTML中定义的,而"property"是在DOM上定义的。为了说明区别,假设我们在HTML中有一个文本框:
<input type="text" value="Hello">
const input = document.querySelector(‘input‘);
console.log(input.getAttribute(‘value‘)); // Hello
console.log(input.value); // Hello
但是在文本框中键入“ World!”后:
console.log(input.getAttribute(‘value‘)); // Hello
console.log(input.value); // Hello World!
定义: 全局属性 NaN 的值表示不是一个数字(Not-A-Number) 如何判断一个值是否是NaN: 等号运算符(== 和 ===) 不能被用来判断一个值是否是 NaN。必须使用 Number.isNaN() 或 isNaN() 函数。
NaN === NaN; // false
Number.NaN === NaN; // false
isNaN(NaN); // true
isNaN(Number.NaN); // true
需要考虑三个问题:
检查对象的“值相等”的一个强大的方法,最好是依靠完善的测试库,涵盖了各种边界情况。Underscore和Lo-Dash有一个名为_.isEqual()方法,用来比较好的处理深度对象的比较。您可以使用它们像这样:
// Outputs: true
console.log(_.isEqual(obj1, obj2));
‘use strict‘ 是用于对整个脚本或单个函数启用严格模式的语句。严格模式是可选择的一个限制 JavaScript 的变体一种方式 。
总的来说,我认为利大于弊,我从来不使用严格模式禁用的功能,因此我推荐使用严格模式。
.call和.apply都用于调用函数,第一个参数将用作函数内 this 的值。然而,.call接受逗号分隔的参数作为后面的参数,而.apply接受一个参数数组作为后面的参数。一个简单的记忆方法是,从call中的 C 联想到逗号分隔(comma-separated),从apply中的 A 联想到数组(array)。
function add(a, b) {
return a + b;
}
console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3
.call和.apply是立即执行的, .bind
返回函数的副本,但带有绑定上下文!它不是立即执行的。
const person = { name: ‘Lydia‘ }
function sayHi(age) {
console.log(`${this.name} is ${age}`)
}
sayHi.call(person, 21)
sayHi.bind(person, 21)
结果: Lydia is 21 function
ƒ sayHi(age) {
console.log(`${this.name} is ${age}`)
}
bind()方法创建一个新的函数, 当被调用时,将其 this 关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
根据我的经验,将this的值绑定到想要传递给其他函数的类的方法中是非常有用的。在 React 组件中经常这样做。
var arr = [];
if (Array.isArray(arr) && arr.length === 0) {
console.log(‘是空数组‘);
}
// Array.isArray是ES5提供的,如果不支持。用下面的方案。
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === ‘[object Array]‘;
};
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.sort(function () {
return Math.random() - 0.5;
});
// flat: [1,[2,3]] --> [1, 2, 3]
Array.prototype.flat = function() {
return this.toString().split(‘,‘).map(item => +item )
}
以上4种操作均会改变数组本身
map用法:
let array = [1, 2, 3, 4, 5];
let newArray = array.map((item, i, arr) => {
return item * 2;
});
console.log("array:", array); // [1, 2, 3, 4, 5]
console.log("newArray:", newArray); // [2, 4, 6, 8, 10]
// 此处的array接受map方法运算之后的返回值
// 但是map方法并不能改变原来的数组
forEach用法:
let array = [1, 2, 3, 4, 5];
let newArray = array.forEach((item, i, arr) => {
console.log(‘item:‘ + item + ‘, index:‘ + i);
// array[i] = item * 2; // 可以用这种方式改变原始数组的值
});
console.log("array:", array); // [1, 2, 3, 4, 5]
console.log("newArray:", newArray); // undefined
// forEach方法没有返回值
各种循环遍历的比较地址:https://blog.csdn.net/qq_41899174/article/details/82797089
https://segmentfault.com/a/1190000020389596
Object?.prototype?.has?OwnProperty()
详情解释地址:https://www.jianshu.com/p/5dc26e47fe9a
Array.prototype.slice.call(arguments)
[].slice.call(arguments)
更多用法详情地址:https://www.jianshu.com/p/a8354475016c
for (let property in obj) {
console.log(property);
}
但是,这还会遍历到它的继承属性,在使用之前,你需要加入obj.hasOwnProperty(property)检查。
Object.keys(obj).forEach((property) => { ... })
Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组。
Object.getOwnPropertyNames(obj).forEach((property) => { ... })
Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。
for (let i = 0; i < arr.length; i++) { ... }
arr.forEach((item, index, arr) { ... })
arr.map((item, index, arr) => { ... })
匿名函数可以在 IIFE 中使用,来封装局部作用域内的代码,以便其声明的变量不会暴露到全局作用域。
(function() {
// 一些代码。
})();
匿名函数可以作为只用一次,不需要在其他地方使用的回调函数。当处理函数在调用它们的程序内部被定义时,代码具有更好地自闭性和可读性,可以省去寻找该处理函数的函数体位置的麻烦。
setTimeout(function() {
console.log(‘Hello world!‘);
}, 1000);
匿名函数可以用于函数式编程或 Lodash(类似于回调函数)。
const arr = [1, 2, 3];
const double = arr.map(function(el) {
return el * 2;
});
console.log(double); // [2, 4, 6]
IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
(function () {
statements
})();
这是一个被称为 自执行匿名函数 的设计模式,主要包含两部分。第一部分是包围在 圆括号运算符 () 里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。
第二部分再一次使用 () 创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。
详细讲解地址:https://blog.csdn.net/cuishizun/article/details/81672371
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完成加载。
window的load事件仅在 DOM 和所有相关资源全部完成加载后才会触发。
详细讲解地址:https://blog.csdn.net/weixin_40387601/article/details/80500235
下面将对如下数据进行判断它们的类型
var bool = true
var num = 1
var str = ‘abc‘
var und = undefined
var nul = null
var arr = [1, 2, 3]
var obj = {a: ‘aa‘, b: ‘bb‘}
var fun = function() {console.log(‘I am a function‘)}
console.log(typeof bool); // boolean
console.log(typeof num); // number
console.log(typeof str); // string
console.log(typeof und); // undefined
console.log(typeof nul); // object
console.log(typeof arr); // object
console.log(typeof obj); // object
console.log(typeof fun); // function
由结果可知typeof可以测试出number、string、boolean、undefined及function,而对于null及数组、对象,typeof均检测出为object,不能进一步判断它们的类型。
obj instanceof Object: 左操作数是一个对象,右操作数是一个函数构造器或者函数对象,判断左边的操作数的原型链_proto_属性是否有右边这个函数对象的proptotype属性。
console.log(bool instanceof Boolean);// false
console.log(num instanceof Number); // false
console.log(str instanceof String); // false
console.log(und instanceof Object); // false
console.log(arr instanceof Array); // true
console.log(nul instanceof Object); // false
console.log(obj instanceof Object); // true
console.log(fun instanceof Function);// true
var bool2 = new Boolean()
console.log(bool2 instanceof Boolean);// true
var num2 = new Number()
console.log(num2 instanceof Number);// true
var str2 = new String()
console.log(str2 instanceof String);// true
function Animation(){}
var ani = new Animation()
console.log(ani instanceof Animation);// true
function Dog(){}
Dog.prototype = new Animation()
var dog = new Dog()
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animation);// true
console.log(dog instanceof Object); // true
从结果中看出instanceof不能区别undefined和null,而且对于基本类型如果不是用new声明的则也测试不出来,对于是使用new声明的类型,它还可以检测出多层继承关系。
console.log(bool.constructor === Boolean); // true
console.log(num.constructor === Number); // true
console.log(str.constructor === String); // true
console.log(arr.constructor === Array); // true
console.log(obj.constructor === Object); // true
console.log(fun.constructor === Function); // true
console.log(ani.constructor === Animation); // true
console.log(dog.constructor === Dog); // false
console.log(dog.constructor === Animation);// true
null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失。所以dog.constructor === Animation 而不是 Dog
console.log(Object.prototype.toString.call(bool)); //[object Boolean]
console.log(Object.prototype.toString.call(num)); //[object Number]
console.log(Object.prototype.toString.call(str)); //[object String]
console.log(Object.prototype.toString.call(und)); //[object Undefined]
console.log(Object.prototype.toString.call(nul)); //[object Null]
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(obj)); //[object Object]
console.log(Object.prototype.toString.call(fun)); //[object Function]
console.log(Object.prototype.toString.call(dog)); //[object Object]
原理(摘自高级程序设计3):在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。 但是它不能检测非原生构造函数的构造函数名。
console.log($.type(bool)); //boolean
console.log($.type(num)); //number
console.log($.type(str)); //string
console.log($.type(und)); //undefined
console.log($.type(nul)); //null
console.log($.type(arr)); //array
console.log($.type(obj)); //object
console.log($.type(fun)); //function
console.log($.type(dog)); //object
$.type()内部原理就是用的Object.prototype.toString.call()
let element = document.createElement("div"); // 创建元素
body.appendChild(element); // 将一个节点添加到指定父节点的子节点列表末尾
var oldChild = node.removeChild(child); // 删除子元素
ChildNode.remove() // 删除元素
Node.innerText // 修改元素文本内容
Element.innerHTML // 设置或获取描述元素后代的HTML语句
Document.getElementById() // 返回对拥有指定 id 的第一个对象的引用
Document.querySelector() // 返回文档中匹配指定的CSS选择器的第一元素
Document.querySelectorAll() // 返回与指定的选择器组匹配的文档中的元素列表
更多操作详见:https://www.jianshu.com/p/b0aa846f4dcc
浏览器下载除JS外的资源时,会并行下载,以提高性能。但下载JS脚本时,会禁止并行下载(称为脚本阻塞Scripts Block Downloads)。浏览器遇到JS时,必须等JS下载,解析,执行完后,才能继续并行下载下一个资源。原因是JS可能会改变页面或改变JS间的依赖关系,例如A.js中用document.write改变页面,B.js依赖于A.js。因此要严格保证顺序,不能并行下载。
由于浏览器在遇到<body>标签前是不会渲染页面的,为了避免白屏,通常的建议是将JS放到标签底下,可以有最佳的用户体验。
按推荐度排序:
var script = document.createElement(‘script‘); // 创建script标签
script.type = "text/javascript";
script.src = "A.js";
document.getElementsByTagName(‘head‘)[0].appendChild(script); // 塞进页面
先用document.createElement(‘script’)生成一个script标签,再设置它的src属性,最后将其插入到<head>中。
script标签被插入到页面的DOM树后,就会开始下载src属性指定的脚本。而且通过动态脚本元素下载脚本是异步的,不会阻塞页面的其他下载和处理过程,因此script标签插入<head>中也没问题。
<script type="text/javascript" src="A.js" async></script>
浏览器解析到HTML里的该行script标签,发现指定为async,会异步下载解析执行脚本。
async 是HTML5里为script标签新增的属性,对于低版本浏览器会存在兼容性问题。
它会在下载完成后立刻执行,而不是会等到DOM加载完成之后再执行,所以还是有可能会造成阻塞。
这种方式只适用于引用外部js文件的<script>标签。
添加async属性的js文件不应该使用document.write方法。
对多个带有async的js文件,它不能保证按顺序执行,它是哪个js文件先下载完就先执行哪个。
<script type="text/javascript" src="A.js" defer></script>
浏览器解析到HTML里的该行script标签,发现指定为defer,会暂缓下载解析执行脚本。而是等到页面加载完毕后,才加载脚本(更精确地说,是在DOM树构建完成后,在window.onload触发前,加载defer的脚本)。
defer也是只适用于外部js文件,也不能在js中使用document.write方法。
可以保证多个js文件的执行顺序就是它们在页面中出现的顺序。
document.write会重绘整个页面,如果不指定元素的话,它会覆盖掉整个页面内容。
innerHTML只会重绘页面的一部分。
IE只支持事件冒泡,火狐同时支持事件捕获和事件冒泡两种。
阻止事件冒泡的方式不同
JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中,由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问。
数据在栈内存中的存储与使用方式类似于数据结构中的堆栈数据结构,遵循后进先出的原则。
基础数据类型: Number String Null Undefined Boolean
与其他语言不同,JS的引用数据类型,比如数组Array、对象Object、函数Function,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。
在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。
栈内存 | 堆内存 |
---|---|
存储基础数据类型 | 存储引用数据类型 |
按值访问 | 按引用访问 |
存储的值大小固定 | 存储的值大小不定,可动态调整 |
由系统自动分配内存空间 | 由开发人员通过代码分配 |
主要用来执行程序 | 主要用来存放对象 |
空间小,运行效率高 | 空间大,但是运行效率相对较低 |
先进后出,后进先出 | 无序存储,可根据引用直接获取 |
标签:执行顺序 react 语句 针对 乱序 封装 exp asc 表示
原文地址:https://www.cnblogs.com/jie1995/p/12161744.html