js杂谈

js中的一切都区分大小写(变量、函数名、操作符)。

js中有5种基本的数据类型:undefined、null、boolean、Number、String。还有一种复杂的数据类型:Object。

函数名仅仅是指向函数的指针,所以一个函数可能有多个名字。

解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁,解析器会先读取函数声明,并将其在执行任何代码之前可用,至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

构造函数和其他函数的唯一区别就在于调用他们的方式不同,任何函数,只要通过new调用,那么它就是构造函数。

prototype原型对象,它的作用是对象实例共享该对象所包含的属性和方法。

调用构造函数时会为该实例添加一个指向最初原型(prototype)的指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的关系,请记住,实例中的指针仅指向原型,而不指向构造函数。

如:function Person(){} var friend = new Person();//这里调用了构造函数,此时的friend指向最初的原型。

Person.prototype = {//这里改变了最初的原型,所以,这里已经切断了friend与修改后原型的联系。

  constructor:Person,

  name:'pwd',

  sayName:function(){

         console.log(this.name);

  }

}

friend.sayName();//会报sayName()是not function

可改为:

function Person(){}

Person.prototype = {

  constructor:Person,

  name:'pwd',

  sayName:function(){

         console.log(this.name);

  }

}

var friend = new Person();

friend.sayName();

this对象是在运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this就等于那个对象,不过匿名函数的执行环境具有全局性,因此,其this对象通常指向window。

如:

var name = ‘window’;

var object = {
name:‘my object’,
getFunction:function(){
return function(){
return this.name;
}
}
}
console.log(object.getFunction());//输出window

请问js为什么要阻塞下载?
因为浏览器需要一个稳定的dom树结构,而js中有可能有代码直接改变dom树结构或者使用location.href进行跳转。浏览器为了防止出现js修改dom树,需要重新构建dom树的情况,所以就会阻塞对其他的下载和呈现。

dom树的构建过程是一个深度遍历的过程,当前节点的所有子节点都构建好之后才会去构建当前节点的下一个兄弟节点。

js引擎是单线程运行的,浏览器无论在什么时候都只有一个线程在运行js程序。由于单线程的关系,所以js中有一个任务的东西,请求都会先放入到任务队列中,这些任务会排着队等js引擎一个接一个的去处理,也就是说不管有多少任务,都得在任务队列中排队,js引擎会按顺序一个接一个的去处理。

GUI渲染线程:该线程负责渲染浏览器界面中的html元素,当界面需要重绘时该线程就会执行。该线程与js引擎线程是互斥的,因为js脚本是可操纵dom元素的,如果在修改这些元素属性的同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了。在js引擎运行脚本期间,浏览器渲染线程都处于挂起状态。

一般情况下,我们会将js代码放到html文件的底部,原因是浏览器会根据代码在文件中的顺序加载html。如果先加载js,而且刚好碰到这段js要修改html的Dom,那么它可能会由于html尚未被加载而失败,因此,将js代码放在html页面的底部通常是最好的策略。

js里一切皆对象,一切皆可存储在变量里。

可以用undefined来判断一个变量是否已被赋值。

var input;
if(input === undefined){
  doThis();
} else {
  doThat();
}

undefined值在布尔类型环境中会被当做false,例如下面的代码将会执行函数myFunction,因为数组myArray中的元素未被赋值。

var myArray = [];
if (!myArray[0])   myFunction();

在数值运算环境中会被转换为NaN,如:

var a;
a + 2;    // 计算为 NaN

当你对一个null变量求值时,在数值类型环境中null会被当做0来对待,而布尔类型环境中会被当做false。如:

var n = null;
console.log(n * 32); // 在控制台中会显示 0

在函数之外声明的变量叫做全局变量,因为它可以被当前文档中的任何其他代码所访问,在函数内部声明的变量叫做局部变量,因为它只能在当前函数的内部访问。
ECMAScript 6 之前的 JavaScript 没有 语句块 作用域;相反,语句块中声明的变量将成为语句块所在函数(或全局作用域)的局部变量。例如,如下的代码将在控制台输出 5,因为 x 的作用域是声明了 x 的那个函数(或全局范围),而不是 if 语句块。

if (true) {
  var x = 5;
}
console.log(x); // 5

如果使用 ECMAScript 6 中的 let 声明,上述行为将发生变化。

if (true) {
  let y = 5;
}
console.log(y); // ReferenceError: y 没有被声明

变量提升:
JavaScript 变量的另一个不同寻常的地方是,你可以先使用变量稍后再声明变量而不会引发异常。这一概念称为变量提升;JavaScript 变量感觉上是被“提升”或移到了函数或语句的最前面。但是,提升后的变量将返回 undefined 值。因此在使用或引用某个变量之后进行声明和初始化操作,这个被提升的变量仍将返回 undefined 值。

/**
 * 例子1
 */
console.log(x === undefined); // true
var x = 3;


/**
 * 例子2
 */
// will return a value of undefined
var myvar = "my value";

(function() {
  console.log(myvar); // undefined
  var myvar = "local value";
})();

在 ECMAScript 6 中,let(const)将不会提升变量到代码块的顶部。因此,在变量声明之前引用这个变量,将抛出引用错误(ReferenceError)。这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。

console.log(x); // ReferenceError
let x = 3;

函数提升:
对于函数来说,只有函数声明会被提升到顶部,而函数表达式不会被提升。

/* 函数声明 */

foo(); // "bar"

function foo() {
  console.log("bar");
}


/* 函数表达式 */

baz(); // 类型错误:baz 不是一个函数

var baz = function() {
  console.log("bar2");
};

在同一个作用域中,不能使用与变量名或函数名相同的名字来命名常量。

// 这会造成错误
function f() {};
const f = 5;

// 这也会造成错误
function f() {
  const g = 5;
  var g;

  //语句
}

最新的 ECMAScript 标准定义了8种数据类型:

七种基本数据类型:
1:布尔值(Boolean),有2个值分别是:true 和 false.
2:null , 一个表明 null 值的特殊关键字。 JavaScript 是大小写敏感的,因此 null 与 Null、NULL或变体完全不同。
3:undefined ,和 null 一样是一个特殊的关键字,undefined 表示变量未定义时的属性。
4:数字(Number),整数或浮点数,例如: 42 或者 3.14159。
5:任意精度的整数 (BigInt) ,可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。
6:字符串(String),字符串是一串表示文本值的字符序列,例如:“Howdy” 。
7:代表(Symbol) ( 在 ECMAScript 6 中新添加的类型).。一种实例是唯一且不可改变的数据类型。
以及对象(Object)。

在包含数字和字符串的表达式中使用加法运算符,js会把数字转换成字符串。如:

x = "The answer is " + 42 // "The answer is 42"
y = 42 + " is the answer" // "42 is the answer"

在涉及其它运算符(译注:如下面的减号’-’)时,JavaScript语言不会把数字变为字符串。例如(译注:第一例是数学运算,第二例是字符串运算):

"37" - 7 // 30
"37" + 7 // "377"

对象属性名可以是任意字符串,包括空串,如果对象属性名不是合法的js标识符,它必须用双引号包裹,而不能用.去访问它们,要用中括号[]去访问,如:

var unusualPropertyNames = {
  "": "An empty string",
  "!": "Bang!",
  2: "two"
}
console.log(unusualPropertyNames."");   // 语法错误: Unexpected string
console.log(unusualPropertyNames[""]);  // An empty string
console.log(unusualPropertyNames.!);    // 语法错误: Unexpected token !
console.log(unusualPropertyNames["!"]); // Bang!
console.log(foo[2]);   // two
console.log(foo.2);  // SyntaxError: missing ) after argument list

js没有heredoc语法,但可以用行末的换行符来近似实现,如:

var str = "this string \
is broken \
across multiple\
lines."
console.log(str);   // this string is broken across multiplelines.

ECMAScript 2015 增加了一种新的字面量,叫做模板字面量 template literals。它包含一些新特征,包括了多行字符串!

var poem =
`Roses are red,
Violets are blue.
Sugar is sweet,
and so is foo.`

在ECMAScript6标准之前,js没有块级作用域。

var x = 1;
{
  var x = 2;
}
alert(x); // 输出的结果为 2

ECMAScript6标准之后:

let x = 1;
{
	let x = 2;
}

console.log(x);//输出:1

js里也有try…catch,如:

try{
	let num = 1;
  	if(num == 1){
    	throw 'haha';
    }
}catch(e){
	console.log(e);//输出:haha
}finally{
	console.log('我是finally');//输出:我是finally
}

finally块包含了在try和catch块完成后、下面接着try…catch的语句之前执行的语句。finally块无论是否抛出异常都会执行。如果抛出了一个异常,就算没有异常处理,finally块里的语句也会执行。

使用break、continue可以while、do-while、for循环语句。

虽然for…in来迭代数组Array听起来很诱人,但是它返回的东西除了数字索引外,还有可能包括你自定义的属性名,因此,还是用带有数字索引的传统for循环来迭代数组比较好。如:

let arr = [3,5,7];
arr.foo = 'hello';

for(let i in arr){
	console.log(arr[i]);//输出:3 5 7 hello
}

for(let i = 0;i < arr.length;i++){
	console.log(arr[i]);//输出:3 5 7
}

for…of语句在可迭代对象(包括Array、Map、Set、arguments等等)上创建了一个循环,对值得每一个独特属性调用一次迭代。下面这个例子展示了for…of与for…in的区别。for…in循环遍历的结果是数组元素的下标,而for…of遍历的结果是元素的值,而且它只返回数字索引的值。

let arr = [3,5,7];
arr.foo = 'hello';

for(let i in arr){
	console.log(i);//输出:0 1 2 foo
}

for(let i of arr){
	console.log(i);//输出:3 5 7
}

传递给函数的参数是标量类型,如果在函数内部改变了参数值,则不会影响到该参数外部的值,传递给函数的参数是对象或数组,如果在函数内部改变了参数值,则会影响到外部的值。如:

var name = 'lbj';
function modify(name){
	name = 'kobe';
}
modify(name);
console.log(name);//输出:lbj

var name = {username:'lbj'};
modify1(name);
function modify1(name){
	name.username = 'kobe';
}
console.log(name.username);//输出:kobe

在函数内定义的变量不能在函数之外的任何地方访问,定义在全局域中的函数可以访问所有定义在全局域中的变量。在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。

var name = 'lbj';
var obj = {
	name: 'kobe',
  	getName: function(){
    	console.log(name);//输出:lbj
      	console.log(this.name);//输出:kobe
    }
}
obj.getName();

一个函数可以指向并调用自身,有三种方法可以达到这个目的:
1:函数名。
2:arguments.callee
3:作用域下的一个指向该函数的变量名。

var foo = function bar(){}
在这个函数体内,以下的语句是等价的:
1:bar()
2:arguments.callee()
3:foo()

调用自身的函数我们称之为递归函数,在某种意义上说,递归近似于循环,两者都重复执行相同的代码,并且两者都需要一个终止条件。

嵌套函数和闭包:
你可以在一个函数里面嵌套另外一个函数,嵌套(内部)函数对其容器(外部)函数是私有的。它自身形成了一个闭包,一个闭包是一个可以自己拥有独立的环境与变量的表达式。既然嵌套函数是一个闭包,就意味着一个嵌套函数可以继承容器函数的参数和变量,换句话说,内部函数包含外部函数的作用域。
总结如下:
1:内部函数只可以在外部函数中访问。
2:内部函数形成了一个闭包,它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。

function addSquares(a, b) {
  function square(x) {
    return x * x;
  }
  return square(a) + square(b);
}
a = addSquares(2, 3); // returns 13
b = addSquares(3, 4); // returns 25
c = addSquares(4, 5); // returns 41

由于内部函数形成了闭包,因此你可以调用外部函数并为外部函数和内部函数指定参数:

function outside(x) {
  function inside(y) {
    return x + y;
  }
  return inside;
}
fn_inside = outside(3); // 可以这样想:给一个函数,使它的值加3
result = fn_inside(5); // returns 8

result1 = outside(3)(5); // returns 8

注意到上例中inside被返回时x是怎么被保留下来的,一个闭包必须保存它可见作用域中所有的参数和变量,因为每一次调用传入的参数都可能不同,每一次对外部函数的调用实际上重新创建了一遍这个闭包。只有当返回的 inside 没有再被引用时,内存才会被释放。

当同一个闭包作用域下两个参数或者变量同名时,就会产生命名冲突。更近的作用域有更高的优先权,所以最近的优先级最高,最远的优先级最低。

function outside() {
  var x = 5;
  function inside(x) {
    return x * 2;
  }
  return inside;
}

outside()(10); // returns 20 instead of 10

闭包是 JavaScript 中最强大的特性之一。JavaScript 允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。但是,外部函数却不能够访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一定的安全性。此外,由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行时间长。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。那么我们怎么才能读取到内部函数中定义的变量呢?可以通过公用方法来读取,如:

var createPet = function(name){
	
  return {
  	setName: function(newName){
    	name = newName;
    },
    getName: function(){
    	console.log(name);
    }
  }
}

var pet = createPet('vivi');
pet.getName();//vivi
pet.setName('lulu');
pet.getName();//lulu

函数的实际参数会被保存在一个类似数组的arguments对象中,在函数内,你可以按如下方式找出传入的参数:arguments[i]。其中i是参数的序数编号(译注:数组索引),以0开始。所以第一个传来的参数会是arguments[0]。参数的数量由arguments.length表示。使用arguments对象,你可以处理比声明的更多的参数来调用函数。这在你事先不知道会需要将多少参数传递给函数时十分有用。你可以用arguments.length来获得实际传递给函数的参数的数量,然后用arguments对象来取得每个参数。
例如,设想有一个用来连接字符串的函数。唯一事先确定的参数是在连接后的字符串中用来分隔各个连接部分的字符(译注:比如例子里的分号“;”)。该函数定义如下:

function myConcat(separator) {
   var result = ''; // 把值初始化成一个字符串,这样就可以用来保存字符串了!!
   var i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}
// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");

// returns "elephant; giraffe; lion; cheetah; "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");

// returns "sage. basil. oregano. pepper. parsley. "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

从ec6开始,有两个新的类型的参数:默认参数、剩余参数。

默认参数:
在js中,函数参数的默认值是undefined,然而,在某些情况下设置不同的默认值是有用的。这时默认参数可以提供帮助。在过去,用于设定默认参数的一般策略是在函数的主体中测试参数值是否为undefined,如果是则赋予这个参数一个默认值。如果在下面的例子中,调用函数时没有实参传递给b,那么它的值就是undefined,于是计算a*b得到、函数返回的是 NaN。但是,在下面的例子中,这个已经被第二行获取处理:

function multiply(a, b) {
  b = (typeof b !== 'undefined') ?  b : 1;

  return a*b;
}

multiply(5); // 5

使用默认参数,在函数体的检查就不再需要了。现在,你可以在函数头简单地把1设定为b的默认值:
function multiply(a, b = 1) {
  return a*b;
}

multiply(5); // 5

剩余参数:
剩余参数语法允许将不确定数量的参数表示为数组。在下面的例子中,使用剩余参数收集从第二个到最后参数。然后,我们将这个数组的每一个数与第一个参数相乘。

function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

箭头函数:
ES6标准新增了一种新的函数(箭头函数):

x => x * x;
上面的箭头函数就相当于:
function(x){
	return x * x;
}

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种是像上面的,只包含一个表达式,连{…}和return都省略掉。还有一个种可以包含多条语句,这时候就不能省略{…}和return。

x => {
    if (x > 0) {
        return x * x;
    }
    else {
        return - x * x;
    }
}

如果参数不是一个,就需要用括号()括起来:
// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

// 可变参数:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}
如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:
// SyntaxError:
x => { foo: x }
因为和函数体的{ ... }有语法冲突,所以要改为:
// ok:
x => ({ foo: x })

箭头函数this指向:
箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文决定。
回顾前面的例子,由于JavaScript函数对this绑定的错误处理(闭包中的this总是指向windows),下面的例子无法得到预期结果:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:
var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

删除数组中的元素时,数组的长度是不变的,值会变为undefined,但是用for和for…in循环时取出的数据是不同的,如:

var arr = ['red','black','white'];
delete arr[0];
console.log(arr.length);//输出:3
for(var i = 0;i < arr.length;i++){
	console.log(arr[i]);//输出:undefined black white
}
for(var i in arr){
	console.log(arr[i]);//输出:black white
}

void运算符,表明一个运算没有返回值。void(express)表示执行express表达式,但是没有返回值。

如下创建了一个超链接文本,当用户单击该文本时,不会有任何效果。
<a href="javascript:void(0)">Click here to do nothing</a>
下面的代码创建了一个超链接,当用户单击它时,提交一个表单。
<a href="javascript:void(document.form.submit())">
Click here to submit</a>

关系操作符对操作数进行比较,根据比较结果真或假,返回相应的布尔值。
in操作符,如果所指定的属性确实存在于所指定的对象中,则返回true。
propNameOrNumber in objectName
在这里 propNameOrNumber可以是一个代表着属性名的字符串或者是一个代表着数组索引的数值表达式,而objectName则是一个对象名。

var arr = ['red','black','white'];
if(0 in arr){
	console.log('haha')
}

var obj = {name: 'kobe',age: 18};
if('age' in obj){
	console.log('hello');
}

instanceof操作符,如果所判别的对象确实是所指定的类型,则返回true。

objectName instanceof objectType
objectName 是需要做判别的对象的名称,而objectType是假定的对象的类型, 例如Date或 Array.

例如, 下面的代码使用instanceof去判断 theDay是否是一个 Date 对象. 因为theDay是一个Date对象, 所以if中的代码会执行.
var theDay = new Date(1995, 12, 17);
if (theDay instanceof Date) {
  // statements to execute
}

数字类型原型上的toFixed()方法,表示返回指定小数的位数。
如:

var num = 123.0012345;
var num1 = num.toFixed(3)
console.log(num1);//123.001

js没有日期数据类型,但是你可以在你的程序里使用 Date 对象和其方法来处理日期和时间。Date对象有大量的设置、获取和操作日期的方法。 它并不含有任何属性。

String类型属性:
1:String.prototype:表示String原型对象。所有string的实例都继承自String.prototype。所以,任何String.prototype上的改变都会影响到所有的String实例。
2:String.length:该属性返回字符串中字符编码单元的数量。js使用utf-16编码。

String类型常用方法:
charAt(index):从一个字符串中返回指定的字符。index是一个介于0 和字符串长度减1之间的整数。

var str = 'hello world';
console.log(str.charAt(1));//e

charCodeAt(index):表示给定索引处(String中index索引处)字符的 UTF-16 代码单元值的数字;如果索引超出范围,则返回 NaN。
```bash
var str = 'ABC';
console.log(str.charCodeAt(str));//65

concat(string1,string2…);将一个或多个字符与原字符连接合并,形成一个新的字符串并返回。

var str = 'hello';
console.log(str.concat(' world'));//hello world
该方法性能不是很好,因此强烈建议使用 赋值操作符(+, +=)代替 concat 方法。

endsWith:
添加链接描述
添加链接描述

includes():用于判断一个字符串是否包含在另一个字符串中。
添加链接描述

indexOf():返回调用它的 String 对象中第一次出现的指定值的索引,从 fromIndex 处进行搜索。如果未找到该值,则返回 -1。
添加链接描述

match():检索返回一个字符串匹配正则表达式的的结果。
添加链接描述
添加链接描述

pageEnd():会用一个字符串填充当前字符串(如果需要的话则重复填充),返回填充后达到指定长度的字符串。从当前字符串的末尾(右侧)开始填充。
添加链接描述
添加链接描述

repeat() 构造并返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串的副本。
添加链接描述

search() 方法执行正则表达式和 String 对象之间的一个搜索匹配。
添加链接描述

slice() 方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。
添加链接描述

split() 方法使用指定的分隔符字符串将一个String对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。
添加链接描述

substring() 方法返回一个字符串在开始索引到结束索引之间的一个子集, 或从开始索引直到字符串的末尾的一个子集。
添加链接描述

toLowerCase() 会将调用该方法的字符串值转为小写形式,并返回。
toUpperCase() 方法返回一个将调用字符串转换为大写形式的值。(如果这个值不是字符串则会被变成字符串)

Function常用方法:
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
添加链接描述

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
添加链接描述

bind()方法:创建一个新函数,在bind被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。
添加链接描述
添加链接描述

数组常用方法/属性:
添加链接描述

Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值: 添加链接描述

Error对象:添加链接描述

使用 Promise:添加链接描述

Promise对象:用于表示一个异步操作的最终完成(或失败)及其结果值。添加链接描述

Proxy 对象:添加链接描述

RegExp对象:添加链接描述

Set 对象:添加链接描述

闭包:添加链接描述

在js中,对象的属性分为可枚举和不可枚举,它们是由属性的enumerable值决定的,可枚举性决定了这个属性能否被for…in查找遍历到。

js中的基本包装类型的原型属性是不可枚举的,如:Object、Array、Number等,如果你写出这样的代码遍历其中的属性:

var num = new Number();
for(var pro in num) {
    console.log("num." + pro + " = " + num[pro]);
}
它的输出结果会是空。这是因为Number中内置的属性是不可枚举的,所以不能被for…in访问到。

Object对象的propertyIsEnumerable()方法可以判断此对象是否包含某个属性,并且这个属性是否可枚举。
需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false。
添加链接描述

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
添加链接描述

Object.create():这个方法用于创建一个新对象,被创建的对象继承另一个对象的原型,,在创建新对象时可以指定一些属性。
添加链接描述
添加链接描述

Object.defineProperty():方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
添加链接描述

Object.entries():返回一个给定对象自身可枚举属性的键值对数组,其排队与使用for…in循环遍历该对象时返回的顺序一致(区别在于for-in循环也枚举原型链中的属性)。
添加链接描述

Object.freeze():冻结一个对象/数组。
添加链接描述

Object.getOwnPropertyDescriptor(object,prop):返回指定对象的一个自有属性对应的属性描述符(自有属性指的是直接赋予该对象的属性,不需要从原型链上查找的属性)。
添加链接描述

function Foo(){}
var foo = new Foo();
当js执行构造函数new Foo()时,实际上的执行步骤是:
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);

console.log(foo);//输出:Foo {}
console.log(o);//输出:Foo {}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值